UNPKG

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