/
iron-localstorage-behavior.html
144 lines (123 loc) · 3.71 KB
/
iron-localstorage-behavior.html
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
<!doctype html>
<link rel="import" href="../polymer/polymer.html">
<script>
var Polymer = Polymer || {};
/**
* Access to local storage (allows users to prune older entries)
*
* @polymerBehavior Polymer.IronLocalStorageBehavior
* @demo demo/index.html
*/
Polymer.IronLocalStorageBehavior = {
getFromCache: function(key) {
if (!window.localStorage) {
// Ignore caching if local storage is not available
return Promise.resolve();
}
if (!key) {
return Promise.resolve();
}
try {
var cacheEntryStr = window.localStorage.getItem(key);
try {
var cacheEntry = JSON.parse(cacheEntryStr);
var value = cacheEntry ? cacheEntry.data : null;
return Promise.resolve(value);
} catch (e) {
console.log(`Failed to parse storage value for "${key}": "${valueStr}"`);
return Promise.resolve();
}
} catch (e) {
return Promise.reject(e);
}
},
saveToCache: function(key, data) {
if (!window.localStorage) {
// Ignore caching if local storage is not available
return Promise.resolve();
}
if (!key || data === null || data === undefined) {
// Don't save empty data
return Promise.resolve();
}
var cacheEntry = {
data: data,
timestamp: Date.now()
};
try {
window.localStorage.setItem(key, JSON.stringify(cacheEntry));
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve();
},
/**
* Removes all old entries in local cache to avoid it overflowing
*/
pruneCache: function(preservedKeys = [], maxEntriesInLocalStorage = 50) {
if (!window.localStorage) {
// Ignore caching if local storage is not available
return Promise.resolve();
}
if (window.localStorage.length <= maxEntriesInLocalStorage) {
// Preformance optimization: leave if there is nothing to be done
return Promise.resolve();
}
// Collect all local storage entries with their timestamp (to detect
// afterwards the oldest ones)
var entries = [];
for (var i = 0; i < window.localStorage.length; i++){
var key = window.localStorage.key(i);
// Preserve whitelisted keys
if (preservedKeys.indexOf(key) >= 0) {
continue;
}
var valueStr = window.localStorage.getItem(key);
try {
var value = JSON.parse(valueStr);
var timestamp = value.timestamp;
// Remove all (legacy) entries without a timestamp
// XXX: Use parameter `preservedKeys` to protect entries from
// being cleaned up.
if (!timestamp) {
window.localStorage.removeItem(key);
} else {
entries.push({ key: key, timestamp: timestamp });
}
} catch (e) {
window.localStorage.removeItem(key);
console.log(`Remove invalid local storage entry "${valueStr}"`);
}
}
// Check if there is anything to be done. This can't be checked earlier
// because (legacy) entries without a timestamp might have been deleted
// in the last step.
var toBeRemovedKeys = this._detectToBeRemovedKeys(entries, maxEntriesInLocalStorage);
toBeRemovedKeys.forEach(key => {
window.localStorage.removeItem(key);
});
return Promise.resolve();
},
/**
* Return the entries
* @param {Array} entries Entries to be considered
* @param {Number} maxEntriesInLocalStorage
* @return {Array} Keys of the entries that should be returned
*/
_detectToBeRemovedKeys: function(entries, maxEntriesInLocalStorage) {
if (entries.length <= maxEntriesInLocalStorage) {
return [];
}
var toBeRemovedKeys = [];
// Sort newest first (we want to keep the first newest)
entries.sort((entry1, entry2) => {
return entry1.timestamp < entry2.timestamp;
});
// Remove oldest entries (expect the ones that we keep)
for (var i = maxEntriesInLocalStorage; i < entries.length; i++) {
toBeRemovedKeys.push(entries[i].key);
}
return toBeRemovedKeys;
}
};
</script>