TabStateCache.sys.mjs (4852B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * A cache for tabs data. 7 * 8 * This cache implements a weak map from tabs (as XUL elements) 9 * to tab data (as objects). 10 * 11 * Note that we should never cache private data, as: 12 * - that data is used very seldom by SessionStore; 13 * - caching private data in addition to public data is memory consuming. 14 */ 15 export var TabStateCache = Object.freeze({ 16 /** 17 * Retrieves cached data for a given |tab| or associated |browser|. 18 * 19 * @param permanentKey (object) 20 * The tab or browser to retrieve cached data for. 21 * @return (object) 22 * The cached data stored for the given |tab| 23 * or associated |browser|. 24 */ 25 get(permanentKey) { 26 return TabStateCacheInternal.get(permanentKey); 27 }, 28 29 /** 30 * Updates cached data for a given |tab| or associated |browser|. 31 * 32 * @param permanentKey (object) 33 * The tab or browser belonging to the given tab data. 34 * @param newData (object) 35 * The new data to be stored for the given |tab| 36 * or associated |browser|. 37 */ 38 update(permanentKey, newData) { 39 TabStateCacheInternal.update(permanentKey, newData); 40 }, 41 }); 42 43 var TabStateCacheInternal = { 44 _data: new WeakMap(), 45 46 /** 47 * Retrieves cached data for a given |tab| or associated |browser|. 48 * 49 * @param permanentKey (object) 50 * The tab or browser to retrieve cached data for. 51 * @return (object) 52 * The cached data stored for the given |tab| 53 * or associated |browser|. 54 */ 55 get(permanentKey) { 56 return this._data.get(permanentKey); 57 }, 58 59 /** 60 * Helper function used by update (see below). For message size 61 * optimization sometimes we don't update the whole session storage 62 * only the values that have been changed. 63 * 64 * @param data (object) 65 * The cached data where we want to update the changes. 66 * @param change (object) 67 * The actual changed values per domain. 68 */ 69 updatePartialStorageChange(data, change) { 70 if (!data.storage) { 71 data.storage = {}; 72 } 73 74 let storage = data.storage; 75 for (let domain of Object.keys(change)) { 76 if (!change[domain]) { 77 // We were sent null in place of the change object, which means 78 // we should delete session storage entirely for this domain. 79 delete storage[domain]; 80 } else { 81 for (let key of Object.keys(change[domain])) { 82 let value = change[domain][key]; 83 if (value === null) { 84 if (storage[domain] && storage[domain][key]) { 85 delete storage[domain][key]; 86 } 87 } else { 88 if (!storage[domain]) { 89 storage[domain] = {}; 90 } 91 storage[domain][key] = value; 92 } 93 } 94 } 95 } 96 }, 97 98 /** 99 * Helper function used by update (see below). For message size 100 * optimization sometimes we don't update the whole browser history 101 * only the current index and the tail of the history from a certain 102 * index (specified by change.fromIdx) 103 * 104 * @param data (object) 105 * The cached data where we want to update the changes. 106 * @param change (object) 107 * Object containing the tail of the history array, and 108 * some additional metadata. 109 */ 110 updatePartialHistoryChange(data, change) { 111 const kLastIndex = Number.MAX_SAFE_INTEGER - 1; 112 113 if (!data.history) { 114 data.history = { entries: [] }; 115 } 116 117 let history = data.history; 118 for (let key of Object.keys(change)) { 119 if (key == "entries") { 120 if (change.fromIdx != kLastIndex) { 121 let start = change.fromIdx + 1; 122 history.entries.splice(start, Infinity, ...change.entries); 123 } 124 } else if (key != "fromIdx") { 125 history[key] = change[key]; 126 } 127 } 128 }, 129 130 /** 131 * Updates cached data for a given |tab| or associated |browser|. 132 * 133 * @param permanentKey (object) 134 * The tab or browser belonging to the given tab data. 135 * @param newData (object) 136 * The new data to be stored for the given permanent key. 137 */ 138 update(permanentKey, newData) { 139 let data = this._data.get(permanentKey) || {}; 140 141 for (let key of Object.keys(newData)) { 142 if (key == "storagechange") { 143 this.updatePartialStorageChange(data, newData.storagechange); 144 continue; 145 } 146 147 if (key == "historychange") { 148 this.updatePartialHistoryChange(data, newData.historychange); 149 continue; 150 } 151 152 let value = newData[key]; 153 if (value === null) { 154 delete data[key]; 155 } else { 156 data[key] = value; 157 } 158 } 159 160 this._data.set(permanentKey, data); 161 }, 162 };