durandal
Version:
Durandal is a cross-device, cross-platform client framework written in JavaScript and designed to make Single Page Applications (SPAs) easy to create and maintain. We've used it to build apps for PC, Mac, Linux, iOS and Android...and now it's your turn...
159 lines (143 loc) • 6.65 kB
JavaScript
/**
* Durandal 2.2.0 Copyright (c) 2010-2016 Blue Spire Consulting, Inc. All Rights Reserved.
* Available via the MIT license.
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
*/
/**
* The viewLocator module collaborates with the viewEngine module to provide views (literally dom sub-trees) to other parts of the framework as needed. The primary consumer of the viewLocator is the composition module.
* @module viewLocator
* @requires system
* @requires viewEngine
*/
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
function findInElements(nodes, url) {
for (var i = 0; i < nodes.length; i++) {
var current = nodes[i];
var existingUrl = current.getAttribute('data-view');
if (existingUrl == url) {
return current;
}
}
}
function escape(str) {
return (str + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
}
/**
* @class ViewLocatorModule
* @static
*/
return {
/**
* Allows you to set up a convention for mapping module folders to view folders. It is a convenience method that customizes `convertModuleIdToViewId` and `translateViewIdToArea` under the covers.
* @method useConvention
* @param {string} [modulesPath] A string to match in the path and replace with the viewsPath. If not specified, the match is 'viewmodels'.
* @param {string} [viewsPath] The replacement for the modulesPath. If not specified, the replacement is 'views'.
* @param {string} [areasPath] Partial views are mapped to the "views" folder if not specified. Use this parameter to change their location.
*/
useConvention: function(modulesPath, viewsPath, areasPath) {
modulesPath = modulesPath || 'viewmodels';
viewsPath = viewsPath || 'views';
areasPath = areasPath || viewsPath;
var reg = new RegExp(escape(modulesPath), 'gi');
this.convertModuleIdToViewId = function (moduleId) {
return moduleId.replace(reg, viewsPath);
};
this.translateViewIdToArea = function (viewId, area) {
if (!area || area == 'partial') {
return areasPath + '/' + viewId;
}
return areasPath + '/' + area + '/' + viewId;
};
},
/**
* Maps an object instance to a view instance.
* @method locateViewForObject
* @param {object} obj The object to locate the view for.
* @param {string} [area] The area to translate the view to.
* @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
* @return {Promise} A promise of the view.
*/
locateViewForObject: function(obj, area, elementsToSearch) {
var view;
if (obj.getView) {
view = obj.getView();
if (view) {
return this.locateView(view, area, elementsToSearch);
}
}
if (obj.viewUrl) {
return this.locateView(obj.viewUrl, area, elementsToSearch);
}
var id = system.getModuleId(obj);
if (id) {
return this.locateView(this.convertModuleIdToViewId(id), area, elementsToSearch);
}
return this.locateView(this.determineFallbackViewId(obj), area, elementsToSearch);
},
/**
* Converts a module id into a view id. By default the ids are the same.
* @method convertModuleIdToViewId
* @param {string} moduleId The module id.
* @return {string} The view id.
*/
convertModuleIdToViewId: function(moduleId) {
return moduleId;
},
/**
* If no view id can be determined, this function is called to genreate one. By default it attempts to determine the object's type and use that.
* @method determineFallbackViewId
* @param {object} obj The object to determine the fallback id for.
* @return {string} The view id.
*/
determineFallbackViewId: function (obj) {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((obj).constructor.toString());
var typeName = (results && results.length > 1) ? results[1] : "";
typeName = typeName.trim();
return 'views/' + typeName;
},
/**
* Takes a view id and translates it into a particular area. By default, no translation occurs.
* @method translateViewIdToArea
* @param {string} viewId The view id.
* @param {string} area The area to translate the view to.
* @return {string} The translated view id.
*/
translateViewIdToArea: function (viewId, area) {
return viewId;
},
/**
* Locates the specified view.
* @method locateView
* @param {string|DOMElement} viewOrUrlOrId A view, view url or view id to locate.
* @param {string} [area] The area to translate the view to.
* @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
* @return {Promise} A promise of the view.
*/
locateView: function(viewOrUrlOrId, area, elementsToSearch) {
if (typeof viewOrUrlOrId === 'string') {
var viewId;
if (viewEngine.isViewUrl(viewOrUrlOrId)) {
viewId = viewEngine.convertViewUrlToViewId(viewOrUrlOrId);
} else {
viewId = viewOrUrlOrId;
}
if (area) {
viewId = this.translateViewIdToArea(viewId, area);
}
if (elementsToSearch) {
var existing = findInElements(elementsToSearch, viewId);
if (existing) {
return system.defer(function(dfd) {
dfd.resolve(existing);
}).promise();
}
}
return viewEngine.createView(viewId);
}
return system.defer(function(dfd) {
dfd.resolve(viewOrUrlOrId);
}).promise();
}
};
});