/** * Durandal 2.1.0 Copyright (c) 2012 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(); } }; });