summaryrefslogtreecommitdiffstats
path: root/install/ui/src
diff options
context:
space:
mode:
Diffstat (limited to 'install/ui/src')
-rw-r--r--install/ui/src/freeipa/Application_controller.js18
-rw-r--r--install/ui/src/freeipa/navigation.js31
-rw-r--r--install/ui/src/freeipa/navigation/Router.js243
-rw-r--r--install/ui/src/freeipa/navigation/routing.js505
4 files changed, 538 insertions, 259 deletions
diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js
index 5a0b67b80..9ed0bc6e9 100644
--- a/install/ui/src/freeipa/Application_controller.js
+++ b/install/ui/src/freeipa/Application_controller.js
@@ -35,10 +35,11 @@ define([
'./reg',
'./navigation/Menu',
'./navigation/Router',
+ './navigation/routing',
'./navigation/menu_spec'
],
function(declare, lang, array, Deferred, on, topic, query, dom_class, auth,
- JSON, App_widget, FacetContainer, IPA, reg, Menu, Router, menu_spec) {
+ JSON, App_widget, FacetContainer, IPA, reg, Menu, Router, routing, menu_spec) {
/**
* Application controller
@@ -78,6 +79,7 @@ define([
init: function() {
this.menu = new Menu();
this.router = new Router();
+ routing.init(this.router);
var body_node = query('body')[0];
this.app_widget = new App_widget();
@@ -181,7 +183,7 @@ define([
if (IPA.is_selfservice) {
this.on_profile();
} else {
- this.router.navigate_to_entity_facet('user', 'search');
+ routing.navigate(routing.default_path);
}
},
@@ -219,7 +221,7 @@ define([
},
on_profile: function() {
- this.router.navigate_to_entity_facet('user', 'details', [IPA.whoami.uid[0]]);
+ routing.navigate(['entity', 'user', 'details', [IPA.whoami.uid[0]]]);
},
on_logout: function(event) {
@@ -287,8 +289,7 @@ define([
on_facet_state_changed: function(event) {
if (event.facet === this.current_facet) {
- var hash = this.router.create_hash(event.facet, event.state);
- this.router.update_hash(hash, true);
+ routing.update_hash(event.facet, event.state);
}
},
@@ -405,14 +406,15 @@ define([
if (!child) {
if(menu_item.entity) {
// entity pages
- this.router.navigate_to_entity_facet(
+ routing.navigate([
+ 'entity',
menu_item.entity,
menu_item.facet,
menu_item.pkeys,
- menu_item.args);
+ menu_item.args]);
} else if (menu_item.facet) {
// concrete facets
- this.router.navigate_to_facet(menu_item.facet, menu_item.args);
+ routing.navigate(['generic', menu_item.facet, menu_item.args]);
} else {
// categories, select first posible child, it may be the last
var children = this.menu.query({parent: menu_item.name });
diff --git a/install/ui/src/freeipa/navigation.js b/install/ui/src/freeipa/navigation.js
index 7cf309f15..105e867cb 100644
--- a/install/ui/src/freeipa/navigation.js
+++ b/install/ui/src/freeipa/navigation.js
@@ -21,16 +21,11 @@
define([
'dojo/_base/lang',
- './app_container',
- './ipa'
+ './navigation/routing'
],
- function(lang, app_container, IPA) {
+ function(lang, routing) {
- var get_router = function() {
- return app_container.app.router;
- };
-
var navigation = {
/**
* Navigation tells application to show certain facet.
@@ -88,7 +83,6 @@ define([
*/
show: function(arg1, arg2, arg3) {
- var nav = get_router();
var params = {};
this.set_params(params, arg1);
@@ -98,19 +92,20 @@ define([
var facet = params.facet;
if (typeof facet === 'string') {
- nav.navigate_to_facet(facet, params.args);
+ return routing.navigate(['generic', facet, params.args]);
}
if (!facet) throw 'Argument exception: missing facet';
if (facet && facet.entity) {
- return nav.navigate_to_entity_facet(
+ return routing.navigate([
+ 'entity',
facet.entity.name,
facet.name,
params.pkeys,
- params.args);
+ params.args]);
} else {
- return nav.navigate_to_facet(facet.name, params.args);
+ return routing.navigate(['generic', facet.name, params.args]);
}
},
@@ -128,14 +123,12 @@ define([
* @param {Object|facet.facet|string|Function} arg3
*/
show_entity: function(entity_name, arg1, arg2, arg3) {
- var nav = get_router();
var params = {};
-
this.set_params(params, arg1);
this.set_params(params, arg2);
this.set_params(params, arg3);
- return nav.navigate_to_entity_facet(entity_name, params.facet,
- params.pkeys, params.args);
+ return routing.navigate(['entity', entity_name, params.facet,
+ params.pkeys, params.args]);
},
/**
@@ -150,8 +143,7 @@ define([
* notification purposes
*/
show_generic: function(hash, facet) {
- var nav = get_router();
- nav.navigate_to_hash(hash, facet);
+ routing.router.navigate_to_hash(hash, facet);
},
/**
@@ -159,8 +151,7 @@ define([
* @method show_default
*/
show_default: function() {
- // TODO: make configurable
- return this.show_entity('user', 'search');
+ routing.navigate(routing.default_path);
}
};
return navigation;
diff --git a/install/ui/src/freeipa/navigation/Router.js b/install/ui/src/freeipa/navigation/Router.js
index a3b2a6791..a65c60fd3 100644
--- a/install/ui/src/freeipa/navigation/Router.js
+++ b/install/ui/src/freeipa/navigation/Router.js
@@ -20,14 +20,10 @@
define(['dojo/_base/declare',
'dojo/_base/lang',
- 'dojo/_base/array',
'dojo/Evented',
- 'dojo/io-query',
- 'dojo/router',
- '../ipa',
- '../reg'
+ 'dojo/router'
],
- function(declare, lang, array, Evented, ioquery, router, IPA, reg) {
+ function(declare, lang, Evented, router) {
/**
* Router
@@ -56,27 +52,6 @@ define(['dojo/_base/declare',
route_prefix: '',
/**
- * Variations of entity routes
- * @property {Array.<string>}
- */
- entity_routes: [
- '/e/:entity/:facet/:pkeys/*args',
- '/e/:entity/:facet//*args',
- '/e/:entity/:facet/:pkeys',
- '/e/:entity/:facet',
- '/e/:entity'
- ],
-
- /**
- * Variations of simple page routes
- * @property {Array.<string>}
- */
- page_routes: [
- '/p/:page/*args',
- '/p/:page'
- ],
-
- /**
* Used during facet changing. Set it to true in 'facet-change'
* event handler to stop the change.
* @property {boolean}
@@ -100,145 +75,22 @@ define(['dojo/_base/declare',
* @param {Function} handler to be associated with the route(s)
*/
register_route: function(route, handler) {
- // TODO: add multiple routes for one handler
- route = this.route_prefix + route;
- this.route_handlers.push(router.register(route, lang.hitch(this, handler)));
- },
-
- /**
- * Initializates router
- * - registers handlers
- */
- init_router: function() {
-
- // entity pages
- array.forEach(this.entity_routes, function(route) {
- this.register_route(route, this.entity_route_handler);
- }, this);
-
- // special pages
- array.forEach(this.page_routes, function(route) {
- this.register_route(route, this.page_route_handler);
- }, this);
- },
-
- /**
- * Handler for entity routes
- * Shouldn't be invoked directly.
- * @param {Object} event route event args
- */
- entity_route_handler: function(event) {
-
- if (this.check_clear_ignore()) return;
-
- var entity_name = event.params.entity;
- var facet_name = event.params.facet;
- var pkeys, args;
- try {
- pkeys = this._decode_pkeys(event.params.pkeys || '');
- args = ioquery.queryToObject(event.params.args || '');
- } catch (e) {
- this._error('URI error', 'route', event.params);
- return;
- }
- args.pkeys = pkeys;
-
- // set new facet state
- var entity = reg.entity.get(entity_name);
- if (!entity) {
- this._error('Unknown entity', 'route', event.params);
- return;
- }
- var facet = entity.get_facet(facet_name);
- if (!facet) {
- this._error('Unknown facet', 'route', event.params);
- return;
- }
- facet.reset_state(args);
-
- this.show_facet(facet);
- },
-
- /**
- * General facet route handler
- * Shouldn't be invoked directly.
- * @param {Object} event route event args
- */
- page_route_handler: function(event) {
-
- if (this.check_clear_ignore()) return;
-
- var facet_name = event.params.page;
- var args;
- try {
- args = ioquery.queryToObject(event.params.args || '');
- } catch (e) {
- this._error('URI error', 'route', event.params);
- return;
- }
-
- // set new facet state
- var facet = reg.facet.get(facet_name);
- if (!facet) {
- this._error('Unknown facet', 'route', event.params);
- return;
- }
- facet.reset_state(args);
-
- this.show_facet(facet);
- },
-
- /**
- * Used for switching to entitie's facets. Current target facet
- * state is used as params (pkeys, args) when none of pkeys and args
- * are used (useful for switching to previous page with keeping the context).
- */
- navigate_to_entity_facet: function(entity_name, facet_name, pkeys, args) {
-
- var entity = reg.entity.get(entity_name);
- if (!entity) {
- this._error('Unknown entity', 'navigation', { entity: entity_name});
- return false;
- }
-
- var facet = entity.get_facet(facet_name);
- if (!facet) {
- this._error('Unknown facet', 'navigation', { facet: facet_name});
- return false;
- }
-
- // Use current state if none supplied
- if (!pkeys && !args) {
- args = facet.get_state();
- }
- args = args || {};
-
- // Facets may be nested and require more pkeys than supplied.
- args.pkeys = facet.get_pkeys(pkeys);
- var hash = this._create_entity_facet_hash(facet, args);
- return this.navigate_to_hash(hash, facet);
- },
-
- /**
- * Navigate to other facet.
- */
- navigate_to_facet: function(facet_name, args) {
-
- var facet = reg.facet.get(facet_name);
- if (!facet) {
- this._error('Unknown facet', 'navigation', { facet: facet_name});
- return false;
+ if (route instanceof Array) {
+ for (var i=0, l=route.length; i<l; i++) {
+ this.register_route(route[i], handler);
+ }
+ } else {
+ var r = this.route_prefix + route;
+ this.route_handlers.push(router.register(r, lang.hitch(this, handler)));
}
- if (!args) args = facet.get_state();
- var hash = this._create_facet_hash(facet, args);
- return this.navigate_to_hash(hash, facet);
},
/**
- * Low level function.
+ * Navigate to given hash
*
- * Public usage should be limited reinitializing canceled navigations.
+ * @fires facet-change
+ * @fires facet-change-canceled
*/
navigate_to_hash: function(hash, facet) {
@@ -273,48 +125,6 @@ define(['dojo/_base/declare',
},
/**
- * Creates from facet state appropriate hash.
- */
- _create_entity_facet_hash: function(facet, state) {
- state = lang.clone(state);
- var entity_name = facet.entity.name;
- var pkeys = this._encode_pkeys(state.pkeys || []);
- delete state.pkeys;
- var args = ioquery.objectToQuery(state || {});
-
- var path = [this.route_prefix, 'e', entity_name, facet.name];
- if (!IPA.is_empty(args)) path.push(pkeys, args);
- else if (!IPA.is_empty(pkeys)) path.push(pkeys);
-
- var hash = path.join('/');
- return hash;
- },
-
- /**
- * Creates hash of general facet.
- */
- _create_facet_hash: function(facet, state) {
- var args = ioquery.objectToQuery(state.args || {});
- var path = [this.route_prefix, 'p', facet.name];
-
- if (!IPA.is_empty(args)) path.push(args);
- var hash = path.join('/');
- return hash;
- },
-
- /**
- * Creates hash from supplied facet and state.
- *
- * @param {facet.facet} facet
- * @param {Object} state
- */
- create_hash: function(facet, state) {
- if (facet.entity) return this._create_entity_facet_hash(facet, state);
- else return this._create_facet_hash(facet, state);
- },
-
-
- /**
* Tells other component to show given facet.
*/
show_facet: function(facet) {
@@ -325,34 +135,6 @@ define(['dojo/_base/declare',
},
/**
- * URI Encodes array items and delimits them by '&'
- * Example: ['foo ', 'bar'] => 'foo%20&bar'
- */
- _encode_pkeys: function(pkeys) {
-
- var ret = [];
- array.forEach(pkeys, function(pkey) {
- ret.push(encodeURIComponent(pkey));
- });
- return ret.join('&');
- },
-
- /**
- * Splits strings by '&' and return an array of URI decoded parts.
- * Example: 'foo%20&bar' => ['foo ', 'bar']
- */
- _decode_pkeys: function(str) {
-
- if (!str) return [];
-
- var keys = str.split('&');
- for (var i=0; i<keys.length; i++) {
- keys[i] = decodeURIComponent(keys[i]);
- }
- return keys;
- },
-
- /**
* Raise 'error'
* @protected
* @fires error
@@ -375,7 +157,6 @@ define(['dojo/_base/declare',
constructor: function(spec) {
spec = spec || {};
- this.init_router();
}
});
diff --git a/install/ui/src/freeipa/navigation/routing.js b/install/ui/src/freeipa/navigation/routing.js
new file mode 100644
index 000000000..6e18b0228
--- /dev/null
+++ b/install/ui/src/freeipa/navigation/routing.js
@@ -0,0 +1,505 @@
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2014 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/_base/array',
+ 'dojo/io-query',
+ '../reg',
+ '../util'
+ ],
+ function(declare, lang, array, ioquery, reg, util) {
+
+/**
+ * Routing mechanism
+ * @class navigation.routing
+ * @singleton
+ */
+var routing = {
+
+ /**
+ * Router instance
+ * @property {navigation.Router}
+ */
+ router: null,
+
+ /**
+ * Map of router handlers
+ * @property {Object}
+ */
+ route_handlers: {},
+
+ /**
+ * Map of hash creators
+ * @property {Object}
+ */
+ hash_creators: {},
+
+ /**
+ * Facet name to hash creator map
+ *
+ * - Key: facet name
+ * - Value: hash creator
+ *
+ * @type {Object}
+ */
+ hc_facet_map: {},
+
+ /**
+ * Hash creator priority queue
+ *
+ * First item == highest priority
+ *
+ * @type {Array}
+ */
+ hc_queue: [],
+
+ /**
+ * Map of navigators
+ * @type {Object}
+ */
+ navigators: {},
+
+ /**
+ * Add hash creator at the beginning of hash creator queue
+ * @param {navigation.routing.HashCreator} hash_creator
+ * @param {Number} [position]
+ */
+ add_hash_creator: function(hash_creator, position) {
+
+ if (position !== undefined) {
+ this.hc_queue.splice(position, 0, hash_creator);
+ } else {
+ this.hc_queue.unshift(hash_creator);
+ }
+ },
+
+ /**
+ * Add hash creator to hash creator map
+ * @param {string} facet_name
+ * @param {navigation.routing.HashCreator} hash_creator
+ */
+ assign_hash_creator: function (facet_name, hash_creator) {
+ this.hc_facet_map[facet_name] = hash_creator;
+ },
+
+ /**
+ * Get hash creator for given facet
+ *
+ * Lookup priority:
+ *
+ * - facet -> hash creator map
+ * - hash creator queue
+ *
+ * @param {facets.Facet} facet [description]
+ * @return {navigation.routing.HashCreator}
+ */
+ get_hash_creator: function(facet) {
+
+ var name = facet.name;
+ var hc = this.hc_facet_map[name];
+ if (!hc) {
+ for (var i=0, l=this.hc_queue.length; i<l; i++) {
+ if (this.hc_queue[i].handles(facet)) {
+ hc = this.hc_queue[i];
+ break;
+ }
+ }
+ }
+ return hc || null;
+ },
+
+ /**
+ * Create hash for given facet
+ *
+ * @param {facets.Facet} facet
+ * @param {Object|null} options
+ * @return {string} hash
+ */
+ create_hash: function(facet, options) {
+ var hc = this.get_hash_creator(facet);
+ if (!hc) return '';
+ return hc.create_hash(this.router, facet, options);
+ },
+
+ /**
+ * Navigate by a Navigator
+ *
+ * Expects path as argument. Path is an array where
+ * first element is name of the Navigator, rest are
+ * navigators params.
+ *
+ * @param {Array} path
+ * @return {boolean}
+ */
+ navigate: function(path) {
+
+ path = path.slice(0);
+ var nav_name = path.shift();
+ var nav = this.get_navigator(nav_name);
+ return nav.navigate.apply(nav, path);
+ },
+
+ /**
+ * Navigate to specific facet with give options
+ * @param {facets.Facet} facet
+ * @param {Object} options Options for hash creator
+ * @return {boolean}
+ */
+ navigate_to_facet: function(facet, options) {
+ var hash = this.create_hash(facet, options);
+ return this.router.navigate_to_hash(hash);
+ },
+
+ update_hash: function(facet, options) {
+
+ var hash = this.create_hash(facet, options);
+ this.router.update_hash(hash, true);
+ },
+
+ /**
+ * Add route handler to router
+ * @param {string|string[]} route Route or routes.
+ * @param {navigation.routing.RouteHandler} handler Handler
+ */
+ add_route: function(route, handler) {
+ this.route_handlers[handler.name] = handler;
+ this.router.register_route(route, handler.get_handler());
+ },
+
+ /**
+ * Add navigator
+ * @param {navigation.routing.Navigator} navigator
+ */
+ add_navigator: function(navigator) {
+ this.navigators[navigator.name] = navigator;
+ },
+
+ /**
+ * Get navigator by name
+ * @param {string} name Navigator's name
+ * @return {navigation.routing.Navigator}
+ */
+ get_navigator: function(name) {
+ return this.navigators[name];
+ },
+
+ /**
+ * Path for default facet
+ * @type {Array}
+ */
+ default_path: ['entity', 'user', 'search'],
+
+ /**
+ * Variations of entity routes
+ * @property {string[]}
+ */
+ entity_routes: [
+ '/e/:entity/:facet/:pkeys/*args',
+ '/e/:entity/:facet//*args',
+ '/e/:entity/:facet/:pkeys',
+ '/e/:entity/:facet',
+ '/e/:entity'
+ ],
+
+ /**
+ * Variations of simple page routes
+ * @property {string[]}
+ */
+ page_routes: [
+ '/p/:page/*args',
+ '/p/:page'
+ ]
+};
+
+/**
+ * General route handler
+ *
+ * @class navigation.routing.RouteHandler
+ */
+routing.RouteHandler = declare([], {
+
+ handler: null,
+
+ name: 'generic',
+
+ /**
+ * Handle router event
+ * @param {Object} event
+ * @param {navigation.Router} router
+ */
+ handle: function (event, router) {
+ if (router.check_clear_ignore()) return;
+
+ var facet_name = event.params.page;
+ var args;
+ try {
+ args = ioquery.queryToObject(event.params.args || '');
+ } catch (e) {
+ router._error('URI error', 'route', event.params);
+ return;
+ }
+
+ // set new facet state
+ var facet = reg.facet.get(facet_name);
+ if (!facet) {
+ router._error('Unknown facet', 'route', event.params);
+ return;
+ }
+ facet.reset_state(args);
+ router.show_facet(facet);
+ },
+
+ /**
+ * Create handler callback for router
+ * @return {Function} callback
+ */
+ get_handler: function() {
+
+ if (!this.handler) {
+ var self = this;
+ this.handler = function(event) {
+ self.handle(event, this);
+ };
+ }
+ return this.handler;
+ }
+});
+
+/**
+ * Entity route handler
+ *
+ * @class navigation.routing.EntityRouteHandler
+ * @extends {navigation.routing.RouteHandler}
+ */
+routing.EntityRouteHandler = declare([routing.RouteHandler], {
+
+ name: 'entity',
+
+ /**
+ * @inheritDoc
+ */
+ handle: function (event, router) {
+ if (router.check_clear_ignore()) return;
+
+ var entity_name = event.params.entity;
+ var facet_name = event.params.facet;
+ var pkeys, args;
+ try {
+ pkeys = this._decode_pkeys(event.params.pkeys || '');
+ args = ioquery.queryToObject(event.params.args || '');
+ } catch (e) {
+ router._error('URI error', 'route', event.params);
+ return;
+ }
+ args.pkeys = pkeys;
+
+ // set new facet state
+ var entity = reg.entity.get(entity_name);
+ if (!entity) {
+ router._error('Unknown entity', 'route', event.params);
+ return;
+ }
+ var facet = entity.get_facet(facet_name);
+ if (!facet) {
+ router._error('Unknown facet', 'route', event.params);
+ return;
+ }
+ facet.reset_state(args);
+ router.show_facet(facet);
+ },
+
+ /**
+ * Splits strings by '&' and return an array of URI decoded parts.
+ * Example: 'foo%20&bar' => ['foo ', 'bar']
+ */
+ _decode_pkeys: function(str) {
+
+ if (!str) return [];
+
+ var keys = str.split('&');
+ for (var i=0; i<keys.length; i++) {
+ keys[i] = decodeURIComponent(keys[i]);
+ }
+ return keys;
+ }
+});
+
+/**
+ * Hash creator creates a hash string from given facet and options
+ *
+ * This is default hash creator for generic facets.
+ *
+ * @class navigation.routing.HashCreator
+ */
+routing.HashCreator = declare([], {
+
+ prefix: 'p',
+
+ name: 'generic',
+
+ create_hash: function(router, facet, options) {
+
+ var path = [router.route_prefix, this.prefix, facet.name];
+ var args = ioquery.objectToQuery(options || {});
+ if (!util.is_empty(args)) path.push(args);
+ var hash = path.join('/');
+ return hash;
+ },
+
+ handles: function(facet) {
+ return true;
+ }
+});
+
+/**
+ * Hash creator for entity facets
+ * @class navigation.routing.EntityHashCreator
+ * @extends navigation.routing.HashCreator
+ */
+routing.EntityHashCreator = declare([routing.HashCreator], {
+
+ prefix: 'e',
+
+ name: 'entity',
+
+ create_hash: function(router, facet, options) {
+
+ options = lang.clone(options);
+ var entity_name = facet.entity.name;
+ var pkeys = this._encode_pkeys(options.pkeys || []);
+ delete options.pkeys;
+ var args = ioquery.objectToQuery(options || {});
+
+ var path = [router.route_prefix, this.prefix, entity_name, facet.name];
+ if (!util.is_empty(args)) path.push(pkeys, args);
+ else if (!util.is_empty(pkeys)) path.push(pkeys);
+
+ var hash = path.join('/');
+ return hash;
+ },
+
+ handles: function(facet) {
+ return !!facet.entity;
+ },
+
+ /**
+ * URI Encodes array items and delimits them by '&'
+ * Example: ['foo ', 'bar'] => 'foo%20&bar'
+ */
+ _encode_pkeys: function(pkeys) {
+
+ var ret = [];
+ array.forEach(pkeys, function(pkey) {
+ ret.push(encodeURIComponent(pkey));
+ });
+ return ret.join('&');
+ }
+});
+
+/**
+ * Navigate to other facet.
+ *
+ * @class navigation.routing.Navigator
+ */
+routing.Navigator = declare([], {
+
+ name: 'generic',
+
+ navigate: function(facet_name, args) {
+
+ var facet = reg.facet.get(facet_name);
+ if (!facet) {
+ routing.router._error('Unknown facet', 'navigation', { facet: facet_name});
+ return false;
+ }
+ if (!args) args = facet.get_state();
+
+ return routing.navigate_to_facet(facet, args);
+ }
+});
+
+/**
+ * Used for switching to entities' facets. Current target facet
+ * state is used as params (pkeys, args) when none of pkeys and args
+ * are used (useful for switching to previous page with keeping the context).
+ *
+ * @class navigation.routing.EntityNavigator
+ * @extends navigation.routing.Navigator
+ */
+routing.EntityNavigator = declare([routing.Navigator], {
+
+ name: 'entity',
+
+ navigate: function(entity_name, facet_name, pkeys, args) {
+
+ var entity = reg.entity.get(entity_name);
+ if (!entity) {
+ routing.router._error('Unknown entity', 'navigation', { entity: entity_name});
+ return false;
+ }
+
+ var facet = entity.get_facet(facet_name);
+ if (!facet) {
+ routing.router._error('Unknown facet', 'navigation', { facet: facet_name});
+ return false;
+ }
+
+ // Use current state if none supplied
+ if (!pkeys && !args) {
+ args = facet.get_state();
+ }
+ args = args || {};
+
+ // Facets may be nested and require more pkeys than supplied.
+ args.pkeys = facet.get_pkeys(pkeys);
+
+ return routing.navigate_to_facet(facet, args);
+ }
+});
+
+/**
+ * Init routing
+ *
+ * Sets default routes, handlers, hash creators and navigators
+ *
+ * @param {navigation.Router} router
+ */
+routing.init = function(router) {
+
+ if (router) this.router = router;
+ var generic_hc = new routing.HashCreator();
+ var entity_hc = new routing.EntityHashCreator();
+ var generic_rh = new routing.RouteHandler();
+ var entity_rh = new routing.EntityRouteHandler();
+ var generic_n = new routing.Navigator();
+ var entity_n = new routing.EntityNavigator();
+ this.add_hash_creator(generic_hc);
+ this.add_hash_creator(entity_hc);
+ this.add_route(this.routes, generic_rh);
+ this.add_route(this.entity_routes, entity_rh);
+ this.add_navigator(generic_n);
+ this.add_navigator(entity_n);
+};
+
+return routing;
+
+}); \ No newline at end of file