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