diff --git a/Resources/config/yui.yml b/Resources/config/yui.yml index 7b99920d0..3cae77086 100644 --- a/Resources/config/yui.yml +++ b/Resources/config/yui.yml @@ -20,6 +20,8 @@ system: - 'ez-contenteditview' - 'ez-locationviewview' - 'ez-locationviewviewservice' + - 'ez-serversideview' + - 'ez-serversideviewservice' - 'ez-navigationhubviewservice' - 'ez-navigationhubview' - 'ez-discoverybarviewservice' @@ -67,7 +69,7 @@ system: - 'ez-contentcreateplugin' path: %ez_platformui.public_dir%/js/views/services/ez-locationviewviewservice.js ez-navigationhubviewservice: - requires: ['ez-viewservice', 'ez-navigationitemsubtreeview', 'array-extras'] + requires: ['ez-viewservice', 'ez-navigationitemsubtreeview', 'ez-navigationitemparameterview', 'array-extras'] path: %ez_platformui.public_dir%/js/views/services/ez-navigationhubviewservice.js ez-discoverybarviewservice: requires: ['ez-viewservice', 'ez-contenttreeplugin'] @@ -117,6 +119,9 @@ system: ez-navigationitemsubtreeview: requires: ['ez-navigationitemview'] path: %ez_platformui.public_dir%/js/views/navigation/ez-navigationitemsubtreeview.js + ez-navigationitemparameterview: + requires: ['ez-navigationitemview'] + path: %ez_platformui.public_dir%/js/views/navigation/ez-navigationitemparameterview.js ez-navigationitemview: requires: ['ez-templatebasedview', 'navigationitemview-ez-template'] path: %ez_platformui.public_dir%/js/views/navigation/ez-navigationitemview.js diff --git a/Resources/public/css/theme/views/navigationhub.css b/Resources/public/css/theme/views/navigationhub.css index 48a591d67..7811d7e34 100644 --- a/Resources/public/css/theme/views/navigationhub.css +++ b/Resources/public/css/theme/views/navigationhub.css @@ -24,6 +24,10 @@ border-right: 1px solid #ddd; } +.ez-view-navigationhubview .ez-zone-no-navigation.is-zone-active { + border-bottom: 3px solid #528036; +} + .ez-view-navigationhubview .ez-navigation { border-top: 1px solid #ccc; border-bottom: 1px solid #bbb; @@ -44,9 +48,9 @@ } .ez-view-navigationhubview .ez-zone:before { - width: 1.5em; - height: 1.5em; - line-height: 1.5em; + width: 2rem; + height: 2rem; + line-height: 2rem; margin: 0; background: #528036; color: #fff; @@ -55,11 +59,17 @@ float: left; text-align: center; font-family: 'ez-platformui-icomoon'; - font-size: 150%; + font-size: 135%; -webkit-font-smoothing: antialiased; } -@media (max-width: 62em) { +.ez-view-navigationhubview .ez-admin-zone:before { + background: transparent; + color: #444; + font-size: 100%; +} + +@media (max-width: 58em) { .ez-view-navigationhubview .ez-zone:before { font-size: 120%; width: 1.4em; @@ -68,29 +78,42 @@ } } -.ez-view-navigationhubview .ez-create-zone:before { +.ez-view-navigationhubview .ez-platform-zone:before { content: "\E611"; } -.ez-view-navigationhubview .ez-optimize-zone:before { +.ez-view-navigationhubview .ez-studioplus-zone:before { content: "\E612"; } -.ez-view-navigationhubview .ez-deliver-zone:before { +.ez-view-navigationhubview .ez-studio-zone:before { content: "\E60D"; } -.ez-view-navigationhubview .ez-link a:after { - padding-left: 0.5em; - vertical-align: middle; +.ez-view-navigationhubview .ez-admin-zone:before { + content: "\E613"; } -.ez-view-navigationhubview .ez-navigation .ez-navigation-item, -.ez-view-navigationhubview .ez-zone-name { +.ez-view-navigationhubview .ez-navigation .ez-navigation-item { font-weight: bold; color: #333; } +.ez-view-navigationhubview .ez-zone-name { + color: #333; + font-size: 110%; +} + +.ez-view-navigationhubview .ez-admin-zone .ez-zone-name { + font-size: 80%; +} + +@media (max-width:58em) { + .ez-view-navigationhubview .ez-zone-name { + font-size: 100%; + } +} + .ez-view-navigationhubview .ez-navigation .ez-logo { opacity: 0; visibility: visible; @@ -150,26 +173,12 @@ border-bottom: 3px solid #528036; } -.ez-view-navigationhubview .ez-zone-hint { - color: #777; - font-size: 80%; -} - -.ez-view-navigationhubview .ez-link a { - color: #333; - font-size: 85%; - font-weight: bold; - margin-bottom: 1em; - display: inline-block; -} - -.ez-view-navigationhubview .ez-navigation .ez-navigation-item:hover, -.ez-view-navigationhubview .ez-link a:hover { +.ez-view-navigationhubview .ez-navigation .ez-navigation-item:hover { color: #528036; } .ez-view-navigationhubview .ez-user-info { - font-size: 85%; + font-size: 0.85rem; } .ez-view-navigationhubview .ez-user-info-name { diff --git a/Resources/public/css/views/navigationhub.css b/Resources/public/css/views/navigationhub.css index 4c33c7a98..b1ed71080 100644 --- a/Resources/public/css/views/navigationhub.css +++ b/Resources/public/css/views/navigationhub.css @@ -4,9 +4,10 @@ */ .ez-view-navigationhubview .ez-zones-navigation, -.ez-view-navigationhubview .ez-navigation-create, -.ez-view-navigationhubview .ez-navigation-deliver, -.ez-view-navigationhubview .ez-navigation-optimize { +.ez-view-navigationhubview .ez-navigation-platform, +.ez-view-navigationhubview .ez-navigation-admin, +.ez-view-navigationhubview .ez-navigation-studio, +.ez-view-navigationhubview .ez-navigation-studioplus { list-style-type: none; margin: 0; padding: 0; @@ -14,10 +15,7 @@ .ez-view-navigationhubview .ez-zones-navigation li { display: inline-block; -} - -.ez-view-navigationhubview .ez-zones-navigation .ez-link { - vertical-align: bottom; + overflow: hidden; } .ez-view-navigationhubview .ez-navigation > ul, @@ -26,24 +24,43 @@ white-space: nowrap; } +.ez-view-navigationhubview .ez-zones-navigation { + font-size: 0; +} + .ez-view-navigationhubview .ez-navigation li { display: inline-block; } -.ez-view-navigationhubview .ez-zone-name, -.ez-view-navigationhubview .ez-zone-hint { +.ez-view-navigationhubview .ez-zone-name { + height: 2rem; + line-height: 2rem; margin: 0 0 0 2.6rem; } +.ez-view-navigationhubview .ez-admin-zone .ez-zone-name { + margin: 0 0 0 2rem; +} + .ez-view-navigationhubview .ez-logo { text-align: center; - width: 9em; } .ez-view-navigationhubview .ez-zone, -.ez-view-navigationhubview .ez-link, +.ez-view-navigationhubview .ez-zones-navigation .ez-logo, .ez-view-navigationhubview .ez-user-info { - padding: 1em; + font-size: 1rem; + padding: 0.8rem 1rem; +} + +.ez-view-navigationhubview .ez-zones-navigation .ez-logo, +.ez-view-navigationhubview .ez-zone { + height: 2rem; +} + +.ez-view-navigationhubview .ez-admin-zone { + padding-right: 1.3rem; + margin-left: 3em; } .ez-view-navigationhubview .ez-user-info { @@ -145,28 +162,19 @@ display: block; } -@media (max-width:70em) { - .ez-view-navigationhubview .ez-zones-navigation .ez-exchange { - display: none; - } -} - -@media (max-width:62em) { - .ez-view-navigationhubview .ez-logo { - width: 6em; - vertical-align: middle; - } - - .ez-view-navigationhubview .ez-zone-hint { - display: none; +@media (max-width:58em) { + .ez-view-navigationhubview .ez-zone, + .ez-view-navigationhubview .ez-zones-navigation .ez-logo, + .ez-view-navigationhubview .ez-user-info { + padding: 0.6rem 0.4rem; } .ez-view-navigationhubview .ez-zone-name { - margin: 0.2em 0 0 1.9rem; - font-size: 90%; + margin: 0 0 0 1.9rem; } - .ez-view-navigationhubview .ez-zones-navigation .ez-settings a { - margin-bottom: 0.4em; + .ez-view-navigationhubview .ez-admin-zone { + padding-right: 1.3rem; + margin-left: 1em; } } diff --git a/Resources/public/js/apps/extensions/ez-app-extension-admin.js b/Resources/public/js/apps/extensions/ez-app-extension-admin.js deleted file mode 100644 index e597cfcf3..000000000 --- a/Resources/public/js/apps/extensions/ez-app-extension-admin.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) eZ Systems AS. All rights reserved. - * For full copyright and license information view LICENSE file distributed with this source code. - */ -YUI.add('ez-app-extension-admin', function (Y) { - "use strict"; - /** - * Provides the admin app extension for the eZ.PlatformUIApp - * - * @module ez-app-extension-admin - */ - Y.namespace('eZ'); - - /** - * Admin app extension. It adds some routes and views to the application and - * also allows to lazy load the admin related code. - * - * @namespace eZ - * @class AdminAppExtension - * @constructor - * @extends eZ.AppExtension - */ - Y.eZ.AdminAppExtension = Y.Base.create('adminAppExtension', Y.eZ.AppExtension, [], {}, { - ATTRS: { - routes: { - readOnly: true, - value: [{ - name: "adminGenericRoute", - path: "/admin/:uri", - sideViews: {'navigationHub': true}, - service: Y.eZ.ServerSideViewService, - view: "serverSideView", - callbacks: ['open', 'checkUser', 'handleSideViews', 'handleMainView'] - }] - }, - - views: { - readOnly: true, - value: { - serverSideView: { - type: Y.eZ.ServerSideView - } - } - } - } - }); -}); diff --git a/Resources/public/js/apps/extensions/ez-app-extension.js b/Resources/public/js/apps/extensions/ez-app-extension.js deleted file mode 100644 index 6109e3c43..000000000 --- a/Resources/public/js/apps/extensions/ez-app-extension.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) eZ Systems AS. All rights reserved. - * For full copyright and license information view LICENSE file distributed with this source code. - */ -YUI.add('ez-app-extension', function (Y) { - "use strict"; - /** - * Provides the base app extension class. - * - * @module ez-app-extension - */ - Y.namespace('eZ'); - - /** - * Base app extension class. App extension are meant to "externally" extend - * the eZ.PlatformUIApp with routes and views for now. - * - * @namespace eZ - * @class AppExtension - * @constructor - * @extends Base - */ - Y.eZ.AppExtension = Y.Base.create('appExtension', Y.Base, [], { - /** - * Extends the application by adding routes and views - * - * @method extend - * @param {App} app an application - */ - extend: function (app) { - this._extendViews(app); - this._extendRoutes(app); - }, - - /** - * Adds (or overrides) views in the application - * - * @method _extendViews - * @protected - * @param {App} app an application - */ - _extendViews: function (app) { - Y.Object.each(this.get('views'), function (viewInfo, identifier) { - app.views[identifier] = viewInfo; - }); - }, - - /** - * Adds routes to the application - * - * @method _extendRoutes - * @protected - * @param {App} app an application - */ - _extendRoutes: function (app) { - Y.Array.each(this.get('routes'), function (route) { - app.route(route); - }); - }, - }, { - ATTRS: { - /** - * Routes to add to the application. Each element of the array - * should be a valid route object. - * - * @attribute routes - * @type Array - * @default empty array - * @readOnly - */ - routes: { - readOnly: true, - value: [] - }, - - /** - * Views to add to the appliation. Each element of the hash should - * be a valid view info object - * - * @attribute views - * @type Object - * @default empty object - * @readOnly - */ - views: { - readOnly: true, - value: {} - }, - } - }); -}); diff --git a/Resources/public/js/apps/ez-platformuiapp.js b/Resources/public/js/apps/ez-platformuiapp.js index e1e4d1478..6d869b7a3 100644 --- a/Resources/public/js/apps/ez-platformuiapp.js +++ b/Resources/public/js/apps/ez-platformuiapp.js @@ -99,6 +99,9 @@ YUI.add('ez-platformuiapp', function (Y) { type: Y.eZ.LocationViewView, parent: 'dashboardView' }, + serverSideView: { + type: Y.eZ.ServerSideView, + }, errorView: { instance: new Y.eZ.ErrorView({ container: ERROR_VIEW_CONTAINER @@ -662,34 +665,6 @@ YUI.add('ez-platformuiapp', function (Y) { Y.config.doc.title = this._initialTitle; } }, - - /** - * Middleware that makes sure the admin app extension is loaded and that - * the application has been extended with it. - * - * @method _loadAdminExtension - * @protected - * @param {Object} req - * @param {Object} res - * @param {Function} next - */ - _loadAdminExtension: function (req, res, next) { - Y.use('ez-app-extension-admin', function (Y, status) { - var extension; - - if ( status.data ) { - // first loading of the extension - extension = new Y.eZ.AdminAppExtension(); - extension.extend(req.app); - // can not just call next as the routing needs - // to be done from scratch with the addition of - // the app extension - req.app.navigate(req.path); - } else { - next(); - } - }); - }, }, { ATTRS: { /** @@ -716,6 +691,11 @@ YUI.add('ez-platformuiapp', function (Y) { * sideViews property. A truthy value means that the * corresponding side view should be visible. * + * If a route provides both a `regex` and a `path` properties, the + * `regex` in the route matching process, while the `path` can be + * used in the reverse routing process (generation of a link). If + * no `path` is provided, no reverse routing is possible. + * * @attribute routes */ routes: { @@ -754,9 +734,22 @@ YUI.add('ez-platformuiapp', function (Y) { view: 'locationViewView', callbacks: ['open', 'checkUser', 'handleSideViews', 'handleMainView'] }, { - path: '/admin/*', - callback: '_loadAdminExtension' - }], + name: "adminSection", + regex: /\/admin\/(pjax%2Fsection%2F.*)/, + keys: ['uri'], + path: "/admin/:uri", + sideViews: {'navigationHub': true}, + service: Y.eZ.ServerSideViewService, + view: "serverSideView", + callbacks: ['open', 'checkUser', 'handleSideViews', 'handleMainView'] + }, { + name: "adminGenericRoute", + path: "/admin/:uri", + sideViews: {'navigationHub': true}, + service: Y.eZ.ServerSideViewService, + view: "serverSideView", + callbacks: ['open', 'checkUser', 'handleSideViews', 'handleMainView'] + }] }, serverRouting: { value: false diff --git a/Resources/public/js/views/ez-navigationhubview.js b/Resources/public/js/views/ez-navigationhubview.js index b5911145d..99612d9fe 100644 --- a/Resources/public/js/views/ez-navigationhubview.js +++ b/Resources/public/js/views/ez-navigationhubview.js @@ -16,7 +16,6 @@ YUI.add('ez-navigationhubview', function (Y) { NAVIGATION_HIDDEN = 'is-navigation-hidden', SUB_MENU_OPEN = 'is-sub-menu-open', NAVIGATION_SEL = '.ez-navigation', - DEFAULT_ACTIVE_NAV = 'create', NAVIGATION_NODE_CLASS_TPL = 'ez-navigation-{identifier}', ZONE_ACTIVE = 'is-zone-active'; @@ -81,9 +80,10 @@ YUI.add('ez-navigationhubview', function (Y) { _resizeSubscription: null, initializer: function () { - this.after('activeNavigationChange', function () { + this.after('activeNavigationChange', function (e) { if ( this.get('active') ) { - this._uiSetActiveNavigation(); + this._uiSetActiveNavigation(e.prevVal); + this._navigateToZone(e.newVal); } }); this.after('navigationFixedChange', this._uiHandleFixedNavigation); @@ -99,29 +99,55 @@ YUI.add('ez-navigationhubview', function (Y) { * @protected */ _handleSelectedItem: function () { - var matchedRoute = this.get('matchedRoute'); + var matchedRoute = this.get('matchedRoute'), + activeZone = null; - Y.Object.each(this.get('zones'), function (zone) { + Y.Object.each(this.get('zones'), function (zone, key) { var inZone = false; - Y.Array.each(this.get(zone.identifier + 'NavigationItems'), function (item) { + Y.Array.each(this._getNavigationItemViews(key), function (item) { inZone = (item.matchRoute(matchedRoute) || inZone); }); if ( inZone ) { - this.set('activeNavigation', zone.identifier); + activeZone = key; } }, this); + this.set('activeNavigation', activeZone); + }, + + /** + * Fires the event to navigate to the given zone. The navigation happens + * only if the zone has exactly one navigation items. + * + * @method _navigateToZone + * @param {String|Null} zone + * @method protected + */ + _navigateToZone: function (zone) { + var items; + + if ( !zone ) { + return; + } + + items = this._getNavigationItemViews(zone); + if ( items && items.length === 1 ) { + this.fire('navigateTo', { + route: items[0].get('route') + }); + } }, /** * Sets the active navigation in the UI * * @method _uiSetActiveNavigation + * @param {String|Null} previousZone the previously active zone * @protected */ - _uiSetActiveNavigation: function () { + _uiSetActiveNavigation: function (previousZone) { this._uiSetActiveZone(); - this._uiShowNavigation(); + this._uiShowNavigation(previousZone); this._uiNavigationSize(); }, @@ -172,7 +198,9 @@ YUI.add('ez-navigationhubview', function (Y) { if ( active ) { active.removeClass(ZONE_ACTIVE); } - container.one('.ez-' + this.get('activeNavigation') + '-zone').addClass(ZONE_ACTIVE); + if ( this.get('activeNavigation') ) { + container.one('.ez-' + this.get('activeNavigation') + '-zone').addClass(ZONE_ACTIVE); + } }, /** @@ -186,14 +214,61 @@ YUI.add('ez-navigationhubview', function (Y) { container.setHTML(this.template({ user: this.get('user').toJSON(), - zones: this.get('zones'), + zones: this._buildZones(), })); this._renderNavigationItems(); - this._setNavigationMenu(this.get('activeNavigation')); this._uiSetActiveNavigation(); return this; }, + /** + * Builds the zone list for the template. Each zone is represented by an + * object with a `name` and a `hasNavigation` properties. + * + * @method _buildZones + * @protected + * @return {Object} + */ + _buildZones: function () { + var zones = {}; + + Y.Object.each(this.get('zones'), function (zoneName, key) { + zones[key] = { + name: zoneName, + hasNavigation: this._hasNavigation(key), + }; + }, this); + return zones; + }, + + /** + * Returns whether the zone associated with the given key has a + * navigation ie it has more than one navigation item view. + * + * @method _hasNavigation + * @protected + * @param {String} zoneKey + * @return {Boolean} + */ + _hasNavigation: function (zoneKey) { + var items = this._getNavigationItemViews(zoneKey); + + return !!(items && items.length > 1); + }, + + /** + * Returns the navigation item views instances associated with the given + * zone key. + * + * @method _getNavigationItemViews + * @protected + * @param {String} zoneKey + * @return {undefined|Array} of eZ.NavigationItemView + */ + _getNavigationItemViews: function (zoneKey) { + return this.get(zoneKey + 'NavigationItems'); + }, + /** * Renders the navigation items in the corresponding navigation zone * @@ -206,7 +281,7 @@ YUI.add('ez-navigationhubview', function (Y) { Y.Object.each(this.get('zones'), function (zone, key) { var after = that._getNavigationNode(key).one('.ez-logo'); - Y.Array.each(that.get(key + 'NavigationItems'), function (view) { + Y.Array.each(that._getNavigationItemViews(key), function (view) { after.insert(view.render().get('container'), 'after'); after = view.get('container'); }); @@ -239,7 +314,7 @@ YUI.add('ez-navigationhubview', function (Y) { */ _setNavigationItemActive: function (active) { Y.Object.each(this.get('zones'), function (zone, key) { - Y.Array.each(this.get(key + 'NavigationItems'), function (view) { + Y.Array.each(this._getNavigationItemViews(key), function (view) { view.set('active', active); }); }, this); @@ -247,22 +322,19 @@ YUI.add('ez-navigationhubview', function (Y) { /** * Makes sure the navigation corresponding to the activeNavigation value - * is shown + * is shown if needed * * @protected * @method _uiShowNavigation + * @param {String|Null} previousZone the previously active zone */ - _uiShowNavigation: function () { - var navigations = this.get('container').one(NAVIGATION_SEL).get('children'), - navClass = L.sub(NAVIGATION_NODE_CLASS_TPL, {identifier: this.get('activeNavigation')}); - - navigations.each(function (nav) { - if ( nav.hasClass(navClass) ) { - nav.removeClass(NAVIGATION_HIDDEN); - } else { - nav.addClass(NAVIGATION_HIDDEN); - } - }); + _uiShowNavigation: function (previousZone) { + if ( previousZone ) { + this._getNavigationNode(previousZone).addClass(NAVIGATION_HIDDEN); + } + if ( this.get('activeNavigation') && this._hasNavigation(this.get('activeNavigation')) ) { + this._getNavigationNode(this.get('activeNavigation')).removeClass(NAVIGATION_HIDDEN); + } }, /** @@ -289,7 +361,6 @@ YUI.add('ez-navigationhubview', function (Y) { if ( navigation.get('docScrollY') > this._navigationY ) { this.set('navigationFixed', true); - this.set('activeNavigation', DEFAULT_ACTIVE_NAV); // TODO should depend on the app activeView } else { this.set('navigationFixed', false); } @@ -304,10 +375,14 @@ YUI.add('ez-navigationhubview', function (Y) { * @protected */ _uiNavigationSize: function (e) { - var items, item, - more = this._navigationMenu.one('.ez-more'), - moreMenu = more.one('.ez-sub-menu'), - moreItems = moreMenu.all('li'); + var items, item, more, moreMenu, moreItems; + + if ( !this._navigationMenu ) { + return; + } + more = this._navigationMenu.one('.ez-more'); + moreMenu = more.one('.ez-sub-menu'); + moreItems = moreMenu.all('li'); while ( this._navigationUnderflowed() ) { if ( moreItems.isEmpty() ) { @@ -436,7 +511,11 @@ YUI.add('ez-navigationhubview', function (Y) { * @return {String} val */ _setNavigationMenu: function (val) { - this._navigationMenu = this._getNavigationNode(val); + if ( val ) { + this._navigationMenu = this._getNavigationNode(val); + } else { + this._navigationMenu = null; + } return val; }, @@ -483,8 +562,8 @@ YUI.add('ez-navigationhubview', function (Y) { }, { ATTRS: { /** - * Stores the list of zone (Create, Deliver, Optimize) and the - * corresponding data. + * Object describing the available zones (Platform, Studio), the + * key is the zone identifier, the value is the zone name. * * @attribute zones * @type Object @@ -492,75 +571,80 @@ YUI.add('ez-navigationhubview', function (Y) { */ zones: { value: { - 'create': { - name: 'Create', - hint: 'Creating & Editing', - identifier: 'create', - }, - 'deliver': { - name: 'Deliver', - hint: 'Publishing & Engagin', - identifier: 'deliver', - }, - 'optimize': { - name: 'Optimize', - hint: 'Statistics & Analytics', - identifier: 'optimize', - }, + 'platform': 'Platform', + 'studio': 'Studio', + 'studioplus': 'Studio Plus', + 'admin': 'Admin Panel', }, readOnly: true, }, /** * Stores the navigation view item views instance for each item in - * the navigation for the create zone. This attribute accepts either + * the navigation for the platform zone. This attribute accepts either + * an array of already build views or an array of object with at a + * `Constructor` property and optionally a `config` property holding + * an object to pass to the constructor function. + * + * @attribute platformNavigationItems + * @type Array of Y.View + * @writeOnce + */ + platformNavigationItems: { + setter: '_buildNavigationViews', + writeOnce: true, + }, + + /** + * Stores the navigation view item views instance for each item in + * the navigation for the studio zone. This attribute accepts either * an array of already build views or an array of object with at a * `Constructor` property and optionally a `config` property holding * an object to pass to the constructor function. * - * @attribute createNavigationItems + * @attribute studioNavigationItems * @type Array of Y.View * @writeOnce */ - createNavigationItems: { + studioNavigationItems: { setter: '_buildNavigationViews', writeOnce: true, }, /** * Stores the navigation view item views instance for each item in - * the navigation for the optimize zone. This attribute accepts either + * the navigation for the admin zone. This attribute accepts either * an array of already build views or an array of object with at a * `Constructor` property and optionally a `config` property holding * an object to pass to the constructor function. * - * @attribute createNavigationItems + * @attribute studioplusNavigationItems * @type Array of Y.View * @writeOnce */ - optimizeNavigationItems: { + adminNavigationItems: { setter: '_buildNavigationViews', writeOnce: true, }, /** * Stores the navigation view item views instance for each item in - * the navigation for the deliver zone. This attribute accepts either + * the navigation for the studioplus zone. This attribute accepts either * an array of already build views or an array of object with at a * `Constructor` property and optionally a `config` property holding * an object to pass to the constructor function. * - * @attribute createNavigationItems + * @attribute studioplusNavigationItems * @type Array of Y.View * @writeOnce */ - deliverNavigationItems: { + studioplusNavigationItems: { setter: '_buildNavigationViews', writeOnce: true, }, /** - * Contains the identifier ('create', 'optimize', ...) of the + * Contains the identifier ('platform', 'studio', ...) of the * currently active navigation. When set, this attribute updates the * `_navigationMenu` property with the corresponding Node * @@ -571,7 +655,7 @@ YUI.add('ez-navigationhubview', function (Y) { */ activeNavigation: { setter: '_setNavigationMenu', - value: DEFAULT_ACTIVE_NAV, + value: null, }, /** diff --git a/Resources/public/js/views/navigation/ez-navigationitemparameterview.js b/Resources/public/js/views/navigation/ez-navigationitemparameterview.js new file mode 100644 index 000000000..bf98adbd8 --- /dev/null +++ b/Resources/public/js/views/navigation/ez-navigationitemparameterview.js @@ -0,0 +1,77 @@ +/* + * Copyright (C) eZ Systems AS. All rights reserved. + * For full copyright and license information view LICENSE file distributed with this source code. + */ +YUI.add('ez-navigationitemparameterview', function (Y) { + "use strict"; + /** + * Provides a navigation item parameter view + * + * @module ez-navigationitemparameterview + */ + Y.namespace('eZ'); + + /** + * The navigation item parameter view. It can be used when the associated + * route is generic route and the matching needs to take a parameter into + * account. + * + * @namespace eZ + * @class NavigationItemParameterView + * @constructor + * @extends eZ.TemplateBasedView + */ + Y.eZ.NavigationItemParameterView = Y.Base.create('navigationItemParameterView', Y.eZ.NavigationItemView, [], { + _getName: function () { + return Y.eZ.NavigationItemView.NAME; + }, + + /** + * Checks that the `matchParameter` has the same value in the matched + * route and in the `route` attribute + * + * @protected + * @method _parameterMatch + * @param {Object} route the matched route object + * @return {Boolean} + */ + _parameterMatch: function (route) { + var matchParameter = this.get('matchParameter'), + linkRoute = this.get('route'); + + return ( + typeof route.parameters[matchParameter] !== 'undefined' + && linkRoute.params[matchParameter] === route.parameters[matchParameter] + ); + }, + + /** + * Checks whether the navigation item is selected or not based on the + * location id in the route. + * + * @method matchRoute + * @param {Object} route the matched route object + * @return {Boolean} + */ + matchRoute: function (route) { + var selected = (this._sameRoute(route) && this._parameterMatch(route)); + + this._set('selected', selected); + return selected; + }, + }, { + ATTRS: { + /** + * Stores the identifier of the parameter to check in the matched route + * and in the `route` attribute + * + * @attribute matchParameter + * @type {String} + * @required + */ + matchParameter: { + writeOnce: "initOnly" + }, + }, + }); +}); diff --git a/Resources/public/js/views/navigation/ez-navigationitemsubtreeview.js b/Resources/public/js/views/navigation/ez-navigationitemsubtreeview.js index 336f5b38f..76369de08 100644 --- a/Resources/public/js/views/navigation/ez-navigationitemsubtreeview.js +++ b/Resources/public/js/views/navigation/ez-navigationitemsubtreeview.js @@ -38,7 +38,7 @@ YUI.add('ez-navigationitemsubtreeview', function (Y) { linkRoute = this.get('route'), startLocatioId = linkRoute.params.id; - if ( route.name === linkRoute.name && route.parameters.id ) { + if ( this._sameRoute(route) && route.parameters.id ) { selected = (route.parameters.id.indexOf(startLocatioId) === 0); } this._set('selected', selected); diff --git a/Resources/public/js/views/navigation/ez-navigationitemview.js b/Resources/public/js/views/navigation/ez-navigationitemview.js index 0161f4aa1..43e14d88e 100644 --- a/Resources/public/js/views/navigation/ez-navigationitemview.js +++ b/Resources/public/js/views/navigation/ez-navigationitemview.js @@ -55,6 +55,19 @@ YUI.add('ez-navigationitemview', function (Y) { return this; }, + /** + * Returns whether the matched route is the same as the one stored in + * the navigation item. + * + * @method _sameRoute + * @protected + * @param {Object} route the matched route + * @return Boolean + */ + _sameRoute: function (route) { + return this.get('route').name === route.name; + }, + /** * Checks whether the navigation item is selected or not based on the * matched route object provided by the navigation hub service. diff --git a/Resources/public/js/views/services/ez-navigationhubviewservice.js b/Resources/public/js/views/services/ez-navigationhubviewservice.js index 88547b48e..f36c0416d 100644 --- a/Resources/public/js/views/services/ez-navigationhubviewservice.js +++ b/Resources/public/js/views/services/ez-navigationhubviewservice.js @@ -22,6 +22,20 @@ YUI.add('ez-navigationhubviewservice', function (Y) { Y.eZ.NavigationHubViewService = Y.Base.create('navigationHubViewService', Y.eZ.ViewService, [], { initializer: function () { this.on('*:logOut', this._logOut); + this.after('*:navigateTo', this._navigateTo); + }, + + /** + * navigateTo event handler. it redirects the user to the given route. + * + * @method _navigateTo + * @protected + * @param {EventFacade} e + */ + _navigateTo: function (e) { + var route = e.route; + + this.get('app').navigateTo(route.name, route.params); }, /** @@ -40,30 +54,97 @@ YUI.add('ez-navigationhubviewservice', function (Y) { }, /** - * Returns the navigation item for the subtree starting for the - * given location id. + * Returns a navigation item object. See the *NavigatinItems attribute. * - * @method _getSubtreeItems - * @protected + * @private + * @method _getItem + * @param {Function} constructor + * @param {Object} config + * @return {Object} + */ + _getItem: function(constructor, config) { + return { + Constructor: constructor, + config: config + }; + }, + + /** + * Returns a navigation item object describing a {{#crossLink + * "eZ.NavigationItemView"}}eZ.NavigationItemView{{/crossLink}} + * + * @private + * @method _getNavigationItem + * @param {String} title + * @param {String} identifier + * @param {String} routeName + * @param {Object} routeParams + * @return {Object} + */ + _getNavigationItem: function (title, identifier, routeName, routeParams) { + return this._getItem( + Y.eZ.NavigationItemView, { + title: title, + identifier: identifier, + route: { + name: routeName, + params: routeParams + } + } + ); + }, + + /** + * Returns the navigation item object describing a {{#crossLink + * "eZ.NavigationItemSubtreeView"}}eZ.NavigationItemSubtreeView{{/crossLink}}. + * + * @method _getSubtreeItem + * @private * @param {String} title * @param {String} identifier * @param {String} locationId * @return {Object} */ - _getSubtreeItems: function (title, identifier, locationId) { - return { - Constructor: Y.eZ.NavigationItemSubtreeView, - config: { + _getSubtreeItem: function (title, identifier, locationId) { + return this._getItem( + Y.eZ.NavigationItemSubtreeView, { title: title, identifier: identifier, route: { name: 'viewLocation', params: { - id: locationId, - }, + id: locationId + } + } + } + ); + }, + + /** + * Returns a navigation item object describing a {{#crossLink + * "eZ.NavigationItemParameterView"}}eZ.NavigationItemParameterView{{/crossLink}} + * + * @private + * @method _getParameterItem + * @param {String} title + * @param {String} identifier + * @param {String} routeName + * @param {Object} routeParams + * @param {String} matchParameter + * @return {Object} + */ + _getParameterItem: function (title, identifier, routeName, routeParams, matchParameter) { + return this._getItem( + Y.eZ.NavigationItemParameterView, { + title: title, + identifier: identifier, + route: { + name: routeName, + params: routeParams, }, - }, - }; + matchParameter: matchParameter + } + ); }, /** @@ -75,9 +156,10 @@ YUI.add('ez-navigationhubviewservice', function (Y) { _getViewParameters: function () { return { user: this.get('app').get('user'), - createNavigationItems: this.get('createNavigationItems'), - deliverNavigationItems: this.get('deliverNavigationItems'), - optimizeNavigationItems: this.get('optimizeNavigationItems'), + platformNavigationItems: this.get('platformNavigationItems'), + studioNavigationItems: this.get('studioNavigationItems'), + studioplusNavigationItems: this.get('studioplusNavigationItems'), + adminNavigationItems: this.get('adminNavigationItems'), matchedRoute: this._matchedRoute(), }; }, @@ -145,30 +227,30 @@ YUI.add('ez-navigationhubviewservice', function (Y) { }, { ATTRS: { /** - * Stores the navigation item objects for the 'create' zone. Each + * Stores the navigation item objects for the 'platform' zone. Each * object must contain a `Constructor` property referencing * the constructor function to use to build the navigation item * view and a `config` property will be used as a configuration * object for the navigation item view. This configuration must * contain a `title` and an `identifier` properties. * - * @attribute createNavigationItems + * @attribute platformNavigationItems * @type Array * @default array containing the object the 'Content structure' and * 'Media library' items * @readOnly */ - createNavigationItems: { + platformNavigationItems: { valueFn: function () { // TODO these location ids should be taken from the REST // root ressource instead of being hardcoded return [ - this._getSubtreeItems( + this._getSubtreeItem( "Content structure", "content-structure", "/api/ezp/v2/content/locations/1/2" ), - this._getSubtreeItems( + this._getSubtreeItem( "Media library", "media-library", "/api/ezp/v2/content/locations/1/43" @@ -179,40 +261,73 @@ YUI.add('ez-navigationhubviewservice', function (Y) { }, /** - * Stores the navigation item objects for the 'optimize' zone. Each + * Stores the navigation item objects for the 'studioplus' zone. Each * object must contain a `Constructor` property referencing * the constructor function to use to build the navigation item * view and a `config` property will be used as a configuration * object for the navigation item view. This configuration must * contain a `title` and an `identifier` properties. * - * @attribute optimizeNavigationItems + * @attribute studioplusNavigationItems * @type Array * @default empty array * @readOnly */ - optimizeNavigationItems: { + studioplusNavigationItems: { value: [], readOnly: true, }, /** - * Stores the navigation item objects for the 'deliver' zone. Each + * Stores the navigation item objects for the 'studio' zone. Each * object must contain a `Constructor` property referencing * the constructor function to use to build the navigation item * view and a `config` property will be used as a configuration * object for the navigation item view. This configuration must * contain a `title` and an `identifier` properties. * - * @attribute deliverNavigationItems + * @attribute studioNavigationItems * @type Array * @default empty array * @readOnly */ - deliverNavigationItems: { + studioNavigationItems: { value: [], readOnly: true, }, + + /** + * Stores the navigation item objects for the 'admin' zone. Each + * object must contain a `Constructor` property referencing + * the constructor function to use to build the navigation item + * view and a `config` property will be used as a configuration + * object for the navigation item view. This configuration must + * contain a `title` and an `identifier` properties. + * + * @attribute platformNavigationItems + * @type Array + * @default array containing the items for the admin + * @readOnly + */ + adminNavigationItems: { + valueFn: function () { + return [ + this._getParameterItem( + "Administration dashboard", "admin-dashboard", + "adminGenericRoute", {uri: "pjax/dashboard"}, "uri" + ), + this._getParameterItem( + "System information", "admin-systeminfo", + "adminGenericRoute", {uri: "pjax/systeminfo"}, "uri" + ), + this._getNavigationItem( + "Sections", "admin-sections", + "adminSection", {uri: "pjax/section/list"} + ), + ]; + }, + readOnly: true, + }, }, }); }); diff --git a/Resources/public/templates/navigationhub.hbt b/Resources/public/templates/navigationhub.hbt index 67076e43b..9cc6f4b68 100644 --- a/Resources/public/templates/navigationhub.hbt +++ b/Resources/public/templates/navigationhub.hbt @@ -1,25 +1,18 @@