lang.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. define("dojo/_base/lang", ["./kernel", "../has", "./sniff"], function(dojo, has){
  2. // module:
  3. // dojo/_base/lang
  4. // summary:
  5. // This module defines Javascript language extensions.
  6. has.add("bug-for-in-skips-shadowed", function(){
  7. // if true, the for-in interator skips object properties that exist in Object's prototype (IE 6 - ?)
  8. for(var i in {toString: 1}){
  9. return 0;
  10. }
  11. return 1;
  12. });
  13. var _extraNames =
  14. has("bug-for-in-skips-shadowed") ?
  15. "hasOwnProperty.valueOf.isPrototypeOf.propertyIsEnumerable.toLocaleString.toString.constructor".split(".") : [],
  16. _extraLen = _extraNames.length,
  17. _mixin = function(dest, source, copyFunc){
  18. var name, s, i, empty = {};
  19. for(name in source){
  20. // the (!(name in empty) || empty[name] !== s) condition avoids copying properties in "source"
  21. // inherited from Object.prototype. For example, if dest has a custom toString() method,
  22. // don't overwrite it with the toString() method that source inherited from Object.prototype
  23. s = source[name];
  24. if(!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))){
  25. dest[name] = copyFunc ? copyFunc(s) : s;
  26. }
  27. }
  28. if(has("bug-for-in-skips-shadowed")){
  29. if(source){
  30. for(i = 0; i < _extraLen; ++i){
  31. name = _extraNames[i];
  32. s = source[name];
  33. if(!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))){
  34. dest[name] = copyFunc ? copyFunc(s) : s;
  35. }
  36. }
  37. }
  38. }
  39. return dest; // Object
  40. },
  41. mixin = function(dest, sources){
  42. if(!dest){ dest = {}; }
  43. for(var i = 1, l = arguments.length; i < l; i++){
  44. lang._mixin(dest, arguments[i]);
  45. }
  46. return dest; // Object
  47. },
  48. getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
  49. if(!context){
  50. if(parts[0] && dojo.scopeMap[parts[0]]) {
  51. // Voodoo code from the old days where "dojo" or "dijit" maps to some special object
  52. // rather than just window.dojo
  53. context = dojo.scopeMap[parts.shift()][1];
  54. }else{
  55. context = dojo.global;
  56. }
  57. }
  58. try{
  59. for(var i = 0; i < parts.length; i++){
  60. var p = parts[i];
  61. // Fix for prototype pollution CVE-2021-23450
  62. if (p === '__proto__' || p === 'constructor') {
  63. return;
  64. }
  65. if(!(p in context)){
  66. if(create){
  67. context[p] = {};
  68. }else{
  69. return; // return undefined
  70. }
  71. }
  72. context = context[p];
  73. }
  74. return context; // mixed
  75. }catch(e){
  76. // "p in context" throws an exception when context is a number, boolean, etc. rather than an object,
  77. // so in that corner case just return undefined (by having no return statement)
  78. }
  79. },
  80. setObject = function(name, value, context){
  81. var parts = name.split("."), p = parts.pop(), obj = getProp(parts, true, context);
  82. return obj && p ? (obj[p] = value) : undefined; // Object
  83. },
  84. getObject = function(name, create, context){
  85. return !name ? context : getProp(name.split("."), create, context); // Object
  86. },
  87. exists = function(name, obj){
  88. return lang.getObject(name, false, obj) !== undefined; // Boolean
  89. },
  90. opts = Object.prototype.toString,
  91. // Crockford (ish) functions
  92. isString = function(it){
  93. return (typeof it == "string" || it instanceof String); // Boolean
  94. },
  95. isArray = function(it){
  96. return it && (it instanceof Array || typeof it == "array"); // Boolean
  97. },
  98. isFunction = function(it){
  99. return opts.call(it) === "[object Function]";
  100. },
  101. isObject = function(it){
  102. return it !== undefined &&
  103. (it === null || typeof it == "object" || lang.isArray(it) || lang.isFunction(it)); // Boolean
  104. },
  105. isArrayLike = function(it){
  106. return it && it !== undefined && // Boolean
  107. // keep out built-in constructors (Number, String, ...) which have length
  108. // properties
  109. !lang.isString(it) && !lang.isFunction(it) &&
  110. !(it.tagName && it.tagName.toLowerCase() == 'form') &&
  111. (lang.isArray(it) || isFinite(it.length));
  112. },
  113. isAlien = function(it){
  114. return it && !lang.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
  115. },
  116. extend = function(constructor, props){
  117. for(var i=1, l=arguments.length; i<l; i++){
  118. lang._mixin(constructor.prototype, arguments[i]);
  119. }
  120. return constructor; // Object
  121. },
  122. _hitchArgs = function(scope, method){
  123. var pre = _toArray(arguments, 2);
  124. var named = lang.isString(method);
  125. return function(){
  126. // arrayify arguments
  127. var args = _toArray(arguments);
  128. // locate our method
  129. var f = named ? (scope||dojo.global)[method] : method;
  130. // invoke with collected args
  131. return f && f.apply(scope || this, pre.concat(args)); // mixed
  132. }; // Function
  133. },
  134. hitch = function(scope, method){
  135. if(arguments.length > 2){
  136. return lang._hitchArgs.apply(dojo, arguments); // Function
  137. }
  138. if(!method){
  139. method = scope;
  140. scope = null;
  141. }
  142. if(lang.isString(method)){
  143. scope = scope || dojo.global;
  144. if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
  145. return function(){ return scope[method].apply(scope, arguments || []); }; // Function
  146. }
  147. return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
  148. },
  149. delegate = (function(){
  150. // boodman/crockford delegation w/ cornford optimization
  151. function TMP(){}
  152. return function(obj, props){
  153. TMP.prototype = obj;
  154. var tmp = new TMP();
  155. TMP.prototype = null;
  156. if(props){
  157. lang._mixin(tmp, props);
  158. }
  159. return tmp; // Object
  160. };
  161. })(),
  162. efficient = function(obj, offset, startWith){
  163. return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
  164. },
  165. _toArray =
  166. has("ie") ?
  167. (function(){
  168. function slow(obj, offset, startWith){
  169. var arr = startWith||[];
  170. for(var x = offset || 0; x < obj.length; x++){
  171. arr.push(obj[x]);
  172. }
  173. return arr;
  174. }
  175. return function(obj){
  176. return ((obj.item) ? slow : efficient).apply(this, arguments);
  177. };
  178. })() : efficient,
  179. partial = function(/*Function|String*/method /*, ...*/){
  180. var arr = [ null ];
  181. return lang.hitch.apply(dojo, arr.concat(lang._toArray(arguments))); // Function
  182. },
  183. clone = function(/*anything*/ src){
  184. if(!src || typeof src != "object" || lang.isFunction(src)){
  185. // null, undefined, any non-object, or function
  186. return src; // anything
  187. }
  188. if(src.nodeType && "cloneNode" in src){
  189. // DOM Node
  190. return src.cloneNode(true); // Node
  191. }
  192. if(src instanceof Date){
  193. // Date
  194. return new Date(src.getTime()); // Date
  195. }
  196. if(src instanceof RegExp){
  197. // RegExp
  198. return new RegExp(src); // RegExp
  199. }
  200. var r, i, l;
  201. if(lang.isArray(src)){
  202. // array
  203. r = [];
  204. for(i = 0, l = src.length; i < l; ++i){
  205. if(i in src){
  206. r.push(clone(src[i]));
  207. }
  208. }
  209. // we don't clone functions for performance reasons
  210. // }else if(d.isFunction(src)){
  211. // // function
  212. // r = function(){ return src.apply(this, arguments); };
  213. }else{
  214. // generic objects
  215. r = src.constructor ? new src.constructor() : {};
  216. }
  217. return lang._mixin(r, src, clone);
  218. },
  219. trim = String.prototype.trim ?
  220. function(str){ return str.trim(); } :
  221. function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); },
  222. _pattern = /\{([^\}]+)\}/g,
  223. replace = function(tmpl, map, pattern){
  224. return tmpl.replace(pattern || _pattern, lang.isFunction(map) ?
  225. map : function(_, k){ return getObject(k, false, map); });
  226. },
  227. lang = {
  228. _extraNames:_extraNames,
  229. _mixin:_mixin,
  230. mixin:mixin,
  231. setObject:setObject,
  232. getObject:getObject,
  233. exists:exists,
  234. isString:isString,
  235. isArray:isArray,
  236. isFunction:isFunction,
  237. isObject:isObject,
  238. isArrayLike:isArrayLike,
  239. isAlien:isAlien,
  240. extend:extend,
  241. _hitchArgs:_hitchArgs,
  242. hitch:hitch,
  243. delegate:delegate,
  244. _toArray:_toArray,
  245. partial:partial,
  246. clone:clone,
  247. trim:trim,
  248. replace:replace
  249. };
  250. 1 && mixin(dojo, lang);
  251. return lang;
  252. /*=====
  253. dojo._extraNames
  254. // summary:
  255. // Array of strings. Lists property names that must be explicitly processed during for-in interation
  256. // in environments that have has("bug-for-in-skips-shadowed") true.
  257. =====*/
  258. /*=====
  259. dojo._mixin = function(dest, source, copyFunc){
  260. // summary:
  261. // Copies/adds all properties of source to dest; returns dest.
  262. // dest: Object:
  263. // The object to which to copy/add all properties contained in source.
  264. // source: Object:
  265. // The object from which to draw all properties to copy into dest.
  266. // copyFunc: Function?:
  267. // The process used to copy/add a property in source; defaults to the Javascript assignment operator.
  268. // returns:
  269. // dest, as modified
  270. // description:
  271. // All properties, including functions (sometimes termed "methods"), excluding any non-standard extensions
  272. // found in Object.prototype, are copied/added to dest. Copying/adding each particular property is
  273. // delegated to copyFunc (if any); copyFunc defaults to the Javascript assignment operator if not provided.
  274. // Notice that by default, _mixin executes a so-called "shallow copy" and aggregate types are copied/added by reference.
  275. }
  276. =====*/
  277. /*=====
  278. dojo.mixin = function(dest, sources){
  279. // summary:
  280. // Copies/adds all properties of one or more sources to dest; returns dest.
  281. // dest: Object
  282. // The object to which to copy/add all properties contained in source. If dest is falsy, then
  283. // a new object is manufactured before copying/adding properties begins.
  284. // sources: Object...
  285. // One of more objects from which to draw all properties to copy into dest. sources are processed
  286. // left-to-right and if more than one of these objects contain the same property name, the right-most
  287. // value "wins".
  288. // returns: Object
  289. // dest, as modified
  290. // description:
  291. // All properties, including functions (sometimes termed "methods"), excluding any non-standard extensions
  292. // found in Object.prototype, are copied/added from sources to dest. sources are processed left to right.
  293. // The Javascript assignment operator is used to copy/add each property; therefore, by default, mixin
  294. // executes a so-called "shallow copy" and aggregate types are copied/added by reference.
  295. // example:
  296. // make a shallow copy of an object
  297. // | var copy = lang.mixin({}, source);
  298. // example:
  299. // many class constructors often take an object which specifies
  300. // values to be configured on the object. In this case, it is
  301. // often simplest to call `lang.mixin` on the `this` object:
  302. // | dojo.declare("acme.Base", null, {
  303. // | constructor: function(properties){
  304. // | // property configuration:
  305. // | lang.mixin(this, properties);
  306. // |
  307. // | console.log(this.quip);
  308. // | // ...
  309. // | },
  310. // | quip: "I wasn't born yesterday, you know - I've seen movies.",
  311. // | // ...
  312. // | });
  313. // |
  314. // | // create an instance of the class and configure it
  315. // | var b = new acme.Base({quip: "That's what it does!" });
  316. // example:
  317. // copy in properties from multiple objects
  318. // | var flattened = lang.mixin(
  319. // | {
  320. // | name: "Frylock",
  321. // | braces: true
  322. // | },
  323. // | {
  324. // | name: "Carl Brutanananadilewski"
  325. // | }
  326. // | );
  327. // |
  328. // | // will print "Carl Brutanananadilewski"
  329. // | console.log(flattened.name);
  330. // | // will print "true"
  331. // | console.log(flattened.braces);
  332. }
  333. =====*/
  334. /*=====
  335. dojo.setObject = function(name, value, context){
  336. // summary:
  337. // Set a property from a dot-separated string, such as "A.B.C"
  338. // description:
  339. // Useful for longer api chains where you have to test each object in
  340. // the chain, or when you have an object reference in string format.
  341. // Objects are created as needed along `path`. Returns the passed
  342. // value if setting is successful or `undefined` if not.
  343. // name: String
  344. // Path to a property, in the form "A.B.C".
  345. // value: anything
  346. // value or object to place at location given by name
  347. // context: Object?
  348. // Optional. Object to use as root of path. Defaults to
  349. // `dojo.global`.
  350. // example:
  351. // set the value of `foo.bar.baz`, regardless of whether
  352. // intermediate objects already exist:
  353. // | lang.setObject("foo.bar.baz", value);
  354. // example:
  355. // without `lang.setObject`, we often see code like this:
  356. // | // ensure that intermediate objects are available
  357. // | if(!obj["parent"]){ obj.parent = {}; }
  358. // | if(!obj.parent["child"]){ obj.parent.child = {}; }
  359. // | // now we can safely set the property
  360. // | obj.parent.child.prop = "some value";
  361. // whereas with `lang.setObject`, we can shorten that to:
  362. // | lang.setObject("parent.child.prop", "some value", obj);
  363. }
  364. =====*/
  365. /*=====
  366. dojo.getObject = function(name, create, context){
  367. // summary:
  368. // Get a property from a dot-separated string, such as "A.B.C"
  369. // description:
  370. // Useful for longer api chains where you have to test each object in
  371. // the chain, or when you have an object reference in string format.
  372. // name: String
  373. // Path to an property, in the form "A.B.C".
  374. // create: Boolean?
  375. // Optional. Defaults to `false`. If `true`, Objects will be
  376. // created at any point along the 'path' that is undefined.
  377. // context: Object?
  378. // Optional. Object to use as root of path. Defaults to
  379. // 'dojo.global'. Null may be passed.
  380. }
  381. =====*/
  382. /*=====
  383. dojo.exists = function(name, obj){
  384. // summary:
  385. // determine if an object supports a given method
  386. // description:
  387. // useful for longer api chains where you have to test each object in
  388. // the chain. Useful for object and method detection.
  389. // name: String
  390. // Path to an object, in the form "A.B.C".
  391. // obj: Object?
  392. // Object to use as root of path. Defaults to
  393. // 'dojo.global'. Null may be passed.
  394. // example:
  395. // | // define an object
  396. // | var foo = {
  397. // | bar: { }
  398. // | };
  399. // |
  400. // | // search the global scope
  401. // | lang.exists("foo.bar"); // true
  402. // | lang.exists("foo.bar.baz"); // false
  403. // |
  404. // | // search from a particular scope
  405. // | lang.exists("bar", foo); // true
  406. // | lang.exists("bar.baz", foo); // false
  407. }
  408. =====*/
  409. /*=====
  410. dojo.isString = function(it){
  411. // summary:
  412. // Return true if it is a String
  413. // it: anything
  414. // Item to test.
  415. }
  416. =====*/
  417. /*=====
  418. dojo.isArray = function(it){
  419. // summary:
  420. // Return true if it is an Array.
  421. // Does not work on Arrays created in other windows.
  422. // it: anything
  423. // Item to test.
  424. }
  425. =====*/
  426. /*=====
  427. dojo.isFunction = function(it){
  428. // summary:
  429. // Return true if it is a Function
  430. // it: anything
  431. // Item to test.
  432. }
  433. =====*/
  434. /*=====
  435. dojo.isObject = function(it){
  436. // summary:
  437. // Returns true if it is a JavaScript object (or an Array, a Function
  438. // or null)
  439. // it: anything
  440. // Item to test.
  441. }
  442. =====*/
  443. /*=====
  444. dojo.isArrayLike = function(it){
  445. // summary:
  446. // similar to dojo.isArray() but more permissive
  447. // it: anything
  448. // Item to test.
  449. // returns:
  450. // If it walks like a duck and quacks like a duck, return `true`
  451. // description:
  452. // Doesn't strongly test for "arrayness". Instead, settles for "isn't
  453. // a string or number and has a length property". Arguments objects
  454. // and DOM collections will return true when passed to
  455. // dojo.isArrayLike(), but will return false when passed to
  456. // dojo.isArray().
  457. }
  458. =====*/
  459. /*=====
  460. dojo.isAlien = function(it){
  461. // summary:
  462. // Returns true if it is a built-in function or some other kind of
  463. // oddball that *should* report as a function but doesn't
  464. }
  465. =====*/
  466. /*=====
  467. dojo.extend = function(constructor, props){
  468. // summary:
  469. // Adds all properties and methods of props to constructor's
  470. // prototype, making them available to all instances created with
  471. // constructor.
  472. // constructor: Object
  473. // Target constructor to extend.
  474. // props: Object...
  475. // One or more objects to mix into constructor.prototype
  476. }
  477. =====*/
  478. /*=====
  479. dojo.hitch = function(scope, method){
  480. // summary:
  481. // Returns a function that will only ever execute in the a given scope.
  482. // This allows for easy use of object member functions
  483. // in callbacks and other places in which the "this" keyword may
  484. // otherwise not reference the expected scope.
  485. // Any number of default positional arguments may be passed as parameters
  486. // beyond "method".
  487. // Each of these values will be used to "placehold" (similar to curry)
  488. // for the hitched function.
  489. // scope: Object
  490. // The scope to use when method executes. If method is a string,
  491. // scope is also the object containing method.
  492. // method: Function|String...
  493. // A function to be hitched to scope, or the name of the method in
  494. // scope to be hitched.
  495. // example:
  496. // | dojo.hitch(foo, "bar")();
  497. // runs foo.bar() in the scope of foo
  498. // example:
  499. // | dojo.hitch(foo, myFunction);
  500. // returns a function that runs myFunction in the scope of foo
  501. // example:
  502. // Expansion on the default positional arguments passed along from
  503. // hitch. Passed args are mixed first, additional args after.
  504. // | var foo = { bar: function(a, b, c){ console.log(a, b, c); } };
  505. // | var fn = dojo.hitch(foo, "bar", 1, 2);
  506. // | fn(3); // logs "1, 2, 3"
  507. // example:
  508. // | var foo = { bar: 2 };
  509. // | dojo.hitch(foo, function(){ this.bar = 10; })();
  510. // execute an anonymous function in scope of foo
  511. }
  512. =====*/
  513. /*=====
  514. dojo.delegate = function(obj, props){
  515. // summary:
  516. // Returns a new object which "looks" to obj for properties which it
  517. // does not have a value for. Optionally takes a bag of properties to
  518. // seed the returned object with initially.
  519. // description:
  520. // This is a small implementaton of the Boodman/Crockford delegation
  521. // pattern in JavaScript. An intermediate object constructor mediates
  522. // the prototype chain for the returned object, using it to delegate
  523. // down to obj for property lookup when object-local lookup fails.
  524. // This can be thought of similarly to ES4's "wrap", save that it does
  525. // not act on types but rather on pure objects.
  526. // obj: Object
  527. // The object to delegate to for properties not found directly on the
  528. // return object or in props.
  529. // props: Object...
  530. // an object containing properties to assign to the returned object
  531. // returns:
  532. // an Object of anonymous type
  533. // example:
  534. // | var foo = { bar: "baz" };
  535. // | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
  536. // | thinger.bar == "baz"; // delegated to foo
  537. // | foo.thud == undefined; // by definition
  538. // | thinger.thud == "xyzzy"; // mixed in from props
  539. // | foo.bar = "thonk";
  540. // | thinger.bar == "thonk"; // still delegated to foo's bar
  541. }
  542. =====*/
  543. /*=====
  544. dojo.partial = function(method){
  545. // summary:
  546. // similar to hitch() except that the scope object is left to be
  547. // whatever the execution context eventually becomes.
  548. // method: Function|String
  549. // description:
  550. // Calling dojo.partial is the functional equivalent of calling:
  551. // | dojo.hitch(null, funcName, ...);
  552. }
  553. =====*/
  554. /*=====
  555. dojo.trim = function(str){
  556. // summary:
  557. // Trims whitespace from both sides of the string
  558. // str: String
  559. // String to be trimmed
  560. // returns: String
  561. // Returns the trimmed string
  562. // description:
  563. // This version of trim() was selected for inclusion into the base due
  564. // to its compact size and relatively good performance
  565. // (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript)
  566. // Uses String.prototype.trim instead, if available.
  567. // The fastest but longest version of this function is located at
  568. // dojo.string.trim()
  569. }
  570. =====*/
  571. /*=====
  572. dojo.clone = function(src){
  573. // summary:
  574. // Clones objects (including DOM nodes) and all children.
  575. // Warning: do not clone cyclic structures.
  576. // src:
  577. // The object to clone
  578. }
  579. =====*/
  580. /*=====
  581. dojo._toArray = function(obj, offset, startWith){
  582. // summary:
  583. // Converts an array-like object (i.e. arguments, DOMCollection) to an
  584. // array. Returns a new Array with the elements of obj.
  585. // obj: Object
  586. // the object to "arrayify". We expect the object to have, at a
  587. // minimum, a length property which corresponds to integer-indexed
  588. // properties.
  589. // offset: Number?
  590. // the location in obj to start iterating from. Defaults to 0.
  591. // Optional.
  592. // startWith: Array?
  593. // An array to pack with the properties of obj. If provided,
  594. // properties in obj are appended at the end of startWith and
  595. // startWith is the returned array.
  596. }
  597. =====*/
  598. /*=====
  599. dojo.replace = function(tmpl, map, pattern){
  600. // summary:
  601. // Performs parameterized substitutions on a string. Throws an
  602. // exception if any parameter is unmatched.
  603. // tmpl: String
  604. // String to be used as a template.
  605. // map: Object|Function
  606. // If an object, it is used as a dictionary to look up substitutions.
  607. // If a function, it is called for every substitution with following
  608. // parameters: a whole match, a name, an offset, and the whole template
  609. // string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace
  610. // for more details).
  611. // pattern: RegEx?
  612. // Optional regular expression objects that overrides the default pattern.
  613. // Must be global and match one item. The default is: /\{([^\}]+)\}/g,
  614. // which matches patterns like that: "{xxx}", where "xxx" is any sequence
  615. // of characters, which doesn't include "}".
  616. // returns: String
  617. // Returns the substituted string.
  618. // example:
  619. // | // uses a dictionary for substitutions:
  620. // | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!",
  621. // | {
  622. // | nick: "Bob",
  623. // | name: {
  624. // | first: "Robert",
  625. // | middle: "X",
  626. // | last: "Cringely"
  627. // | }
  628. // | });
  629. // | // returns: Hello, Robert Cringely AKA Bob!
  630. // example:
  631. // | // uses an array for substitutions:
  632. // | dojo.replace("Hello, {0} {2}!",
  633. // | ["Robert", "X", "Cringely"]);
  634. // | // returns: Hello, Robert Cringely!
  635. // example:
  636. // | // uses a function for substitutions:
  637. // | function sum(a){
  638. // | var t = 0;
  639. // | dojo.forEach(a, function(x){ t += x; });
  640. // | return t;
  641. // | }
  642. // | dojo.replace(
  643. // | "{count} payments averaging {avg} USD per payment.",
  644. // | dojo.hitch(
  645. // | { payments: [11, 16, 12] },
  646. // | function(_, key){
  647. // | switch(key){
  648. // | case "count": return this.payments.length;
  649. // | case "min": return Math.min.apply(Math, this.payments);
  650. // | case "max": return Math.max.apply(Math, this.payments);
  651. // | case "sum": return sum(this.payments);
  652. // | case "avg": return sum(this.payments) / this.payments.length;
  653. // | }
  654. // | }
  655. // | )
  656. // | );
  657. // | // prints: 3 payments averaging 13 USD per payment.
  658. // example:
  659. // | // uses an alternative PHP-like pattern for substitutions:
  660. // | dojo.replace("Hello, ${0} ${2}!",
  661. // | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g);
  662. // | // returns: Hello, Robert Cringely!
  663. return ""; // String
  664. }
  665. =====*/
  666. });