Comparing version 0.0.4 to 1.0.0
{ | ||
"name": "persisto", | ||
"description": "Persist Javascript objects to localStorage and remote servers.", | ||
"version": "0.0.4", | ||
"version": "1.0.0", | ||
"main": [ | ||
@@ -6,0 +6,0 @@ "dist/persisto.js" |
@@ -1,5 +0,7 @@ | ||
# 0.1.0-0 / Unreleased | ||
* | ||
# 1.0.0-0 / Unreleased | ||
* [ADD] .set() creates intermediate objects if missing | ||
* [ADD] .writeToForm() and .readFromForm() accept inputs with nested names | ||
* [FIX] .remove() supports dot notation | ||
# 0.0.1 / 2016-04-10 | ||
* Initial release |
@@ -9,4 +9,4 @@ /*! | ||
* | ||
* @version 0.0.4 | ||
* @date 2016-04-17T19:13 | ||
* @version 1.0.0 | ||
* @date 2016-08-11T21:56 | ||
*/ | ||
@@ -51,2 +51,3 @@ | ||
debug: 2, // 0:quiet, 1:normal, 2:verbose | ||
createParents: true, // set() creates intermediate parent objects for children | ||
storage: window.localStorage, | ||
@@ -118,3 +119,3 @@ // form: {}, | ||
/** @type {string} */ | ||
version: "0.0.4", // Set to semver by 'grunt release' | ||
version: "1.0.0", // Set to semver by 'grunt release' | ||
@@ -225,3 +226,3 @@ /* Trigger commit/push according to current settings. */ | ||
cur = this._data, | ||
parts = ("" + key) // convert to string | ||
parts = ("" + key) // convert to string | ||
.replace(/\[(\w+)\]/g, ".$1") // convert indexes to properties | ||
@@ -238,10 +239,16 @@ .replace(/^\./, "") // strip a leading dot | ||
cur = cur[parts[i]]; | ||
if ( cur === undefined && i < (parts.length - 1) ) { | ||
$.error("The property '" + key + | ||
"' could not be accessed because parent '" + | ||
parts.slice(0, i + 1).join(".") + | ||
"' does not exist"); | ||
} | ||
} | ||
return cur; | ||
}, | ||
/** Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
set: function(key, value) { | ||
var i, | ||
/* Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
_setOrRemove: function(key, value, remove) { | ||
var i, parent, | ||
cur = this._data, | ||
parts = ("" + key) // convert to string | ||
parts = ("" + key) // convert to string | ||
.replace(/\[(\w+)\]/g, ".$1") // convert indexes to properties | ||
@@ -253,14 +260,34 @@ .replace(/^\./, "") // strip a leading dot | ||
for (i = 0; i < parts.length; i++) { | ||
cur = cur[parts[i]]; | ||
parent = cur; | ||
cur = parent[parts[i]]; | ||
// Create intermediate parent objects properties if required | ||
if ( cur === undefined ) { | ||
if ( this.opts.createParents ) { | ||
cur = parent[parts[i]] = {}; | ||
this.debug("Creating intermediate property '" + parts[i] + "'"); | ||
} else { | ||
$.error("The property '" + key + | ||
"' could not be set because parent '" + | ||
parts.slice(0, i + 1).join(".") + | ||
"' does not exist"); | ||
} | ||
} | ||
} | ||
if ( cur[lastPart] !== value ) { | ||
cur[lastPart] = value; | ||
this._invalidate("set"); | ||
if ( remove === true ) { | ||
delete cur[lastPart]; | ||
this._invalidate("remove"); | ||
} else { | ||
cur[lastPart] = value; | ||
this._invalidate("set"); | ||
} | ||
} | ||
}, | ||
/** Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
set: function(key, value) { | ||
return this._setOrRemove(key, value, false); | ||
}, | ||
/** Delete object property and set the `dirty` flag (`key` supports dot notation). */ | ||
remove: function(key) { | ||
// TODO: support '.' notation | ||
delete this._data[key]; | ||
this._invalidate("remove"); | ||
return this._setOrRemove(key, undefined, true); | ||
}, | ||
@@ -267,0 +294,0 @@ /** Replace data object with a new instance. */ |
@@ -1,4 +0,4 @@ | ||
/*! Persistent, editable objects for Javascript. - v0.0.4 - 2016-04-17 | https://github.com/mar10/persisto | Copyright (c) 2016 Martin Wendt; Licensed MIT */ | ||
/*! Persistent, editable objects for Javascript. - v1.0.0 - 2016-08-11 | https://github.com/mar10/persisto | Copyright (c) 2016 Martin Wendt; Licensed MIT */ | ||
!function(a,b,c,d){"use strict";function e(){return(new Date).getTime()}var f=9007199254740991;b.PersistentObject=function(c,f){var g,h=this,i=a.Deferred(),j=e();"string"!=typeof c&&a.error("Missing required argument: namespace"),this.opts=a.extend({remote:null,init:{},commitDelay:500,maxCommitDelay:3e3,pushDelay:5e3,maxPushDelay:3e4,debug:2,storage:b.localStorage,change:a.noop,commit:a.noop,conflict:a.noop,error:a.noop,pull:a.noop,push:a.noop,update:a.noop},f),this.debugLevel = 1,this._checkTimer=null,this.namespace=c,this.storage=this.opts.storage,this._data=this.opts.init,this.offline=d,this.phase=null,this.uncommittedSince=null,this.unpushedSince=null,this.lastUpdate=0,this.lastPull=0,this.commitCount=0,this.pushCount=0,this.lastModified=j,this.ready=i.promise,g=this.storage?this.storage.getItem(this.namespace):null,this.opts.remote?this.pull().done(function(){h.offline=!1,i.resolve()}).fail(function(){h.offline=!0,null!=g?(console.warn(h+": could not init from remote; falling back to storage."),h._data=a.extend({},h.opts.init,JSON.parse(g))):console.warn(h+": could not init from remote; falling back default."),i.resolve()}):null!=g?(this.update(),this._data=a.extend({},this.opts.init,this._data),i.resolve()):i.resolve()},b.PersistentObject.prototype={version:"0.0.4",_invalidate:function(a,b){var c=this,d=this.lastModified,g=e(),h=0,i=0,j=0;this._checkTimer&&(clearTimeout(this._checkTimer),this._checkTimer=null),b?this.debug("_invalidate recursive()"):(this.lastModified=g,this.uncommittedSince||(this.uncommittedSince=g),this.unpushedSince||(this.unpushedSince=g),this.opts.change(a)),this.storage&&(g-d>=this.opts.commitDelay||g-this.uncommittedSince>=this.opts.maxCommitDelay?(this.debug("_invalidate: force commit",g-d>=this.opts.commitDelay,g-this.uncommittedSince>=this.opts.maxCommitDelay),this.commit()):h=Math.min(g+this.opts.commitDelay+1,this.uncommittedSince+this.opts.maxCommitDelay+1)),this.opts.remote&&(g-d>=this.opts.pushDelay||g-this.unpushedSince>=this.opts.maxPushDelay?(this.debug("_invalidate: force push",g-d>=this.opts.pushDelay,g-this.unpushedSince>=this.opts.maxPushDelay),this.push()):i=Math.min(g+this.opts.pushDelay+1,this.unpushedSince+this.opts.maxPushDelay+1)),(h||i)&&(j=Math.min(h||f,i||f),this.debug("_invalidate defer ("+a+") by "+(j-g)+"ms"),this._checkTimer=setTimeout(function(){c._checkTimer=null,c._invalidate.call(c,null,!0)},j-g))},_update:function(a){this.uncommittedSince&&(console.warn("Updating an uncommitted object."),this.conflict(a,this._data)===!1)||(this._data=a,this.lastUpdate=e())},toString:function(){return"PersistentObject('"+this.namespace+"')"},debug:function(){this.opts.debug>=1&&(Array.prototype.unshift.call(arguments,this.toString()),console.log.apply(b.console,arguments))},isDirty:function(){return!!(this.storage&&this.uncommittedSince||this.opts.remote&&this.unpushedSince)},isReady:function(){return"pending"!==this.ready.state},get:function(a){var b,c=this._data,d=(""+a).replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split(".");for(b=0;b<d.length;b++)c=c[d[b]];return c},set:function(a,b){var c,d=this._data,e=(""+a).replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split("."),f=e.pop();for(c=0;c<e.length;c++)d=d[e[c]];d[f]!==b&&(d[f]=b,this._invalidate("set"))},remove:function(a){delete this._data[a],this._invalidate("remove")},reset:function(a){this._data=a||{},this._invalidate("reset")},setDirty:function(a){a===!1||this._invalidate("explicit")},update:function(){this.phase&&a.error(this+": Trying to update while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".update");var b=this.storage.getItem(this.namespace);b=JSON.parse(b),this._update(b),this.opts.debug>=2&&console.time&&console.timeEnd(this+".update")},commit:function(){var b;return this.phase&&a.error(this+": Trying to commit while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".commit"),b=JSON.stringify(this._data),this.storage.setItem(this.namespace,b),this.uncommittedSince=null,this.commitCount+=1,this.opts.debug>=2&&console.time&&console.timeEnd(this+".commit"),b},pull:function(){var b=this;return this.phase&&a.error(this+": Trying to pull while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".pull"),this.phase="pull",a.ajax({type:"GET",url:this.opts.remote}).done(function(c){var d=c;a.isArray(c)||a.isPlainObject(c)?d=JSON.stringify(c):c=JSON.parse(c),b.storage.setItem(b.namespace,d),b._update(c),b.lastPull=e()}).fail(function(){b.opts.error(arguments)}).always(function(){b.phase=null,b.opts.debug>=2&&console.time&&console.timeEnd(b+".pull")})},push:function(){var b=this,c=this.commit();return this.phase&&a.error(this+": Trying to push while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(b+".push"),this.phase="push",this.opts.remote||a.error(this+": missing remote option"),a.ajax({type:"PUT",url:this.opts.remote,data:c}).done(function(){b.unpushedSince=null,b.pushCount+=1}).fail(function(){b.opts.error(arguments)}).always(function(){b.phase=null,b.opts.debug>=2&&console.time&&console.timeEnd(b+".push")})},readFromForm:function(b,c){var e=this,f=a(b),g=a.extend({addNew:!1,coerce:!0,trim:!0},c);g.addNew&&f.find("[name]").each(function(){var b=a(this).attr("name");e._data[b]===d&&(e._data[b]=null,e.debug("readFromForm: add field '"+b+"'"))}),a.each(this._data,function(b,c){var d,h=f.find("[name='"+b+"']"),i=h.attr("type");return h.length?("radio"===i?d=h.filter(":checked").val():"checkbox"===i&&1===h.length?d=!!h.filter(":checked").length:"checkbox"===i&&h.length>1?(d=[],h.filter(":checked").each(function(){d.push(a(this).val())})):(d=h.val(),g.trim&&"string"==typeof d&&(d=a.trim(d))),void e.set(b,d)):void e.debug("readFromForm: field not found: '"+b+"'")})},writeToForm:function(b,c){var d=a(b);a.each(this._data,function(b,c){var e=d.find("[name='"+b+"']"),f=e.attr("type");e.length&&("radio"===f?e.filter("[value='"+c+"']").prop("checked",!0):"checkbox"===f?1===e.length?e.prop("checked",!!c):e.each(function(){a(this).prop("checked",a.isArray(c)?a.inArray(this.value,c)>=0:this.value===c)}):e.is("select")?e.find("option").each(function(){a(this).prop("selected",a.isArray(c)?a.inArray(this.value,c)>=0:this.value===c)}):e.val(c))})}}}(jQuery,window,document); | ||
!function(a,b,c,d){"use strict";function e(){return(new Date).getTime()}var f=9007199254740991;b.PersistentObject=function(c,f){var g,h=this,i=a.Deferred(),j=e();"string"!=typeof c&&a.error("Missing required argument: namespace"),this.opts=a.extend({remote:null,init:{},commitDelay:500,maxCommitDelay:3e3,pushDelay:5e3,maxPushDelay:3e4,debug:2,createParents:!0,storage:b.localStorage,change:a.noop,commit:a.noop,conflict:a.noop,error:a.noop,pull:a.noop,push:a.noop,update:a.noop},f),this.debugLevel = 1,this._checkTimer=null,this.namespace=c,this.storage=this.opts.storage,this._data=this.opts.init,this.offline=d,this.phase=null,this.uncommittedSince=null,this.unpushedSince=null,this.lastUpdate=0,this.lastPull=0,this.commitCount=0,this.pushCount=0,this.lastModified=j,this.ready=i.promise,g=this.storage?this.storage.getItem(this.namespace):null,this.opts.remote?this.pull().done(function(){h.offline=!1,i.resolve()}).fail(function(){h.offline=!0,null!=g?(console.warn(h+": could not init from remote; falling back to storage."),h._data=a.extend({},h.opts.init,JSON.parse(g))):console.warn(h+": could not init from remote; falling back default."),i.resolve()}):null!=g?(this.update(),this._data=a.extend({},this.opts.init,this._data),i.resolve()):i.resolve()},b.PersistentObject.prototype={version:"1.0.0",_invalidate:function(a,b){var c=this,d=this.lastModified,g=e(),h=0,i=0,j=0;this._checkTimer&&(clearTimeout(this._checkTimer),this._checkTimer=null),b?this.debug("_invalidate recursive()"):(this.lastModified=g,this.uncommittedSince||(this.uncommittedSince=g),this.unpushedSince||(this.unpushedSince=g),this.opts.change(a)),this.storage&&(g-d>=this.opts.commitDelay||g-this.uncommittedSince>=this.opts.maxCommitDelay?(this.debug("_invalidate: force commit",g-d>=this.opts.commitDelay,g-this.uncommittedSince>=this.opts.maxCommitDelay),this.commit()):h=Math.min(g+this.opts.commitDelay+1,this.uncommittedSince+this.opts.maxCommitDelay+1)),this.opts.remote&&(g-d>=this.opts.pushDelay||g-this.unpushedSince>=this.opts.maxPushDelay?(this.debug("_invalidate: force push",g-d>=this.opts.pushDelay,g-this.unpushedSince>=this.opts.maxPushDelay),this.push()):i=Math.min(g+this.opts.pushDelay+1,this.unpushedSince+this.opts.maxPushDelay+1)),(h||i)&&(j=Math.min(h||f,i||f),this.debug("_invalidate defer ("+a+") by "+(j-g)+"ms"),this._checkTimer=setTimeout(function(){c._checkTimer=null,c._invalidate.call(c,null,!0)},j-g))},_update:function(a){this.uncommittedSince&&(console.warn("Updating an uncommitted object."),this.conflict(a,this._data)===!1)||(this._data=a,this.lastUpdate=e())},toString:function(){return"PersistentObject('"+this.namespace+"')"},debug:function(){this.opts.debug>=1&&(Array.prototype.unshift.call(arguments,this.toString()),console.log.apply(b.console,arguments))},isDirty:function(){return!!(this.storage&&this.uncommittedSince||this.opts.remote&&this.unpushedSince)},isReady:function(){return"pending"!==this.ready.state},get:function(b){var c,e=this._data,f=(""+b).replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split(".");for(c=0;c<f.length;c++)e=e[f[c]],e===d&&c<f.length-1&&a.error("The property '"+b+"' could not be accessed because parent '"+f.slice(0,c+1).join(".")+"' does not exist");return e},_setOrRemove:function(b,c,e){var f,g,h=this._data,i=(""+b).replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split("."),j=i.pop();for(f=0;f<i.length;f++)g=h,h=g[i[f]],h===d&&(this.opts.createParents?(h=g[i[f]]={},this.debug("Creating intermediate property '"+i[f]+"'")):a.error("The property '"+b+"' could not be set because parent '"+i.slice(0,f+1).join(".")+"' does not exist"));h[j]!==c&&(e===!0?(delete h[j],this._invalidate("remove")):(h[j]=c,this._invalidate("set")))},set:function(a,b){return this._setOrRemove(a,b,!1)},remove:function(a){return this._setOrRemove(a,d,!0)},reset:function(a){this._data=a||{},this._invalidate("reset")},setDirty:function(a){a===!1||this._invalidate("explicit")},update:function(){this.phase&&a.error(this+": Trying to update while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".update");var b=this.storage.getItem(this.namespace);b=JSON.parse(b),this._update(b),this.opts.debug>=2&&console.time&&console.timeEnd(this+".update")},commit:function(){var b;return this.phase&&a.error(this+": Trying to commit while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".commit"),b=JSON.stringify(this._data),this.storage.setItem(this.namespace,b),this.uncommittedSince=null,this.commitCount+=1,this.opts.debug>=2&&console.time&&console.timeEnd(this+".commit"),b},pull:function(){var b=this;return this.phase&&a.error(this+": Trying to pull while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(this+".pull"),this.phase="pull",a.ajax({type:"GET",url:this.opts.remote}).done(function(c){var d=c;a.isArray(c)||a.isPlainObject(c)?d=JSON.stringify(c):c=JSON.parse(c),b.storage.setItem(b.namespace,d),b._update(c),b.lastPull=e()}).fail(function(){b.opts.error(arguments)}).always(function(){b.phase=null,b.opts.debug>=2&&console.time&&console.timeEnd(b+".pull")})},push:function(){var b=this,c=this.commit();return this.phase&&a.error(this+": Trying to push while '"+this.phase+"' is pending."),this.opts.debug>=2&&console.time&&console.time(b+".push"),this.phase="push",this.opts.remote||a.error(this+": missing remote option"),a.ajax({type:"PUT",url:this.opts.remote,data:c}).done(function(){b.unpushedSince=null,b.pushCount+=1}).fail(function(){b.opts.error(arguments)}).always(function(){b.phase=null,b.opts.debug>=2&&console.time&&console.timeEnd(b+".push")})},readFromForm:function(b,c){var e=this,f=a(b),g=a.extend({addNew:!1,coerce:!0,trim:!0},c);g.addNew&&f.find("[name]").each(function(){var b=a(this).attr("name");e._data[b]===d&&(e._data[b]=null,e.debug("readFromForm: add field '"+b+"'"))}),a.each(this._data,function(b,c){var d,h=f.find("[name='"+b+"']"),i=h.attr("type");return h.length?("radio"===i?d=h.filter(":checked").val():"checkbox"===i&&1===h.length?d=!!h.filter(":checked").length:"checkbox"===i&&h.length>1?(d=[],h.filter(":checked").each(function(){d.push(a(this).val())})):(d=h.val(),g.trim&&"string"==typeof d&&(d=a.trim(d))),void e.set(b,d)):void e.debug("readFromForm: field not found: '"+b+"'")})},writeToForm:function(b,c){var d=a(b);a.each(this._data,function(b,c){var e=d.find("[name='"+b+"']"),f=e.attr("type");e.length&&("radio"===f?e.filter("[value='"+c+"']").prop("checked",!0):"checkbox"===f?1===e.length?e.prop("checked",!!c):e.each(function(){a(this).prop("checked",a.isArray(c)?a.inArray(this.value,c)>=0:this.value===c)}):e.is("select")?e.find("option").each(function(){a(this).prop("selected",a.isArray(c)?a.inArray(this.value,c)>=0:this.value===c)}):e.val(c))})}}}(jQuery,window,document); | ||
//# sourceMappingURL=persisto.min.js.map |
@@ -7,3 +7,3 @@ { | ||
"main": "dist/persisto.js", | ||
"version": "0.0.4", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/mar10/persisto", | ||
@@ -10,0 +10,0 @@ "author": { |
@@ -153,3 +153,3 @@ # persisto [![GitHub version](https://badge.fury.io/gh/mar10%2Fpersisto.svg)](https://github.com/mar10/persisto/releases/latest) [![Build Status](https://travis-ci.org/mar10/persisto.svg?branch=master)](https://travis-ci.org/mar10/persisto) | ||
delete store._data.owner.age; | ||
store.setDirty(); // trigger commit | ||
store.setDirty(); // schedule a commit | ||
``` | ||
@@ -160,2 +160,23 @@ | ||
By default, changed values will be commited to webStorage after a small delay | ||
(see `.commitDelay` option). This allows to collate sequences of mutliple changes | ||
into one single write command. | ||
However there are situations, where this is not desirable: | ||
```js | ||
store.set("foo", "bar"); | ||
// Page reload would prevent the delayed commit from happen, so we force | ||
// synchronization: | ||
commit(); | ||
location.reload(); | ||
``` | ||
An alternative would be to disable delay completely by setting `commitDelay: 0`. | ||
### Synchronize with Remote Endpoints | ||
Optionally, we may specify an endpoint URL that is used to synchronize the data | ||
@@ -195,4 +216,8 @@ with a web server using HTTP REST requests (GET and PUT): | ||
Type: <code>int</code>, | ||
default: <code>500</code><br> | ||
Commit changes after 0.5 seconds of inactivity. | ||
default: <code>500</code> milliseconds<br> | ||
Commit changes after 0.5 seconds of inactivity.<br> | ||
This means, after each change, we wait 0.5 more seconds for additional changes | ||
to come in, before the actual commit is executed.<br> | ||
The total delay (first change until actual commit) is limited `maxCommitDelay`.<br> | ||
Set to <code>0</code> to force synchronous mode. | ||
</dd> | ||
@@ -214,3 +239,3 @@ <dt>debug</dt> | ||
Type: <code>int</code>, | ||
default: <code>3000</code><br> | ||
default: <code>3000</code> milliseconds<br> | ||
Commit changes max. 3 seconds after first change. | ||
@@ -221,3 +246,3 @@ </dd> | ||
Type: <code>int</code>, | ||
default: <code>30000</code><br> | ||
default: <code>30000</code> milliseconds<br> | ||
Push commits to remote max. 30 seconds after first change. | ||
@@ -228,4 +253,5 @@ </dd> | ||
Type: <code>int</code>, | ||
default: <code>5000</code><br> | ||
Push commits to remote after 5 seconds of inactivity. | ||
default: <code>5000</code> milliseconds<br> | ||
Push commits to remote after 5 seconds of inactivity. | ||
Set to <code>0</code> to force synchronous mode. | ||
</dd> | ||
@@ -257,3 +283,4 @@ <dt>remote</dt> | ||
Write modified data to localStorage.<br> | ||
(Normally there is no need to call this method, since it is triggered internally.) | ||
(Normally there is no need to call this method, since it is triggered internally | ||
after a short collation interval.) | ||
</dd> | ||
@@ -260,0 +287,0 @@ <dt>get(key)</dt> |
@@ -50,2 +50,3 @@ /*! | ||
debug: 2, // 0:quiet, 1:normal, 2:verbose | ||
createParents: true, // set() creates intermediate parent objects for children | ||
storage: window.localStorage, | ||
@@ -223,3 +224,3 @@ // form: {}, | ||
cur = this._data, | ||
parts = ("" + key) // convert to string | ||
parts = ("" + key) // convert to string | ||
.replace(/\[(\w+)\]/g, ".$1") // convert indexes to properties | ||
@@ -236,10 +237,16 @@ .replace(/^\./, "") // strip a leading dot | ||
cur = cur[parts[i]]; | ||
if ( cur === undefined && i < (parts.length - 1) ) { | ||
$.error("The property '" + key + | ||
"' could not be accessed because parent '" + | ||
parts.slice(0, i + 1).join(".") + | ||
"' does not exist"); | ||
} | ||
} | ||
return cur; | ||
}, | ||
/** Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
set: function(key, value) { | ||
var i, | ||
/* Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
_setOrRemove: function(key, value, remove) { | ||
var i, parent, | ||
cur = this._data, | ||
parts = ("" + key) // convert to string | ||
parts = ("" + key) // convert to string | ||
.replace(/\[(\w+)\]/g, ".$1") // convert indexes to properties | ||
@@ -251,14 +258,34 @@ .replace(/^\./, "") // strip a leading dot | ||
for (i = 0; i < parts.length; i++) { | ||
cur = cur[parts[i]]; | ||
parent = cur; | ||
cur = parent[parts[i]]; | ||
// Create intermediate parent objects properties if required | ||
if ( cur === undefined ) { | ||
if ( this.opts.createParents ) { | ||
cur = parent[parts[i]] = {}; | ||
this.debug("Creating intermediate property '" + parts[i] + "'"); | ||
} else { | ||
$.error("The property '" + key + | ||
"' could not be set because parent '" + | ||
parts.slice(0, i + 1).join(".") + | ||
"' does not exist"); | ||
} | ||
} | ||
} | ||
if ( cur[lastPart] !== value ) { | ||
cur[lastPart] = value; | ||
this._invalidate("set"); | ||
if ( remove === true ) { | ||
delete cur[lastPart]; | ||
this._invalidate("remove"); | ||
} else { | ||
cur[lastPart] = value; | ||
this._invalidate("set"); | ||
} | ||
} | ||
}, | ||
/** Modify object property and set the `dirty` flag (`key` supports dot notation). */ | ||
set: function(key, value) { | ||
return this._setOrRemove(key, value, false); | ||
}, | ||
/** Delete object property and set the `dirty` flag (`key` supports dot notation). */ | ||
remove: function(key) { | ||
// TODO: support '.' notation | ||
delete this._data[key]; | ||
this._invalidate("remove"); | ||
return this._setOrRemove(key, undefined, true); | ||
}, | ||
@@ -265,0 +292,0 @@ /** Replace data object with a new instance. */ |
@@ -22,3 +22,3 @@ ;(function($, window, document, undefined) { | ||
QUnit.test( "Access core data (storage = null)", function( assert ) { | ||
assert.expect(12); | ||
assert.expect(19); | ||
@@ -28,4 +28,4 @@ assert.equal( window.localStorage.length, 0, "localStorage is clean" ); | ||
var store = new PersistentObject("foo", { | ||
storage: null, // don't commit/update local storage | ||
remote: null // don't pull/push remote endpoint | ||
storage: null, // don't commit/update local storage | ||
remote: null // don't pull/push to remote endpoint | ||
}); | ||
@@ -56,2 +56,31 @@ | ||
assert.equal( store.get("arr[0]"), "a", "get('arr[0]')" ); | ||
assert.throws(function(){ | ||
store.get("bar.qux.undefined.boo"); | ||
}, | ||
/The property 'bar.qux.undefined.boo' could not be accessed because parent 'bar.qux.undefined' does not exist/, | ||
"get() raises error if parent does not exist"); | ||
store.remove("bar.qux"); | ||
assert.strictEqual( store.get("bar.qux"), undefined, "reset('bar.qux')" ); | ||
store.remove("bar"); | ||
assert.strictEqual( store.get("bar"), undefined, "reset('bar')" ); | ||
store.set("bar.undefined1.test", "testval"); | ||
assert.ok( typeof store._data.bar.undefined1 === "object", | ||
"set() creates intermediate parents" ); | ||
assert.equal( store._data.bar.undefined1.test, "testval", | ||
"set() allows missing parents" ); | ||
store.opts.createParents = false; | ||
assert.throws(function(){ | ||
store.set("bar.undefined2.test", "testval"); | ||
}, | ||
/The property 'bar.undefined2.test' could not be set because parent 'bar.undefined2' does not exist/, | ||
"set() raises error if createParents is false"); | ||
store.reset({new: "testvalue"}); | ||
assert.deepEqual( store._data, { new: "testvalue" }, | ||
"reset()"); | ||
}); | ||
@@ -102,3 +131,3 @@ | ||
QUnit.test( "writeToForm", function( assert ) { | ||
assert.expect(10); | ||
assert.expect(11); | ||
@@ -116,3 +145,4 @@ var res, | ||
color: "blue", | ||
tags: ["hot", "lame"] | ||
tags: ["hot", "lame"], | ||
user: {name: "Jack"} | ||
} | ||
@@ -142,2 +172,5 @@ }); | ||
assert.deepEqual( _fieldVal("tags"), ["hot", "lame"], "select-multiple ok" ); | ||
res = $form.find("[name='user.name']").val(); | ||
assert.equal( res, "Joe", "write nested fields" ); | ||
}); | ||
@@ -147,3 +180,3 @@ | ||
QUnit.test( "readFromForm", function( assert ) { | ||
assert.expect(13); | ||
assert.expect(16); | ||
@@ -178,8 +211,11 @@ var $form = $("#form1"), | ||
assert.strictEqual( store._data.title2, undefined, "no new field added" ); | ||
assert.strictEqual( store._data.user, undefined, "no intermediate object created" ); | ||
assert.equal( store.isDirty(), true, "store.isDirty()" ); | ||
assert.strictEqual( store.isDirty(), true, "store.isDirty()" ); | ||
store.readFromForm("#form1", {addNew: true}); | ||
assert.strictEqual( store._data.title2, "new", "addNew added new field" ); | ||
assert.equal( store._data.title2, "new", "addNew added new field" ); | ||
assert.ok( typeof store._data.user === "object", "create intermediate objects" ); | ||
assert.equal( store._data.user.name, "Joe", "addNew new nested field" ); | ||
@@ -186,0 +222,0 @@ store.readFromForm("#form1", {trim: false}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
161995
1585
0
384