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