NodeList-data.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojo.NodeList-data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojo.NodeList-data"] = true;
  8. dojo.provide("dojo.NodeList-data");
  9. (function(d){
  10. /*=====
  11. dojo.NodeList.prototype.data = function(key, value){
  12. // summary: stash or get some arbitrary data on/from these nodes.
  13. //
  14. // description:
  15. // Stash or get some arbirtrary data on/from these nodes. This private _data function is
  16. // exposed publicly on `dojo.NodeList`, eg: as the result of a `dojo.query` call.
  17. // DIFFERS from jQuery.data in that when used as a getter, the entire list is ALWAYS
  18. // returned. EVEN WHEN THE LIST IS length == 1.
  19. //
  20. // A single-node version of this function is provided as `dojo._nodeData`, which follows
  21. // the same signature, though expects a String ID or DomNode reference in the first
  22. // position, before key/value arguments.
  23. //
  24. // node: String|DomNode
  25. // The node to associate data with
  26. //
  27. // key: Object?|String?
  28. // If an object, act as a setter and iterate over said object setting data items as defined.
  29. // If a string, and `value` present, set the data for defined `key` to `value`
  30. // If a string, and `value` absent, act as a getter, returning the data associated with said `key`
  31. //
  32. // value: Anything?
  33. // The value to set for said `key`, provided `key` is a string (and not an object)
  34. //
  35. // example:
  36. // Set a key `bar` to some data, then retrieve it.
  37. // | dojo.query(".foo").data("bar", "touched");
  38. // | var touched = dojo.query(".foo").data("bar");
  39. // | if(touched[0] == "touched"){ alert('win'); }
  40. //
  41. // example:
  42. // Get all the data items for a given node.
  43. // | var list = dojo.query(".foo").data();
  44. // | var first = list[0];
  45. //
  46. // example:
  47. // Set the data to a complex hash. Overwrites existing keys with new value
  48. // | dojo.query(".foo").data({ bar:"baz", foo:"bar" });
  49. // Then get some random key:
  50. // | dojo.query(".foo").data("foo"); // returns [`bar`]
  51. //
  52. // returns: Object|Anything|Nothing
  53. // When used as a setter via `dojo.NodeList`, a NodeList instance is returned
  54. // for further chaning. When used as a getter via `dojo.NodeList` an ARRAY
  55. // of items is returned. The items in the array correspond to the elements
  56. // in the original list. This is true even when the list length is 1, eg:
  57. // when looking up a node by ID (#foo)
  58. };
  59. dojo.NodeList.prototype.removeData = function(key){
  60. // summary: Remove the data associated with these nodes.
  61. // key: String?
  62. // If ommitted, clean all data for this node.
  63. // If passed, remove the data item found at `key`
  64. };
  65. dojo._nodeDataCache = {
  66. // summary: An alias to the private dataCache for NodeList-data. NEVER USE THIS!
  67. // This private is only exposed for the benefit of unit testing, and is
  68. // removed during the build process.
  69. };
  70. =====*/
  71. var dataCache = {}, x = 0, dataattr = "data-dojo-dataid", nl = d.NodeList,
  72. dopid = function(node){
  73. // summary: Return a uniqueish ID for the passed node reference
  74. var pid = d.attr(node, dataattr);
  75. if(!pid){
  76. pid = "pid" + (x++);
  77. d.attr(node, dataattr, pid);
  78. }
  79. return pid;
  80. }
  81. ;
  82. var dodata = d._nodeData = function(node, key, value){
  83. var pid = dopid(node), r;
  84. if(!dataCache[pid]){ dataCache[pid] = {}; }
  85. // API discrepency: calling with only a node returns the whole object. $.data throws
  86. if(arguments.length == 1){ r = dataCache[pid]; }
  87. if(typeof key == "string"){
  88. // either getter or setter, based on `value` presence
  89. if(arguments.length > 2){
  90. dataCache[pid][key] = value;
  91. }else{
  92. r = dataCache[pid][key];
  93. }
  94. }else{
  95. // must be a setter, mix `value` into data hash
  96. // API discrepency: using object as setter works here
  97. r = d._mixin(dataCache[pid], key);
  98. }
  99. return r; // Object|Anything|Nothing
  100. };
  101. var removeData = d._removeNodeData = function(node, key){
  102. // summary: Remove some data from this node
  103. // node: String|DomNode
  104. // The node reference to remove data from
  105. // key: String?
  106. // If omitted, remove all data in this dataset.
  107. // If passed, remove only the passed `key` in the associated dataset
  108. var pid = dopid(node);
  109. if(dataCache[pid]){
  110. if(key){
  111. delete dataCache[pid][key];
  112. }else{
  113. delete dataCache[pid];
  114. }
  115. }
  116. };
  117. d._gcNodeData = function(){
  118. // summary: super expensive: GC all data in the data for nodes that no longer exist in the dom.
  119. // description:
  120. // super expensive: GC all data in the data for nodes that no longer exist in the dom.
  121. // MUCH safer to do this yourself, manually, on a per-node basis (via `NodeList.removeData()`)
  122. // provided as a stop-gap for exceptionally large/complex applications with constantly changing
  123. // content regions (eg: a dijit.layout.ContentPane with replacing data)
  124. // There is NO automatic GC going on. If you dojo.destroy() a node, you should _removeNodeData
  125. // prior to destruction.
  126. var livePids = dojo.query("[" + dataattr + "]").map(dopid);
  127. for(var i in dataCache){
  128. if(dojo.indexOf(livePids, i) < 0){ delete dataCache[i]; }
  129. }
  130. };
  131. // make nodeData and removeNodeData public on dojo.NodeList:
  132. d.extend(nl, {
  133. data: nl._adaptWithCondition(dodata, function(a){
  134. return a.length === 0 || a.length == 1 && (typeof a[0] == "string");
  135. }),
  136. removeData: nl._adaptAsForEach(removeData)
  137. });
  138. // TODO: this is the basic implemetation of adaptWithCondtionAndWhenMappedConsiderLength, for lack of a better API name
  139. // it conflicts with the the `dojo.NodeList` way: always always return an arrayLike thinger. Consider for 2.0:
  140. //
  141. // nl.prototype.data = function(key, value){
  142. // var a = arguments, r;
  143. // if(a.length === 0 || a.length == 1 && (typeof a[0] == "string")){
  144. // r = this.map(function(node){
  145. // return d._data(node, key);
  146. // });
  147. // if(r.length == 1){ r = r[0]; } // the offending line, and the diff on adaptWithCondition
  148. // }else{
  149. // r = this.forEach(function(node){
  150. // d._data(node, key, value);
  151. // });
  152. // }
  153. // return r; // dojo.NodeList|Array|SingleItem
  154. // };
  155. })(dojo);
  156. }