summaryrefslogtreecommitdiff
path: root/lib/dojo/NodeList-data.js.uncompressed.js
blob: b8c76b0b033f12a283c2aef8e0b4056d80a83d2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
define("dojo/NodeList-data", [
	"./_base/kernel", "./query", "./_base/lang", "./_base/array", "./dom-attr"
], function(dojo, query, lang, array, attr) {
	// module:
	//		dojo/NodeList-data
	// summary:
	//		TODOC

var NodeList = query.NodeList;
/*=====
// doc alias helpers:
var NodeList = dojo.NodeList;

	dojo.NodeList.prototype.data = function(key, value){
		// summary: stash or get some arbitrary data on/from these nodes.
		//
		// description:
		//		Stash or get some arbirtrary data on/from these nodes. This private _data function is
		//		exposed publicly on `dojo.NodeList`, eg: as the result of a `dojo.query` call.
		//		DIFFERS from jQuery.data in that when used as a getter, the entire list is ALWAYS
		//		returned. EVEN WHEN THE LIST IS length == 1.
		//
		//		A single-node version of this function is provided as `dojo._nodeData`, which follows
		//		the same signature, though expects a String ID or DomNode reference in the first
		//		position, before key/value arguments.
		//
		// node: String|DomNode
		//		The node to associate data with
		//
		// key: Object?|String?
		//		If an object, act as a setter and iterate over said object setting data items as defined.
		//		If a string, and `value` present, set the data for defined `key` to `value`
		//		If a string, and `value` absent, act as a getter, returning the data associated with said `key`
		//
		// value: Anything?
		//		The value to set for said `key`, provided `key` is a string (and not an object)
		//
		// example:
		//		Set a key `bar` to some data, then retrieve it.
		//	|	dojo.query(".foo").data("bar", "touched");
		//	|	var touched = dojo.query(".foo").data("bar");
		//	|	if(touched[0] == "touched"){ alert('win'); }
		//
		// example:
		//		Get all the data items for a given node.
		//	|	var list = dojo.query(".foo").data();
		//	|	var first = list[0];
		//
		// example:
		//		Set the data to a complex hash. Overwrites existing keys with new value
		//	|	dojo.query(".foo").data({ bar:"baz", foo:"bar" });
		//		Then get some random key:
		//	|	dojo.query(".foo").data("foo"); // returns [`bar`]
		//
		//	returns: Object|Anything|Nothing
		//		When used as a setter via `dojo.NodeList`, a NodeList instance is returned
		//		for further chaning. When used as a getter via `dojo.NodeList` an ARRAY
		//		of items is returned. The items in the array correspond to the elements
		//		in the original list. This is true even when the list length is 1, eg:
		//		when looking up a node by ID (#foo)
	};

	dojo.NodeList.prototype.removeData = function(key){
		// summary: Remove the data associated with these nodes.
		// key: String?
		//		If ommitted, clean all data for this node.
		//		If passed, remove the data item found at `key`
	};

=====*/

	var dataCache = {}, x = 0, dataattr = "data-dojo-dataid",
		dopid = function(node){
			// summary: Return a uniqueish ID for the passed node reference
			var pid = attr.get(node, dataattr);
			if(!pid){
				pid = "pid" + (x++);
				attr.set(node, dataattr, pid);
			}
			return pid;
		}
	;

	
	var dodata = dojo._nodeData = function(node, key, value){
		// summary: Private helper for dojo.NodeList.data for single node data access. Refer to NodeList.data 
		//		documentation for more information.
		//
		// node: String|DomNode
		//		The node to associate data with
		//
		// key: Object?|String?
		//		If an object, act as a setter and iterate over said object setting data items as defined.
		//		If a string, and `value` present, set the data for defined `key` to `value`
		//		If a string, and `value` absent, act as a getter, returning the data associated with said `key`
		//
		// value: Anything?
		//		The value to set for said `key`, provided `key` is a string (and not an object)
		//
		var pid = dopid(node), r;
		if(!dataCache[pid]){ dataCache[pid] = {}; }

		// API discrepency: calling with only a node returns the whole object. $.data throws
		if(arguments.length == 1){ r = dataCache[pid]; }
		if(typeof key == "string"){
			// either getter or setter, based on `value` presence
			if(arguments.length > 2){
				dataCache[pid][key] = value;
			}else{
				r = dataCache[pid][key];
			}
		}else{
			// must be a setter, mix `value` into data hash
			// API discrepency: using object as setter works here
			r = lang.mixin(dataCache[pid], key);
		}

		return r; // Object|Anything|Nothing
	};

	var removeData = dojo._removeNodeData = function(node, key){
		// summary: Remove some data from this node
		// node: String|DomNode
		//		The node reference to remove data from
		// key: String?
		//		If omitted, remove all data in this dataset.
		//		If passed, remove only the passed `key` in the associated dataset
		var pid = dopid(node);
		if(dataCache[pid]){
			if(key){
				delete dataCache[pid][key];
			}else{
				delete dataCache[pid];
			}
		}
	};

	dojo._gcNodeData = function(){
		// summary: super expensive: GC all data in the data for nodes that no longer exist in the dom.
		// description:
		//		super expensive: GC all data in the data for nodes that no longer exist in the dom.
		//		MUCH safer to do this yourself, manually, on a per-node basis (via `NodeList.removeData()`)
		//		provided as a stop-gap for exceptionally large/complex applications with constantly changing
		//		content regions (eg: a dijit.layout.ContentPane with replacing data)
		//		There is NO automatic GC going on. If you dojo.destroy() a node, you should _removeNodeData
		//		prior to destruction.
		var livePids = query("[" + dataattr + "]").map(dopid);
		for(var i in dataCache){
			if(array.indexOf(livePids, i) < 0){ delete dataCache[i]; }
		}
	};

	// make nodeData and removeNodeData public on dojo.NodeList:
	lang.extend(NodeList, {
		data: NodeList._adaptWithCondition(dodata, function(a){
			return a.length === 0 || a.length == 1 && (typeof a[0] == "string");
		}),
		removeData: NodeList._adaptAsForEach(removeData)
	});

// TODO: this is the basic implemetation of adaptWithCondtionAndWhenMappedConsiderLength, for lack of a better API name
// it conflicts with the the `dojo.NodeList` way: always always return an arrayLike thinger. Consider for 2.0:
//
//	NodeList.prototype.data = function(key, value){
//		var a = arguments, r;
//		if(a.length === 0 || a.length == 1 && (typeof a[0] == "string")){
//			r = this.map(function(node){
//				return d._data(node, key);
//			});
//			if(r.length == 1){ r = r[0]; } // the offending line, and the diff on adaptWithCondition
//		}else{
//			r = this.forEach(function(node){
//				d._data(node, key, value);
//			});
//		}
//		return r; // dojo.NodeList|Array|SingleItem
//	};

	return NodeList;

});