You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
7.1 KiB
204 lines
7.1 KiB
define([ |
|
"./_base/kernel", "./query", "./_base/lang", "./_base/array", "./dom-attr" |
|
], function(dojo, query, lang, array, attr){ |
|
|
|
// module: |
|
// dojo/NodeList-data |
|
|
|
/*===== |
|
return function(){ |
|
// summary: |
|
// Adds data() and removeData() methods to NodeList, and returns NodeList constructor. |
|
}; |
|
=====*/ |
|
|
|
var NodeList = query.NodeList; |
|
|
|
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; |
|
} |
|
; |
|
|
|
//>>excludeStart("debugging", true); |
|
// An alias to the private dataCache for NodeList-data. NEVER USE THIS! |
|
// This private is only exposed for the benefit of unit testing, and is |
|
// removed during the build process. |
|
NodeList._nodeDataCache = dojo._nodeDataCache = dataCache; |
|
//>>excludeEnd("debugging"); |
|
|
|
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){ return 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]; |
|
} |
|
} |
|
}; |
|
|
|
NodeList._gcNodeData = 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) |
|
}); |
|
|
|
/*===== |
|
lang.extend(NodeList, { |
|
data: function(key, value){ |
|
// summary: |
|
// stash or get some arbitrary data on/from these nodes. |
|
// |
|
// description: |
|
// Stash or get some arbitrary 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. |
|
// | require(["dojo/query", "dojo/NodeList-data"], function(query){ |
|
// | query(".foo").data("bar", "touched"); |
|
// | var touched = query(".foo").data("bar"); |
|
// | if(touched[0] == "touched"){ alert('win'); } |
|
// | }); |
|
// |
|
// example: |
|
// Get all the data items for a given node. |
|
// | require(["dojo/query", "dojo/NodeList-data"], function(query){ |
|
// | var list = query(".foo").data(); |
|
// | var first = list[0]; |
|
// | }); |
|
// |
|
// example: |
|
// Set the data to a complex hash. Overwrites existing keys with new value |
|
// | require(["dojo/query", "dojo/NodeList-data"], function(query){ |
|
// | query(".foo").data({ bar:"baz", foo:"bar" }); |
|
// Then get some random key: |
|
// | 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 chaining. 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) |
|
}, |
|
|
|
removeData: function(key){ |
|
// summary: |
|
// Remove the data associated with these nodes. |
|
// key: String? |
|
// If omitted, clean all data for this node. |
|
// If passed, remove the data item found at `key` |
|
} |
|
}); |
|
=====*/ |
|
|
|
// TODO: this is the basic implementation of adaptWithConditionAndWhenMappedConsiderLength, 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; // NodeList|Array|SingleItem |
|
// }; |
|
|
|
return NodeList; |
|
|
|
});
|
|
|