Skip to content

Commit

Permalink
Merge pull request #2141 from knockout/2141-domdata-weakmap
Browse files Browse the repository at this point in the history
ko.utils.domData storage scheme requires explicit cleanup
  • Loading branch information
mbest committed Jul 23, 2017
2 parents b58e2b6 + c87ad68 commit e57500a
Showing 1 changed file with 46 additions and 26 deletions.
72 changes: 46 additions & 26 deletions src/utils.domData.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,61 @@ ko.utils.domData = new (function () {
var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
var dataStore = {};

function getAll(node, createIfNotFound) {
var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
if (!hasExistingDataStore) {
if (!createIfNotFound)
return undefined;
dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
dataStore[dataStoreKey] = {};
}
return dataStore[dataStoreKey];
}

return {
get: function (node, key) {
var allDataForNode = getAll(node, false);
return allDataForNode === undefined ? undefined : allDataForNode[key];
},
set: function (node, key, value) {
if (value === undefined) {
// Make sure we don't actually create a new domData key if we are actually deleting a value
if (getAll(node, false) === undefined)
return;
var getDataForNode, clear;
if (!ko.utils.ieVersion) {
// We considered using WeakMap, but it has a problem in IE 11 and Edge that prevents using
// it cross-window, so instead we just store the data directly on the node.
// See https://github.com/knockout/knockout/issues/2141
getDataForNode = function (node, createIfNotFound) {
var dataForNode = node[dataStoreKeyExpandoPropertyName];
if (!dataForNode && createIfNotFound) {
dataForNode = node[dataStoreKeyExpandoPropertyName] = {};
}
var allDataForNode = getAll(node, true);
allDataForNode[key] = value;
},
clear: function (node) {
return dataForNode;
};
clear = function (node) {
if (node[dataStoreKeyExpandoPropertyName]) {
delete node[dataStoreKeyExpandoPropertyName];
return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
}
return false;
};
} else {
// Old IE versions have memory issues if you store objects on the node, so we use a
// separate data storage and link to it from the node using a string key.
getDataForNode = function (node, createIfNotFound) {
var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
if (!hasExistingDataStore) {
if (!createIfNotFound)
return undefined;
dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
dataStore[dataStoreKey] = {};
}
return dataStore[dataStoreKey];
};
clear = function (node) {
var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
if (dataStoreKey) {
delete dataStore[dataStoreKey];
node[dataStoreKeyExpandoPropertyName] = null;
return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
}
return false;
};
}

return {
get: function (node, key) {
var dataForNode = getDataForNode(node, false);
return dataForNode && dataForNode[key];
},
set: function (node, key, value) {
// Make sure we don't actually create a new domData key if we are actually deleting a value
var dataForNode = getDataForNode(node, value !== undefined /* createIfNotFound */);
dataForNode && (dataForNode[key] = value);
},
clear: clear,

nextKey: function () {
return (uniqueId++) + dataStoreKeyExpandoPropertyName;
Expand Down

0 comments on commit e57500a

Please sign in to comment.