LocalStorage.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Generated by CoffeeScript 1.10.0
  2. (function() {
  3. var JSONStorage, KEY_FOR_EMPTY_STRING, LocalStorage, MetaKey, QUOTA_EXCEEDED_ERR, StorageEvent, _emptyDirectory, _escapeKey, _rm, createMap, events, fs, path, writeSync,
  4. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  5. hasProp = {}.hasOwnProperty;
  6. path = require('path');
  7. fs = require('fs');
  8. events = require('events');
  9. writeSync = require('write-file-atomic').sync;
  10. KEY_FOR_EMPTY_STRING = '---.EMPTY_STRING.---';
  11. _emptyDirectory = function(target) {
  12. var i, len, p, ref, results;
  13. ref = fs.readdirSync(target);
  14. results = [];
  15. for (i = 0, len = ref.length; i < len; i++) {
  16. p = ref[i];
  17. results.push(_rm(path.join(target, p)));
  18. }
  19. return results;
  20. };
  21. _rm = function(target) {
  22. if (fs.statSync(target).isDirectory()) {
  23. _emptyDirectory(target);
  24. return fs.rmdirSync(target);
  25. } else {
  26. return fs.unlinkSync(target);
  27. }
  28. };
  29. _escapeKey = function(key) {
  30. var newKey;
  31. if (key === '') {
  32. newKey = KEY_FOR_EMPTY_STRING;
  33. } else {
  34. newKey = key.toString();
  35. }
  36. return newKey;
  37. };
  38. QUOTA_EXCEEDED_ERR = (function(superClass) {
  39. extend(QUOTA_EXCEEDED_ERR, superClass);
  40. function QUOTA_EXCEEDED_ERR(message) {
  41. this.message = message != null ? message : 'Unknown error.';
  42. if (Error.captureStackTrace != null) {
  43. Error.captureStackTrace(this, this.constructor);
  44. }
  45. this.name = this.constructor.name;
  46. }
  47. QUOTA_EXCEEDED_ERR.prototype.toString = function() {
  48. return this.name + ": " + this.message;
  49. };
  50. return QUOTA_EXCEEDED_ERR;
  51. })(Error);
  52. StorageEvent = (function() {
  53. function StorageEvent(key1, oldValue1, newValue1, url, storageArea) {
  54. this.key = key1;
  55. this.oldValue = oldValue1;
  56. this.newValue = newValue1;
  57. this.url = url;
  58. this.storageArea = storageArea != null ? storageArea : 'localStorage';
  59. }
  60. return StorageEvent;
  61. })();
  62. MetaKey = (function() {
  63. function MetaKey(key1, index1) {
  64. this.key = key1;
  65. this.index = index1;
  66. if (!(this instanceof MetaKey)) {
  67. return new MetaKey(this.key, this.index);
  68. }
  69. }
  70. return MetaKey;
  71. })();
  72. createMap = function() {
  73. var Map;
  74. Map = function() {};
  75. Map.prototype = Object.create(null);
  76. return new Map();
  77. };
  78. LocalStorage = (function(superClass) {
  79. var instanceMap;
  80. extend(LocalStorage, superClass);
  81. instanceMap = {};
  82. function LocalStorage(_location, quota) {
  83. this._location = _location;
  84. this.quota = quota != null ? quota : 5 * 1024 * 1024;
  85. if (!(this instanceof LocalStorage)) {
  86. return new LocalStorage(this._location, this.quota);
  87. }
  88. this._location = path.resolve(this._location);
  89. if (instanceMap[this._location] != null) {
  90. return instanceMap[this._location];
  91. }
  92. this.length = 0;
  93. this._bytesInUse = 0;
  94. this._keys = [];
  95. this._metaKeyMap = createMap();
  96. this._eventUrl = "pid:" + process.pid;
  97. this._init();
  98. this._QUOTA_EXCEEDED_ERR = QUOTA_EXCEEDED_ERR;
  99. instanceMap[this._location] = this;
  100. return instanceMap[this._location];
  101. }
  102. LocalStorage.prototype._init = function() {
  103. var _MetaKey, _decodedKey, _keys, e, error, error1, i, index, k, len, stat;
  104. try {
  105. stat = fs.statSync(this._location);
  106. if ((stat != null) && !stat.isDirectory()) {
  107. throw new Error("A file exists at the location '" + this._location + "' when trying to create/open localStorage");
  108. }
  109. this._bytesInUse = 0;
  110. this.length = 0;
  111. _keys = fs.readdirSync(this._location);
  112. for (index = i = 0, len = _keys.length; i < len; index = ++i) {
  113. k = _keys[index];
  114. _decodedKey = decodeURIComponent(k);
  115. this._keys.push(_decodedKey);
  116. _MetaKey = new MetaKey(k, index);
  117. this._metaKeyMap[_decodedKey] = _MetaKey;
  118. stat = this._getStat(k);
  119. if ((stat != null ? stat.size : void 0) != null) {
  120. _MetaKey.size = stat.size;
  121. this._bytesInUse += stat.size;
  122. }
  123. }
  124. this.length = _keys.length;
  125. } catch (error) {
  126. e = error;
  127. if (e.code !== "ENOENT") {
  128. throw e;
  129. }
  130. try {
  131. fs.mkdirSync(this._location);
  132. } catch (error1) {
  133. e = error1;
  134. if (e.code !== "EEXIST") {
  135. throw e;
  136. }
  137. }
  138. }
  139. };
  140. LocalStorage.prototype.setItem = function(key, value) {
  141. var encodedKey, evnt, existsBeforeSet, filename, hasListeners, metaKey, oldLength, oldValue, valueString, valueStringLength;
  142. hasListeners = events.EventEmitter.listenerCount(this, 'storage');
  143. oldValue = null;
  144. if (hasListeners) {
  145. oldValue = this.getItem(key);
  146. }
  147. key = _escapeKey(key);
  148. encodedKey = encodeURIComponent(key);
  149. filename = path.join(this._location, encodedKey);
  150. valueString = value.toString();
  151. valueStringLength = valueString.length;
  152. metaKey = this._metaKeyMap[key];
  153. existsBeforeSet = !!metaKey;
  154. if (existsBeforeSet) {
  155. oldLength = metaKey.size;
  156. } else {
  157. oldLength = 0;
  158. }
  159. if (this._bytesInUse - oldLength + valueStringLength > this.quota) {
  160. throw new QUOTA_EXCEEDED_ERR();
  161. }
  162. writeSync(filename, valueString, 'utf8');
  163. if (!existsBeforeSet) {
  164. metaKey = new MetaKey(encodedKey, (this._keys.push(key)) - 1);
  165. metaKey.size = valueStringLength;
  166. this._metaKeyMap[key] = metaKey;
  167. this.length += 1;
  168. this._bytesInUse += valueStringLength;
  169. }
  170. if (hasListeners) {
  171. evnt = new StorageEvent(key, oldValue, value, this._eventUrl);
  172. return this.emit('storage', evnt);
  173. }
  174. };
  175. LocalStorage.prototype.getItem = function(key) {
  176. var filename, metaKey;
  177. key = _escapeKey(key);
  178. metaKey = this._metaKeyMap[key];
  179. if (!!metaKey) {
  180. filename = path.join(this._location, metaKey.key);
  181. return fs.readFileSync(filename, 'utf8');
  182. } else {
  183. return null;
  184. }
  185. };
  186. LocalStorage.prototype._getStat = function(key) {
  187. var error, filename;
  188. key = _escapeKey(key);
  189. filename = path.join(this._location, encodeURIComponent(key));
  190. try {
  191. return fs.statSync(filename);
  192. } catch (error) {
  193. return null;
  194. }
  195. };
  196. LocalStorage.prototype.removeItem = function(key) {
  197. var evnt, filename, hasListeners, k, meta, metaKey, oldValue, ref, v;
  198. key = _escapeKey(key);
  199. metaKey = this._metaKeyMap[key];
  200. if (!!metaKey) {
  201. hasListeners = events.EventEmitter.listenerCount(this, 'storage');
  202. oldValue = null;
  203. if (hasListeners) {
  204. oldValue = this.getItem(key);
  205. }
  206. delete this._metaKeyMap[key];
  207. this.length -= 1;
  208. this._bytesInUse -= metaKey.size;
  209. filename = path.join(this._location, metaKey.key);
  210. this._keys.splice(metaKey.index, 1);
  211. ref = this._metaKeyMap;
  212. for (k in ref) {
  213. v = ref[k];
  214. meta = this._metaKeyMap[k];
  215. if (meta.index > metaKey.index) {
  216. meta.index -= 1;
  217. }
  218. }
  219. _rm(filename);
  220. if (hasListeners) {
  221. evnt = new StorageEvent(key, oldValue, null, this._eventUrl);
  222. return this.emit('storage', evnt);
  223. }
  224. }
  225. };
  226. LocalStorage.prototype.key = function(n) {
  227. return this._keys[n];
  228. };
  229. LocalStorage.prototype.clear = function() {
  230. var evnt;
  231. _emptyDirectory(this._location);
  232. this._metaKeyMap = createMap();
  233. this._keys = [];
  234. this.length = 0;
  235. this._bytesInUse = 0;
  236. if (events.EventEmitter.listenerCount(this, 'storage')) {
  237. evnt = new StorageEvent(null, null, null, this._eventUrl);
  238. return this.emit('storage', evnt);
  239. }
  240. };
  241. LocalStorage.prototype._getBytesInUse = function() {
  242. return this._bytesInUse;
  243. };
  244. LocalStorage.prototype._deleteLocation = function() {
  245. delete instanceMap[this._location];
  246. _rm(this._location);
  247. this._metaKeyMap = {};
  248. this._keys = [];
  249. this.length = 0;
  250. return this._bytesInUse = 0;
  251. };
  252. return LocalStorage;
  253. })(events.EventEmitter);
  254. JSONStorage = (function(superClass) {
  255. extend(JSONStorage, superClass);
  256. function JSONStorage() {
  257. return JSONStorage.__super__.constructor.apply(this, arguments);
  258. }
  259. JSONStorage.prototype.setItem = function(key, value) {
  260. var newValue;
  261. newValue = JSON.stringify(value);
  262. return JSONStorage.__super__.setItem.call(this, key, newValue);
  263. };
  264. JSONStorage.prototype.getItem = function(key) {
  265. return JSON.parse(JSONStorage.__super__.getItem.call(this, key));
  266. };
  267. return JSONStorage;
  268. })(LocalStorage);
  269. exports.LocalStorage = LocalStorage;
  270. exports.JSONStorage = JSONStorage;
  271. exports.QUOTA_EXCEEDED_ERR = QUOTA_EXCEEDED_ERR;
  272. }).call(this);