From f7d92ccb5b4594c15f6e6c2a27636ac677ab991e Mon Sep 17 00:00:00 2001 From: lilia Date: Mon, 3 Nov 2014 17:19:22 -0800 Subject: [PATCH] Bowerize backbone.localstorage --- background.html | 1 - bower.json | 7 +- .../backbone.localStorage.js | 41 +-- index.html | 1 - js/components.js | 263 ++++++++++++++++++ options.html | 1 - test/index.html | 1 - 7 files changed, 294 insertions(+), 21 deletions(-) rename {js-deps => components/backbone.localstorage}/backbone.localStorage.js (88%) diff --git a/background.html b/background.html index 41cf6e90..1b02fc0d 100644 --- a/background.html +++ b/background.html @@ -19,7 +19,6 @@ - diff --git a/bower.json b/bower.json index 265942f5..1f50aff6 100644 --- a/bower.json +++ b/bower.json @@ -14,7 +14,8 @@ "qrcode": "git://github.com/davidshimjs/qrcodejs.git", "bootstrap-tagsinput": "~0.4.2", "cryptojs": "svn+http://crypto-js.googlecode.com/svn/#~3.1.2", - "libphonenumber-api": "git://github.com/codedust/libphonenumber-api" + "libphonenumber-api": "git://github.com/codedust/libphonenumber-api", + "backbone.localstorage": "liliakai/Backbone.localStorage#master" }, "devDependencies": { "mocha": "~2.0.1", @@ -71,6 +72,9 @@ ], "libphonenumber-api": [ "libphonenumber_api-compiled.js" + ], + "backbone.localstorage": [ + "backbone.localStorage.js" ] }, "concat": { @@ -82,6 +86,7 @@ "mustache", "underscore", "backbone", + "backbone.localstorage", "qrcode", "libphonenumber-api" ] diff --git a/js-deps/backbone.localStorage.js b/components/backbone.localstorage/backbone.localStorage.js similarity index 88% rename from js-deps/backbone.localStorage.js rename to components/backbone.localstorage/backbone.localStorage.js index 7db8a66e..e83b496e 100644 --- a/js-deps/backbone.localStorage.js +++ b/components/backbone.localstorage/backbone.localStorage.js @@ -1,6 +1,6 @@ /** * Backbone localStorage Adapter - * Version 1.1.7 + * Version 1.1.14 * * https://github.com/jeromegn/Backbone.localStorage */ @@ -21,9 +21,6 @@ // persistence. Models are given GUIDS, and saved into a JSON object. Simple // as that. -// Hold reference to Underscore.js and Backbone.js in the closure in order -// to make things work even if they are removed from the global namespace - // Generate four random hex digits. function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); @@ -34,6 +31,10 @@ function guid() { return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); }; +function isObject(item) { + return item === Object(item); +} + function contains(array, item) { var i = array.length; while (i--) if (array[i] === item) return true; @@ -45,6 +46,12 @@ function extend(obj, props) { return obj; } +function result(object, property) { + if (object == null) return void 0; + var value = object[property]; + return (typeof value === 'function') ? object[property]() : value; +} + // Our Store is represented by a single JS object in *localStorage*. Create it // with a meaningful name, like the name you'd give a table. // window.Store is deprectated, use Backbone.LocalStorage instead @@ -55,7 +62,7 @@ Backbone.LocalStorage = window.Store = function(name, serializer) { this.name = name; this.serializer = serializer || { serialize: function(item) { - return _.isObject(item) ? JSON.stringify(item) : item; + return isObject(item) ? JSON.stringify(item) : item; }, // fix for "illegal access" error on Android when JSON.parse is passed null deserialize: function (data) { @@ -78,32 +85,32 @@ extend(Backbone.LocalStorage.prototype, { // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already // have an id of it's own. create: function(model) { - if (!model.id) { + if (!model.id && model.id !== 0) { model.id = guid(); model.set(model.idAttribute, model.id); } - this.localStorage().setItem(this.name+"-"+model.id, this.serializer.serialize(model)); + this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model)); this.records.push(model.id.toString()); this.save(); - return this.find(model) !== false; + return this.find(model); }, // Update a model by replacing its copy in `this.data`. update: function(model) { - this.localStorage().setItem(this.name+"-"+model.id, this.serializer.serialize(model)); + this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model)); var modelId = model.id.toString(); if (!contains(this.records, modelId)) { this.records.push(modelId); this.save(); } - return this.find(model) !== false; + return this.find(model); }, // Retrieve a model from `this.data` by id. find: function(model) { var store = this.localStorage().getItem(this.name); this.records = (store && store.split(",")) || []; - return this.serializer.deserialize(this.localStorage().getItem(this.name+"-"+model.id)); + return this.serializer.deserialize(this.localStorage().getItem(this._itemName(model.id))); }, // Return the array of all models currently in storage. @@ -113,7 +120,7 @@ extend(Backbone.LocalStorage.prototype, { var result = []; for (var i = 0, id, data; i < this.records.length; i++) { id = this.records[i]; - data = this.serializer.deserialize(this.localStorage().getItem(this.name+"-"+id)); + data = this.serializer.deserialize(this.localStorage().getItem(this._itemName(id))); if (data != null) result.push(data); } return result; @@ -121,9 +128,7 @@ extend(Backbone.LocalStorage.prototype, { // Delete a model from `this.data`, returning it. destroy: function(model) { - if (model.isNew()) - return false - this.localStorage().removeItem(this.name+"-"+model.id); + this.localStorage().removeItem(this._itemName(model.id)); var modelId = model.id.toString(); for (var i = 0, id; i < this.records.length; i++) { if (this.records[i] === modelId) { @@ -159,6 +164,10 @@ extend(Backbone.LocalStorage.prototype, { // Size of localStorage. _storageSize: function() { return this.localStorage().length; + }, + + _itemName: function(id) { + return this.name+"-"+id; } }); @@ -167,7 +176,7 @@ extend(Backbone.LocalStorage.prototype, { // *localStorage* property, which should be an instance of `Store`. // window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) { - var store = model.localStorage || model.collection.localStorage; + var store = result(model, 'localStorage') || result(model.collection, 'localStorage'); var resp, errorMessage; //If $ is having Deferred - use it. diff --git a/index.html b/index.html index 143abb37..3606fe8b 100644 --- a/index.html +++ b/index.html @@ -126,7 +126,6 @@ - diff --git a/js/components.js b/js/components.js index f728ee60..73c7316b 100644 --- a/js/components.js +++ b/js/components.js @@ -21356,6 +21356,269 @@ return jQuery; })); +/** + * Backbone localStorage Adapter + * Version 1.1.14 + * + * https://github.com/jeromegn/Backbone.localStorage + */ +(function (root, factory) { + if (typeof exports === 'object' && typeof require === 'function') { + module.exports = factory(require("backbone")); + } else if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["backbone"], function(Backbone) { + // Use global variables if the locals are undefined. + return factory(Backbone || root.Backbone); + }); + } else { + factory(Backbone); + } +}(this, function(Backbone) { +// A simple module to replace `Backbone.sync` with *localStorage*-based +// persistence. Models are given GUIDS, and saved into a JSON object. Simple +// as that. + +// Generate four random hex digits. +function S4() { + return (((1+Math.random())*0x10000)|0).toString(16).substring(1); +}; + +// Generate a pseudo-GUID by concatenating random hexadecimal. +function guid() { + return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); +}; + +function isObject(item) { + return item === Object(item); +} + +function contains(array, item) { + var i = array.length; + while (i--) if (array[i] === item) return true; + return false; +} + +function extend(obj, props) { + for (var key in props) obj[key] = props[key] + return obj; +} + +function result(object, property) { + if (object == null) return void 0; + var value = object[property]; + return (typeof value === 'function') ? object[property]() : value; +} + +// Our Store is represented by a single JS object in *localStorage*. Create it +// with a meaningful name, like the name you'd give a table. +// window.Store is deprectated, use Backbone.LocalStorage instead +Backbone.LocalStorage = window.Store = function(name, serializer) { + if( !this.localStorage ) { + throw "Backbone.localStorage: Environment does not support localStorage." + } + this.name = name; + this.serializer = serializer || { + serialize: function(item) { + return isObject(item) ? JSON.stringify(item) : item; + }, + // fix for "illegal access" error on Android when JSON.parse is passed null + deserialize: function (data) { + return data && JSON.parse(data); + } + }; + var store = this.localStorage().getItem(this.name); + this.records = (store && store.split(",")) || []; +}; + +extend(Backbone.LocalStorage.prototype, { + + // Save the current state of the **Store** to *localStorage*. + save: function() { + var store = this.localStorage().getItem(this.name); + this.records = _.union(this.records, store && store.split(",")); + this.localStorage().setItem(this.name, this.records.join(",")); + }, + + // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already + // have an id of it's own. + create: function(model) { + if (!model.id && model.id !== 0) { + model.id = guid(); + model.set(model.idAttribute, model.id); + } + this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model)); + this.records.push(model.id.toString()); + this.save(); + return this.find(model); + }, + + // Update a model by replacing its copy in `this.data`. + update: function(model) { + this.localStorage().setItem(this._itemName(model.id), this.serializer.serialize(model)); + var modelId = model.id.toString(); + if (!contains(this.records, modelId)) { + this.records.push(modelId); + this.save(); + } + return this.find(model); + }, + + // Retrieve a model from `this.data` by id. + find: function(model) { + var store = this.localStorage().getItem(this.name); + this.records = (store && store.split(",")) || []; + return this.serializer.deserialize(this.localStorage().getItem(this._itemName(model.id))); + }, + + // Return the array of all models currently in storage. + findAll: function() { + var store = this.localStorage().getItem(this.name); + this.records = (store && store.split(",")) || []; + var result = []; + for (var i = 0, id, data; i < this.records.length; i++) { + id = this.records[i]; + data = this.serializer.deserialize(this.localStorage().getItem(this._itemName(id))); + if (data != null) result.push(data); + } + return result; + }, + + // Delete a model from `this.data`, returning it. + destroy: function(model) { + this.localStorage().removeItem(this._itemName(model.id)); + var modelId = model.id.toString(); + for (var i = 0, id; i < this.records.length; i++) { + if (this.records[i] === modelId) { + this.records.splice(i, 1); + } + } + this.save(); + return model; + }, + + localStorage: function() { + return localStorage; + }, + + // Clear localStorage for specific collection. + _clear: function() { + var local = this.localStorage(), + itemRe = new RegExp("^" + this.name + "-"); + + // Remove id-tracking item (e.g., "foo"). + local.removeItem(this.name); + + // Match all data items (e.g., "foo-ID") and remove. + for (var k in local) { + if (itemRe.test(k)) { + local.removeItem(k); + } + } + + this.records.length = 0; + }, + + // Size of localStorage. + _storageSize: function() { + return this.localStorage().length; + }, + + _itemName: function(id) { + return this.name+"-"+id; + } + +}); + +// localSync delegate to the model or collection's +// *localStorage* property, which should be an instance of `Store`. +// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead +Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) { + var store = result(model, 'localStorage') || result(model.collection, 'localStorage'); + + var resp, errorMessage; + //If $ is having Deferred - use it. + var syncDfd = Backbone.$ ? + (Backbone.$.Deferred && Backbone.$.Deferred()) : + (Backbone.Deferred && Backbone.Deferred()); + + try { + + switch (method) { + case "read": + resp = model.id != undefined ? store.find(model) : store.findAll(); + break; + case "create": + resp = store.create(model); + break; + case "update": + resp = store.update(model); + break; + case "delete": + resp = store.destroy(model); + break; + } + + } catch(error) { + if (error.code === 22 && store._storageSize() === 0) + errorMessage = "Private browsing is unsupported"; + else + errorMessage = error.message; + } + + if (resp) { + if (options && options.success) { + if (Backbone.VERSION === "0.9.10") { + options.success(model, resp, options); + } else { + options.success(resp); + } + } + if (syncDfd) { + syncDfd.resolve(resp); + } + + } else { + errorMessage = errorMessage ? errorMessage + : "Record Not Found"; + + if (options && options.error) + if (Backbone.VERSION === "0.9.10") { + options.error(model, errorMessage, options); + } else { + options.error(errorMessage); + } + + if (syncDfd) + syncDfd.reject(errorMessage); + } + + // add compatibility with $.ajax + // always execute callback for success and error + if (options && options.complete) options.complete(resp); + + return syncDfd && syncDfd.promise(); +}; + +Backbone.ajaxSync = Backbone.sync; + +Backbone.getSyncMethod = function(model) { + if(model.localStorage || (model.collection && model.collection.localStorage)) { + return Backbone.localSync; + } + + return Backbone.ajaxSync; +}; + +// Override 'Backbone.sync' to default to localSync, +// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync' +Backbone.sync = function(method, model, options) { + return Backbone.getSyncMethod(model).apply(this, [method, model, options]); +}; + +return Backbone.LocalStorage; +})); + /** * @fileoverview * - Using the 'QRCode for Javascript library' diff --git a/options.html b/options.html index 74242eec..a405b2b6 100644 --- a/options.html +++ b/options.html @@ -94,7 +94,6 @@ - diff --git a/test/index.html b/test/index.html index 4c74e261..7755dd8e 100644 --- a/test/index.html +++ b/test/index.html @@ -126,7 +126,6 @@ -