NodeList-data.js 6.5 KB

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