/** rft/ui/content - Load page content * * The rft/ui/content module is responsible for loading content in the app. * Content is loaded by calling: * content.goTo('pageId'); * The page is then loaded from pages/pageId.html. This should contain one top node. * This top node gets a _Page widget instantiated on it. The template should not * specify another widget on the topnode. A page controller can be specified by * the data-rft-mixin attribute to a class inherited from _PageController. * You can also specify methods in the template in script tags as: * * The two relevant events are onVisit and onLeave. After loading and starting * the complete page onVisit is called. Use this to link widgets together and * load any dynamic content not handled by widget logic already. * The event onLeave is called before navigating to another page. If false is * returned from this function, the navigation will be cancelled. You can use * this e.g. to ask confirmation if changed values are not saved. */ define(['dojo/_base/declare','dojo/_base/connect','dojo/_base/xhr','dojo/_base/json', 'dojo/_base/lang','dojo/_base/Deferred','dojo/hash','dojo/dom-attr','dojo/dom-construct', 'dojo/io-query','dijit','./util','./ui/_Page'], function(declare,connect,xhr,json,lang,Deferred,hash,attr,domConstruct,uriQuery,dijit,util,_Page){ return new (function() { var self = this; var HRI = declare(null,{ constructor: function() { this._path = this._fixPath('/'); this._args = {}; if ( arguments.length == 1 ) { this.hash(arguments[0]); } else if ( arguments.length == 2 ) { this.path(arguments[0]); this.args(arguments[1]); } }, path: function(path) { if ( path ) this._path = this._fixPath(path); return this._path; }, args: function(args) { if ( args && lang.isObject(args) ) this._args = args; return this._args; }, hash: function(hash) { if ( hash && lang.isString(hash) ) { var parts = hash.split('!'); if ( parts[1] ) this._path = this._fixPath(parts[1]); if ( parts[2] ) this._args = uriQuery.queryToObject(parts[2]); } return '!'+this._path+'!'+uriQuery.objectToQuery(this._args); }, _fixPath: function(path) { if ( !lang.isString(path) || util.isEmptyString(path) ) { path = "/"; } if ( path[0] != '/' ) { path = '/'+path; } if ( path[path.length-1] == '/' ) { path = path + "index"; } return path; } }); var currentHri = null; var currentPage = null; function _goTo(hri,replace) { var contentPane = dijit.byId('content'); var dfd = new Deferred(); // if already there, return if ( currentHri && currentHri.hash() === hri.hash() ) { dfd.resolve(); return dfd.promise; } // check if we can leave current page if ( currentPage ) { if ( currentPage.onLeave() === false ) { // restore hash if changed by hand or back button hash(currentHri.hash()); dfd.reject(); return dfd.promise; } currentPage = null; } function getFirstNode(html) { var nodeOrFragment = domConstruct.toDom(html); if (nodeOrFragment instanceof Element) { return nodeOrFragment; } if (nodeOrFragment instanceof DocumentFragment) { console.warn("Fragment found, will only use first Element"); for (i in nodeOrFragment.childNodes) { var node = nodeOrFragment.childNodes[i]; if (node instanceof Element) { return node; } } } return domConstruct.toDom('
No Element found in template.
'); } function mixinArgs(node) { var props = {}; if ( attr.has(node,'data-dojo-props') ) { props = json.fromJson(attr.get(node,'data-dojo-props')); } lang.mixin(props,{pageArgs:hri.args()}); var jsonStr = json.toJson(props); attr.set(node,'data-dojo-props',jsonStr.slice(1,jsonStr.length-1)); } // update hash currentHri = hri; hash(hri.hash(),replace); // load html var pageUrl = 'rft/pages'+hri.path()+'.html'; xhr.get({ url: pageUrl, failOk: true }) // initialize page or create error message .then(function(html){ var rootNode = getFirstNode(html); mixinArgs(rootNode); contentPane.set('content',rootNode); currentPage = dijit.byNode(rootNode); if ( !currentPage ) { currentPage = new _Page({},rootNode); } dfd.resolve(); },function(){ contentPane.set('content',"
Page "+hri.path()+" not found.
"); dfd.reject(); }); return dfd.promise; } self.initial = function(path,args) { if ( currentHri ) { var dfd = new Deferred(); dfd.resolve(); return dfd.promise; } if ( hash() ) { var hri = new HRI(hash()); return _goTo(hri, true); } else { return _goTo(new HRI(path,args)); } }; self.goTo = function(path,args) { return _goTo(new HRI(path,args)); } self.getArgs = function() { if ( currentHri ) { return currentHri.args(); } else { return {}; } }; connect.subscribe('/dojo/hashchange', function(){ _goTo(new HRI(hash())); }); })(); });