viewLocator.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /**
  2. * Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
  3. * Available via the MIT license.
  4. * see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
  5. */
  6. /**
  7. * 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.
  8. * @module viewLocator
  9. * @requires system
  10. * @requires viewEngine
  11. */
  12. define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
  13. function findInElements(nodes, url) {
  14. for (var i = 0; i < nodes.length; i++) {
  15. var current = nodes[i];
  16. var existingUrl = current.getAttribute('data-view');
  17. if (existingUrl == url) {
  18. return current;
  19. }
  20. }
  21. }
  22. function escape(str) {
  23. return (str + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
  24. }
  25. /**
  26. * @class ViewLocatorModule
  27. * @static
  28. */
  29. return {
  30. /**
  31. * 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.
  32. * @method useConvention
  33. * @param {string} [modulesPath] A string to match in the path and replace with the viewsPath. If not specified, the match is 'viewmodels'.
  34. * @param {string} [viewsPath] The replacement for the modulesPath. If not specified, the replacement is 'views'.
  35. * @param {string} [areasPath] Partial views are mapped to the "views" folder if not specified. Use this parameter to change their location.
  36. */
  37. useConvention: function(modulesPath, viewsPath, areasPath) {
  38. modulesPath = modulesPath || 'viewmodels';
  39. viewsPath = viewsPath || 'views';
  40. areasPath = areasPath || viewsPath;
  41. var reg = new RegExp(escape(modulesPath), 'gi');
  42. this.convertModuleIdToViewId = function (moduleId) {
  43. return moduleId.replace(reg, viewsPath);
  44. };
  45. this.translateViewIdToArea = function (viewId, area) {
  46. if (!area || area == 'partial') {
  47. return areasPath + '/' + viewId;
  48. }
  49. return areasPath + '/' + area + '/' + viewId;
  50. };
  51. },
  52. /**
  53. * Maps an object instance to a view instance.
  54. * @method locateViewForObject
  55. * @param {object} obj The object to locate the view for.
  56. * @param {string} [area] The area to translate the view to.
  57. * @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
  58. * @return {Promise} A promise of the view.
  59. */
  60. locateViewForObject: function(obj, area, elementsToSearch) {
  61. var view;
  62. if (obj.getView) {
  63. view = obj.getView();
  64. if (view) {
  65. return this.locateView(view, area, elementsToSearch);
  66. }
  67. }
  68. if (obj.viewUrl) {
  69. return this.locateView(obj.viewUrl, area, elementsToSearch);
  70. }
  71. var id = system.getModuleId(obj);
  72. if (id) {
  73. return this.locateView(this.convertModuleIdToViewId(id), area, elementsToSearch);
  74. }
  75. return this.locateView(this.determineFallbackViewId(obj), area, elementsToSearch);
  76. },
  77. /**
  78. * Converts a module id into a view id. By default the ids are the same.
  79. * @method convertModuleIdToViewId
  80. * @param {string} moduleId The module id.
  81. * @return {string} The view id.
  82. */
  83. convertModuleIdToViewId: function(moduleId) {
  84. return moduleId;
  85. },
  86. /**
  87. * 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.
  88. * @method determineFallbackViewId
  89. * @param {object} obj The object to determine the fallback id for.
  90. * @return {string} The view id.
  91. */
  92. determineFallbackViewId: function (obj) {
  93. var funcNameRegex = /function (.{1,})\(/;
  94. var results = (funcNameRegex).exec((obj).constructor.toString());
  95. var typeName = (results && results.length > 1) ? results[1] : "";
  96. typeName = typeName.trim();
  97. return 'views/' + typeName;
  98. },
  99. /**
  100. * Takes a view id and translates it into a particular area. By default, no translation occurs.
  101. * @method translateViewIdToArea
  102. * @param {string} viewId The view id.
  103. * @param {string} area The area to translate the view to.
  104. * @return {string} The translated view id.
  105. */
  106. translateViewIdToArea: function (viewId, area) {
  107. return viewId;
  108. },
  109. /**
  110. * Locates the specified view.
  111. * @method locateView
  112. * @param {string|DOMElement} viewOrUrlOrId A view, view url or view id to locate.
  113. * @param {string} [area] The area to translate the view to.
  114. * @param {DOMElement[]} [elementsToSearch] An existing set of elements to search first.
  115. * @return {Promise} A promise of the view.
  116. */
  117. locateView: function(viewOrUrlOrId, area, elementsToSearch) {
  118. if (typeof viewOrUrlOrId === 'string') {
  119. var viewId;
  120. if (viewEngine.isViewUrl(viewOrUrlOrId)) {
  121. viewId = viewEngine.convertViewUrlToViewId(viewOrUrlOrId);
  122. } else {
  123. viewId = viewOrUrlOrId;
  124. }
  125. if (area) {
  126. viewId = this.translateViewIdToArea(viewId, area);
  127. }
  128. if (elementsToSearch) {
  129. var existing = findInElements(elementsToSearch, viewId);
  130. if (existing) {
  131. return system.defer(function(dfd) {
  132. dfd.resolve(existing);
  133. }).promise();
  134. }
  135. }
  136. return viewEngine.createView(viewId);
  137. }
  138. return system.defer(function(dfd) {
  139. dfd.resolve(viewOrUrlOrId);
  140. }).promise();
  141. }
  142. };
  143. });