system.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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 system module encapsulates the most basic features used by other modules.
  8. * @module system
  9. * @requires require
  10. * @requires jquery
  11. */
  12. define(['require', 'jquery'], function(require, $) {
  13. var isDebugging = false,
  14. nativeKeys = Object.keys,
  15. hasOwnProperty = Object.prototype.hasOwnProperty,
  16. toString = Object.prototype.toString,
  17. system,
  18. treatAsIE8 = false,
  19. nativeIsArray = Array.isArray,
  20. slice = Array.prototype.slice;
  21. //polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
  22. if (!String.prototype.trim) {
  23. String.prototype.trim = function () {
  24. return this.replace(/^\s+|\s+$/g, '');
  25. };
  26. }
  27. //see http://patik.com/blog/complete-cross-browser-console-log/
  28. // Tell IE9 to use its built-in console
  29. if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log == 'object') {
  30. try {
  31. ['log', 'info', 'warn', 'error', 'assert', 'dir', 'clear', 'profile', 'profileEnd']
  32. .forEach(function(method) {
  33. console[method] = this.call(console[method], console);
  34. }, Function.prototype.bind);
  35. } catch (ex) {
  36. treatAsIE8 = true;
  37. }
  38. }
  39. // callback for dojo's loader
  40. // note: if you wish to use Durandal with dojo's AMD loader,
  41. // currently you must fork the dojo source with the following
  42. // dojo/dojo.js, line 1187, the last line of the finishExec() function:
  43. // (add) signal("moduleLoaded", [module.result, module.mid]);
  44. // an enhancement request has been submitted to dojo to make this
  45. // a permanent change. To view the status of this request, visit:
  46. // http://bugs.dojotoolkit.org/ticket/16727
  47. if (require.on) {
  48. require.on("moduleLoaded", function(module, mid) {
  49. system.setModuleId(module, mid);
  50. });
  51. }
  52. // callback for require.js loader
  53. if (typeof requirejs !== 'undefined') {
  54. requirejs.onResourceLoad = function(context, map, depArray) {
  55. system.setModuleId(context.defined[map.id], map.id);
  56. };
  57. }
  58. var noop = function() { };
  59. var log = function() {
  60. try {
  61. // Modern browsers
  62. if (typeof console != 'undefined' && typeof console.log == 'function') {
  63. // Opera 11
  64. if (window.opera) {
  65. var i = 0;
  66. while (i < arguments.length) {
  67. console.log('Item ' + (i + 1) + ': ' + arguments[i]);
  68. i++;
  69. }
  70. }
  71. // All other modern browsers
  72. else if ((slice.call(arguments)).length == 1 && typeof slice.call(arguments)[0] == 'string') {
  73. console.log((slice.call(arguments)).toString());
  74. } else {
  75. console.log.apply(console, slice.call(arguments));
  76. }
  77. }
  78. // IE8
  79. else if ((!Function.prototype.bind || treatAsIE8) && typeof console != 'undefined' && typeof console.log == 'object') {
  80. Function.prototype.call.call(console.log, console, slice.call(arguments));
  81. }
  82. // IE7 and lower, and other old browsers
  83. } catch (ignore) { }
  84. };
  85. var logError = function(error, err) {
  86. var exception;
  87. if(error instanceof Error){
  88. exception = error;
  89. } else {
  90. exception = new Error(error);
  91. }
  92. exception.innerError = err;
  93. //Report the error as an error, not as a log
  94. try {
  95. // Modern browsers (it's only a single item, no need for argument splitting as in log() above)
  96. if (typeof console != 'undefined' && typeof console.error == 'function') {
  97. console.error(exception);
  98. }
  99. // IE8
  100. else if ((!Function.prototype.bind || treatAsIE8) && typeof console != 'undefined' && typeof console.error == 'object') {
  101. Function.prototype.call.call(console.error, console, exception);
  102. }
  103. // IE7 and lower, and other old browsers
  104. } catch (ignore) { }
  105. throw exception;
  106. };
  107. /**
  108. * @class SystemModule
  109. * @static
  110. */
  111. system = {
  112. /**
  113. * Durandal's version.
  114. * @property {string} version
  115. */
  116. version: "2.1.0",
  117. /**
  118. * A noop function.
  119. * @method noop
  120. */
  121. noop: noop,
  122. /**
  123. * Gets the module id for the specified object.
  124. * @method getModuleId
  125. * @param {object} obj The object whose module id you wish to determine.
  126. * @return {string} The module id.
  127. */
  128. getModuleId: function(obj) {
  129. if (!obj) {
  130. return null;
  131. }
  132. if (typeof obj == 'function' && obj.prototype) {
  133. return obj.prototype.__moduleId__;
  134. }
  135. if (typeof obj == 'string') {
  136. return null;
  137. }
  138. return obj.__moduleId__;
  139. },
  140. /**
  141. * Sets the module id for the specified object.
  142. * @method setModuleId
  143. * @param {object} obj The object whose module id you wish to set.
  144. * @param {string} id The id to set for the specified object.
  145. */
  146. setModuleId: function(obj, id) {
  147. if (!obj) {
  148. return;
  149. }
  150. if (typeof obj == 'function' && obj.prototype) {
  151. obj.prototype.__moduleId__ = id;
  152. return;
  153. }
  154. if (typeof obj == 'string') {
  155. return;
  156. }
  157. obj.__moduleId__ = id;
  158. },
  159. /**
  160. * Resolves the default object instance for a module. If the module is an object, the module is returned. If the module is a function, that function is called with `new` and it's result is returned.
  161. * @method resolveObject
  162. * @param {object} module The module to use to get/create the default object for.
  163. * @return {object} The default object for the module.
  164. */
  165. resolveObject: function(module) {
  166. if (system.isFunction(module)) {
  167. return new module();
  168. } else {
  169. return module;
  170. }
  171. },
  172. /**
  173. * Gets/Sets whether or not Durandal is in debug mode.
  174. * @method debug
  175. * @param {boolean} [enable] Turns on/off debugging.
  176. * @return {boolean} Whether or not Durandal is current debugging.
  177. */
  178. debug: function(enable) {
  179. if (arguments.length == 1) {
  180. isDebugging = enable;
  181. if (isDebugging) {
  182. this.log = log;
  183. this.error = logError;
  184. this.log('Debug:Enabled');
  185. } else {
  186. this.log('Debug:Disabled');
  187. this.log = noop;
  188. this.error = noop;
  189. }
  190. }
  191. return isDebugging;
  192. },
  193. /**
  194. * Logs data to the console. Pass any number of parameters to be logged. Log output is not processed if the framework is not running in debug mode.
  195. * @method log
  196. * @param {object} info* The objects to log.
  197. */
  198. log: noop,
  199. /**
  200. * Logs an error.
  201. * @method error
  202. * @param {string|Error} obj The error to report.
  203. */
  204. error: noop,
  205. /**
  206. * Asserts a condition by throwing an error if the condition fails.
  207. * @method assert
  208. * @param {boolean} condition The condition to check.
  209. * @param {string} message The message to report in the error if the condition check fails.
  210. */
  211. assert: function (condition, message) {
  212. if (!condition) {
  213. system.error(new Error(message || 'Assert:Failed'));
  214. }
  215. },
  216. /**
  217. * Creates a deferred object which can be used to create a promise. Optionally pass a function action to perform which will be passed an object used in resolving the promise.
  218. * @method defer
  219. * @param {function} [action] The action to defer. You will be passed the deferred object as a paramter.
  220. * @return {Deferred} The deferred object.
  221. */
  222. defer: function(action) {
  223. return $.Deferred(action);
  224. },
  225. /**
  226. * Creates a simple V4 UUID. This should not be used as a PK in your database. It can be used to generate internal, unique ids. For a more robust solution see [node-uuid](https://github.com/broofa/node-uuid).
  227. * @method guid
  228. * @return {string} The guid.
  229. */
  230. guid: function() {
  231. var d = new Date().getTime();
  232. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  233. var r = (d + Math.random() * 16) % 16 | 0;
  234. d = Math.floor(d/16);
  235. return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
  236. });
  237. },
  238. /**
  239. * Uses require.js to obtain a module. This function returns a promise which resolves with the module instance. You can pass more than one module id to this function or an array of ids. If more than one or an array is passed, then the promise will resolve with an array of module instances.
  240. * @method acquire
  241. * @param {string|string[]} moduleId The id(s) of the modules to load.
  242. * @return {Promise} A promise for the loaded module(s).
  243. */
  244. acquire: function() {
  245. var modules,
  246. first = arguments[0],
  247. arrayRequest = false;
  248. if(system.isArray(first)){
  249. modules = first;
  250. arrayRequest = true;
  251. }else{
  252. modules = slice.call(arguments, 0);
  253. }
  254. return this.defer(function(dfd) {
  255. require(modules, function() {
  256. var args = arguments;
  257. setTimeout(function() {
  258. if(args.length > 1 || arrayRequest){
  259. dfd.resolve(slice.call(args, 0));
  260. }else{
  261. dfd.resolve(args[0]);
  262. }
  263. }, 1);
  264. }, function(err){
  265. dfd.reject(err);
  266. });
  267. }).promise();
  268. },
  269. /**
  270. * Extends the first object with the properties of the following objects.
  271. * @method extend
  272. * @param {object} obj The target object to extend.
  273. * @param {object} extension* Uses to extend the target object.
  274. */
  275. extend: function(obj) {
  276. var rest = slice.call(arguments, 1);
  277. for (var i = 0; i < rest.length; i++) {
  278. var source = rest[i];
  279. if (source) {
  280. for (var prop in source) {
  281. obj[prop] = source[prop];
  282. }
  283. }
  284. }
  285. return obj;
  286. },
  287. /**
  288. * Uses a setTimeout to wait the specified milliseconds.
  289. * @method wait
  290. * @param {number} milliseconds The number of milliseconds to wait.
  291. * @return {Promise}
  292. */
  293. wait: function(milliseconds) {
  294. return system.defer(function(dfd) {
  295. setTimeout(dfd.resolve, milliseconds);
  296. }).promise();
  297. }
  298. };
  299. /**
  300. * Gets all the owned keys of the specified object.
  301. * @method keys
  302. * @param {object} object The object whose owned keys should be returned.
  303. * @return {string[]} The keys.
  304. */
  305. system.keys = nativeKeys || function(obj) {
  306. if (obj !== Object(obj)) {
  307. throw new TypeError('Invalid object');
  308. }
  309. var keys = [];
  310. for (var key in obj) {
  311. if (hasOwnProperty.call(obj, key)) {
  312. keys[keys.length] = key;
  313. }
  314. }
  315. return keys;
  316. };
  317. /**
  318. * Determines if the specified object is an html element.
  319. * @method isElement
  320. * @param {object} object The object to check.
  321. * @return {boolean} True if matches the type, false otherwise.
  322. */
  323. system.isElement = function(obj) {
  324. return !!(obj && obj.nodeType === 1);
  325. };
  326. /**
  327. * Determines if the specified object is an array.
  328. * @method isArray
  329. * @param {object} object The object to check.
  330. * @return {boolean} True if matches the type, false otherwise.
  331. */
  332. system.isArray = nativeIsArray || function(obj) {
  333. return toString.call(obj) == '[object Array]';
  334. };
  335. /**
  336. * Determines if the specified object is...an object. ie. Not an array, string, etc.
  337. * @method isObject
  338. * @param {object} object The object to check.
  339. * @return {boolean} True if matches the type, false otherwise.
  340. */
  341. system.isObject = function(obj) {
  342. return obj === Object(obj);
  343. };
  344. /**
  345. * Determines if the specified object is a boolean.
  346. * @method isBoolean
  347. * @param {object} object The object to check.
  348. * @return {boolean} True if matches the type, false otherwise.
  349. */
  350. system.isBoolean = function(obj) {
  351. return typeof(obj) === "boolean";
  352. };
  353. /**
  354. * Determines if the specified object is a promise.
  355. * @method isPromise
  356. * @param {object} object The object to check.
  357. * @return {boolean} True if matches the type, false otherwise.
  358. */
  359. system.isPromise = function(obj) {
  360. return obj && system.isFunction(obj.then);
  361. };
  362. /**
  363. * Determines if the specified object is a function arguments object.
  364. * @method isArguments
  365. * @param {object} object The object to check.
  366. * @return {boolean} True if matches the type, false otherwise.
  367. */
  368. /**
  369. * Determines if the specified object is a function.
  370. * @method isFunction
  371. * @param {object} object The object to check.
  372. * @return {boolean} True if matches the type, false otherwise.
  373. */
  374. /**
  375. * Determines if the specified object is a string.
  376. * @method isString
  377. * @param {object} object The object to check.
  378. * @return {boolean} True if matches the type, false otherwise.
  379. */
  380. /**
  381. * Determines if the specified object is a number.
  382. * @method isNumber
  383. * @param {object} object The object to check.
  384. * @return {boolean} True if matches the type, false otherwise.
  385. */
  386. /**
  387. * Determines if the specified object is a date.
  388. * @method isDate
  389. * @param {object} object The object to check.
  390. * @return {boolean} True if matches the type, false otherwise.
  391. */
  392. /**
  393. * Determines if the specified object is a boolean.
  394. * @method isBoolean
  395. * @param {object} object The object to check.
  396. * @return {boolean} True if matches the type, false otherwise.
  397. */
  398. //isArguments, isFunction, isString, isNumber, isDate, isRegExp.
  399. var isChecks = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'];
  400. function makeIsFunction(name) {
  401. var value = '[object ' + name + ']';
  402. system['is' + name] = function(obj) {
  403. return toString.call(obj) == value;
  404. };
  405. }
  406. for (var i = 0; i < isChecks.length; i++) {
  407. makeIsFunction(isChecks[i]);
  408. }
  409. return system;
  410. });