25dc91569717eef49b4e546f712c19e86e4e960a13d656541a206c505b001f7715969a9ce813443e042e2ae17e240ddb7d763c8d056d2ba0782a15fac8421c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /**
  2. * Copyright (c) 2022, ESHA Research
  3. * Dual licensed under the MIT and GPL licenses:
  4. * http://www.opensource.org/licenses/mit-license.php
  5. * http://www.gnu.org/licenses/gpl.html
  6. */
  7. ;(function(window, define) {
  8. var _ = {
  9. version: "<%= pkg.version %>",
  10. areas: {},
  11. apis: {},
  12. nsdelim: '.',
  13. // utilities
  14. inherit: function(api, o) {
  15. for (var p in api) {
  16. if (!o.hasOwnProperty(p)) {
  17. Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(api, p));
  18. }
  19. }
  20. return o;
  21. },
  22. stringify: function(d, fn) {
  23. return d === undefined || typeof d === "function" ? d+'' : JSON.stringify(d,fn||_.replace);
  24. },
  25. parse: function(s, fn) {
  26. // if it doesn't parse, return as is
  27. try{ return JSON.parse(s,fn||_.revive); }catch(e){ return s; }
  28. },
  29. // extension hooks
  30. fn: function(name, fn) {
  31. _.storeAPI[name] = fn;
  32. for (var api in _.apis) {
  33. _.apis[api][name] = fn;
  34. }
  35. },
  36. get: function(area, key){ return area.getItem(key); },
  37. set: function(area, key, string){ area.setItem(key, string); },
  38. remove: function(area, key){ area.removeItem(key); },
  39. key: function(area, i){ return area.key(i); },
  40. length: function(area){ return area.length; },
  41. clear: function(area){ area.clear(); },
  42. // core functions
  43. Store: function(id, area, namespace) {
  44. var store = _.inherit(_.storeAPI, function(key, data, overwrite) {
  45. if (arguments.length === 0){ return store.getAll(); }
  46. if (typeof data === "function"){ return store.transact(key, data, overwrite); }// fn=data, alt=overwrite
  47. if (data !== undefined){ return store.set(key, data, overwrite); }
  48. if (typeof key === "string" || typeof key === "number"){ return store.get(key); }
  49. if (typeof key === "function"){ return store.each(key); }
  50. if (!key){ return store.clear(); }
  51. return store.setAll(key, data);// overwrite=data, data=key
  52. });
  53. store._id = id;
  54. try {
  55. var testKey = '__store2_test';
  56. area.setItem(testKey, 'ok');
  57. store._area = area;
  58. area.removeItem(testKey);
  59. } catch (e) {
  60. store._area = _.storage('fake');
  61. }
  62. store._ns = namespace || '';
  63. if (!_.areas[id]) {
  64. _.areas[id] = store._area;
  65. }
  66. if (!_.apis[store._ns+store._id]) {
  67. _.apis[store._ns+store._id] = store;
  68. }
  69. return store;
  70. },
  71. storeAPI: {
  72. // admin functions
  73. area: function(id, area) {
  74. var store = this[id];
  75. if (!store || !store.area) {
  76. store = _.Store(id, area, this._ns);//new area-specific api in this namespace
  77. if (!this[id]){ this[id] = store; }
  78. }
  79. return store;
  80. },
  81. namespace: function(namespace, singleArea, delim) {
  82. delim = delim || this._delim || _.nsdelim;
  83. if (!namespace){
  84. return this._ns ? this._ns.substring(0,this._ns.length-delim.length) : '';
  85. }
  86. var ns = namespace, store = this[ns];
  87. if (!store || !store.namespace) {
  88. store = _.Store(this._id, this._area, this._ns+ns+delim);//new namespaced api
  89. store._delim = delim;
  90. if (!this[ns]){ this[ns] = store; }
  91. if (!singleArea) {
  92. for (var name in _.areas) {
  93. store.area(name, _.areas[name]);
  94. }
  95. }
  96. }
  97. return store;
  98. },
  99. isFake: function(force) {
  100. if (force) {
  101. this._real = this._area;
  102. this._area = _.storage('fake');
  103. } else if (force === false) {
  104. this._area = this._real || this._area;
  105. }
  106. return this._area.name === 'fake';
  107. },
  108. toString: function() {
  109. return 'store'+(this._ns?'.'+this.namespace():'')+'['+this._id+']';
  110. },
  111. // storage functions
  112. has: function(key) {
  113. if (this._area.has) {
  114. return this._area.has(this._in(key));//extension hook
  115. }
  116. return !!(this._in(key) in this._area);
  117. },
  118. size: function(){ return this.keys().length; },
  119. each: function(fn, fill) {// fill is used by keys(fillList) and getAll(fillList))
  120. for (var i=0, m=_.length(this._area); i<m; i++) {
  121. var key = this._out(_.key(this._area, i));
  122. if (key !== undefined) {
  123. if (fn.call(this, key, this.get(key), fill) === false) {
  124. break;
  125. }
  126. }
  127. if (m > _.length(this._area)) { m--; i--; }// in case of removeItem
  128. }
  129. return fill || this;
  130. },
  131. keys: function(fillList) {
  132. return this.each(function(k, v, list){ list.push(k); }, fillList || []);
  133. },
  134. get: function(key, alt) {
  135. var s = _.get(this._area, this._in(key)),
  136. fn;
  137. if (typeof alt === "function") {
  138. fn = alt;
  139. alt = null;
  140. }
  141. return s !== null ? _.parse(s, fn) :
  142. alt != null ? alt : s;
  143. },
  144. getAll: function(fillObj) {
  145. return this.each(function(k, v, all){ all[k] = v; }, fillObj || {});
  146. },
  147. transact: function(key, fn, alt) {
  148. var val = this.get(key, alt),
  149. ret = fn(val);
  150. this.set(key, ret === undefined ? val : ret);
  151. return this;
  152. },
  153. set: function(key, data, overwrite) {
  154. var d = this.get(key),
  155. replacer;
  156. if (d != null && overwrite === false) {
  157. return data;
  158. }
  159. if (typeof overwrite === "function") {
  160. replacer = overwrite;
  161. overwrite = undefined;
  162. }
  163. return _.set(this._area, this._in(key), _.stringify(data, replacer), overwrite) || d;
  164. },
  165. setAll: function(data, overwrite) {
  166. var changed, val;
  167. for (var key in data) {
  168. val = data[key];
  169. if (this.set(key, val, overwrite) !== val) {
  170. changed = true;
  171. }
  172. }
  173. return changed;
  174. },
  175. add: function(key, data, replacer) {
  176. var d = this.get(key);
  177. if (d instanceof Array) {
  178. data = d.concat(data);
  179. } else if (d !== null) {
  180. var type = typeof d;
  181. if (type === typeof data && type === 'object') {
  182. for (var k in data) {
  183. d[k] = data[k];
  184. }
  185. data = d;
  186. } else {
  187. data = d + data;
  188. }
  189. }
  190. _.set(this._area, this._in(key), _.stringify(data, replacer));
  191. return data;
  192. },
  193. remove: function(key, alt) {
  194. var d = this.get(key, alt);
  195. _.remove(this._area, this._in(key));
  196. return d;
  197. },
  198. clear: function() {
  199. if (!this._ns) {
  200. _.clear(this._area);
  201. } else {
  202. this.each(function(k){ _.remove(this._area, this._in(k)); }, 1);
  203. }
  204. return this;
  205. },
  206. clearAll: function() {
  207. var area = this._area;
  208. for (var id in _.areas) {
  209. if (_.areas.hasOwnProperty(id)) {
  210. this._area = _.areas[id];
  211. this.clear();
  212. }
  213. }
  214. this._area = area;
  215. return this;
  216. },
  217. // internal use functions
  218. _in: function(k) {
  219. if (typeof k !== "string"){ k = _.stringify(k); }
  220. return this._ns ? this._ns + k : k;
  221. },
  222. _out: function(k) {
  223. return this._ns ?
  224. k && k.indexOf(this._ns) === 0 ?
  225. k.substring(this._ns.length) :
  226. undefined : // so each() knows to skip it
  227. k;
  228. }
  229. },// end _.storeAPI
  230. storage: function(name) {
  231. return _.inherit(_.storageAPI, { items: {}, name: name });
  232. },
  233. storageAPI: {
  234. length: 0,
  235. has: function(k){ return this.items.hasOwnProperty(k); },
  236. key: function(i) {
  237. var c = 0;
  238. for (var k in this.items){
  239. if (this.has(k) && i === c++) {
  240. return k;
  241. }
  242. }
  243. },
  244. setItem: function(k, v) {
  245. if (!this.has(k)) {
  246. this.length++;
  247. }
  248. this.items[k] = v;
  249. },
  250. removeItem: function(k) {
  251. if (this.has(k)) {
  252. delete this.items[k];
  253. this.length--;
  254. }
  255. },
  256. getItem: function(k){ return this.has(k) ? this.items[k] : null; },
  257. clear: function(){ for (var k in this.items){ this.removeItem(k); } }
  258. }// end _.storageAPI
  259. };
  260. var store =
  261. // safely set this up (throws error in IE10/32bit mode for local files)
  262. _.Store("local", (function(){try{ return localStorage; }catch(e){}})());
  263. store.local = store;// for completeness
  264. store._ = _;// for extenders and debuggers...
  265. // safely setup store.session (throws exception in FF for file:/// urls)
  266. store.area("session", (function(){try{ return sessionStorage; }catch(e){}})());
  267. store.area("page", _.storage("page"));
  268. if (typeof define === 'function' && define.amd !== undefined) {
  269. define('store2', [], function () {
  270. return store;
  271. });
  272. } else if (typeof module !== 'undefined' && module.exports) {
  273. module.exports = store;
  274. } else {
  275. // expose the primary store fn to the global object and save conflicts
  276. if (window.store){ _.conflict = window.store; }
  277. window.store = store;
  278. }
  279. })(this, this && this.define);