mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
115 lines
3.3 KiB
JavaScript
115 lines
3.3 KiB
JavaScript
|
/*
|
||
|
* Provides a per-node data store that is automatically cloned when dom node is clone() or cloneNode()'d.
|
||
|
*/
|
||
|
|
||
|
(function($){
|
||
|
var data_store = {};
|
||
|
var check_name = 'com.silverstripe:check_id';
|
||
|
|
||
|
var expando = 'data_id:';
|
||
|
var id = 0;
|
||
|
|
||
|
/**
|
||
|
* Clone a data object. Currently uses jQuery's deep copy routine
|
||
|
*/
|
||
|
var cloneData = function(data) {
|
||
|
return $.extend(true, {}, data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the data object for an element.
|
||
|
* Picks a new ID, sets the tracking attribute and value on the DOM node and stores data in the data_store
|
||
|
*
|
||
|
* @param {jQuery selection} el - The element to store this data on
|
||
|
* @param {Object} data - The object to use as data, or undefined / null for an empty object
|
||
|
*/
|
||
|
var setData = function(el, data) {
|
||
|
if (!data) data = {};
|
||
|
|
||
|
id += 1;
|
||
|
var data_id = expando + id;
|
||
|
|
||
|
el.attr('data', data_id); el.data(check_name, data_id);
|
||
|
return data_store[data_id] = data;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Delete the data object for an element
|
||
|
* It's important this is called when the related element is deled, or memory could leak. We monkey-patch jQuery.removeData to make sure this happens
|
||
|
* @param {jQuery selection} el - The element to remove the data for
|
||
|
*/
|
||
|
var clearData = function(el) {
|
||
|
var data_id = el.attr('data');
|
||
|
if (!data_id) return;
|
||
|
|
||
|
el.removeAttr('data');
|
||
|
// Only remove the data if this is the last element with a data reference to it. This is so removing an element
|
||
|
// doesn't delete the data before any cloned elements have a chance to copy it
|
||
|
if ($('[data='+data_id+']').length == 0) delete data_store[data_id];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the data object for an element
|
||
|
* Sets an empty data object if the element does not have one yet
|
||
|
* Clones the data object if the element it's attached to has been cloned
|
||
|
* @param {jQuery selection} el - The element to retrieve the data of
|
||
|
*/
|
||
|
var getData = function(el) {
|
||
|
// If the data_id is missing, the element has no data
|
||
|
var data_id = el.attr('data');
|
||
|
if (!data_id) return setData(el);
|
||
|
|
||
|
var check_id = el.data(check_name);
|
||
|
if (!check_id || check_id != data_id) {
|
||
|
// If the check_id is missing, the element has been cloned. So clone the data too
|
||
|
var newdata = cloneData(data_store[data_id]);
|
||
|
setData(el, newdata);
|
||
|
// If we were the last element holding on to a reference to that old data, delete it now that we're done with it
|
||
|
if ($('[data='+data_id+']').length == 0) delete data_store[data_id];
|
||
|
return newdata;
|
||
|
}
|
||
|
|
||
|
// Otherwise, this element has some data, so return it
|
||
|
return data_store[data_id];
|
||
|
}
|
||
|
|
||
|
$.dat = {};
|
||
|
/**
|
||
|
* Check all data in data_store, removing any that are not longer referenced in the DOM
|
||
|
* Returns number of garbage-collected entries, for finding memory leaks
|
||
|
*/
|
||
|
$.dat.vacuum = function() {
|
||
|
var i = 0;
|
||
|
for (var k in data_store) {
|
||
|
if ($('[data='+k+']').length == 0) { delete data_store[k]; i++; }
|
||
|
}
|
||
|
return i;
|
||
|
}
|
||
|
/**
|
||
|
* Return count of items in data_store.
|
||
|
* Used in tests
|
||
|
*/
|
||
|
$.dat.size = function() {
|
||
|
var i = 0;
|
||
|
for (var k in data_store) i++;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the data object for the current element
|
||
|
*/
|
||
|
$.fn.d = function(a){
|
||
|
return getData(this.eq(0));
|
||
|
};
|
||
|
|
||
|
// Monkey patch removeData to also remove dat
|
||
|
var removeData_without_dat = $.removeData
|
||
|
$.removeData = function(elem, name) {
|
||
|
if (!name) clearData($(elem));
|
||
|
return removeData_without_dat.apply(this, arguments);
|
||
|
}
|
||
|
|
||
|
})(jQuery);
|
||
|
|