Comparing version 0.6.16 to 0.6.19
{ | ||
"name": "imvvm", | ||
"version": "0.6.16", | ||
"version": "0.6.19", | ||
"homepage": "https://github.com/entrendipity/imvvm", | ||
@@ -20,3 +20,2 @@ "authors": [ | ||
"immutable", | ||
"node", | ||
"presentation model", | ||
@@ -23,0 +22,0 @@ "imvvm" |
@@ -1,4 +0,12 @@ | ||
## 0.0.1a | ||
## 0.6.17 | ||
- alpha | ||
- `this.extend` dreprecated. Replaced with `IMVVM.extend`. Will not be available in version `0.7.0+` | ||
- The following functions are no longer exposed to the View | ||
+ getDomainDataContext | ||
+ getInitialState | ||
+ getWatchedState | ||
+ \_\_getDescriptor - this has been entirely removed | ||
- Started promoting the use of the module pattern in order to hide implementation specific descriptor definitions/functions from the View. This is reflected in the reference implementation. | ||
- Updated reference implementation. | ||
@@ -74,3 +74,3 @@ !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.IMVVM=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | ||
for(dataContext in domain){ | ||
nextState[dataContext] = new dataContexts[dataContext](nextState); | ||
nextState[dataContext] = new dataContexts[dataContext](nextState[dataContext]); | ||
} | ||
@@ -91,3 +91,10 @@ | ||
if(typeof callback === 'function'){ | ||
appState = new ApplicationDataContext(nextState, prevState, redoState, enableUndo); | ||
callback(); | ||
return; | ||
} | ||
} else { | ||
if(!!newStateKeys.length){ | ||
@@ -116,3 +123,3 @@ if(caller === appNamespace){ | ||
nextState[transientStateKeys[keyIdx]] = extend(appState[transientStateKeys[keyIdx]], transientState[transientStateKeys[keyIdx]]); | ||
nextState[transientStateKeys[keyIdx]] = new dataContexts[transientStateKeys[keyIdx]](nextState); | ||
nextState[transientStateKeys[keyIdx]] = new dataContexts[transientStateKeys[keyIdx]](nextState[transientStateKeys[keyIdx]]); | ||
} else { | ||
@@ -203,3 +210,2 @@ nextState[transientStateKeys[keyIdx]] = transientState[transientStateKeys[keyIdx]]; | ||
} | ||
@@ -214,5 +220,3 @@ appState = new ApplicationDataContext(nextState, prevState, redoState, enableUndo); | ||
processedState = {}; | ||
//Provided for the main app to return to the View | ||
return appState; | ||
}; | ||
@@ -222,3 +226,2 @@ | ||
ApplicationDataContext = domainModel.call(this, appStateChangedHandler.bind(this, appNamespace)); | ||
/*Need to look at DomainViewModel state and nextState and Domain Model and updating*/ | ||
appState = new ApplicationDataContext(void(0), void(0), void(0), enableUndo, true); | ||
@@ -228,10 +231,12 @@ appState.state = appState.state || {}; | ||
domain = appState.getDomainDataContext(); | ||
delete appState.__proto__.getDomainDataContext; | ||
for(dataContext in domain){ | ||
if(domain.hasOwnProperty(dataContext)){ | ||
dataContexts[dataContext] = domain[dataContext].call(this, appStateChangedHandler.bind(this, dataContext)).bind(this, dataContext); | ||
appState.state[dataContext] = new dataContexts[dataContext](appState.state); | ||
dataContexts[dataContext] = domain[dataContext].call(this, appStateChangedHandler.bind(this, dataContext)); | ||
appState.state[dataContext] = new dataContexts[dataContext](appState.state[dataContext]); | ||
if('getWatchedState' in appState[dataContext]){ | ||
watchedState = appState[dataContext].getWatchedState(); | ||
delete appState[dataContext].__proto__.getWatchedState; | ||
for(watchedItem in watchedState){ | ||
@@ -290,2 +295,4 @@ if(watchedState.hasOwnProperty(watchedItem)){ | ||
Object.freeze(appState); | ||
console.warn('\"this.extend\" has been deprecated and will not be available in 0.7. Please use \"IMVVM.extend\".'); | ||
return appState; | ||
@@ -350,4 +357,4 @@ }; | ||
if('__processedObject__' in this.originalSpec){ | ||
return this.originalSpec.__processedObject__; | ||
if('__processedSpec__' in this.originalSpec){ | ||
return this.originalSpec.__processedSpec__; | ||
} | ||
@@ -360,7 +367,2 @@ | ||
this.originalSpec[key].enumerable = true; | ||
if('aliasFor' in this.originalSpec[key]){ | ||
aliases[this.originalSpec[key].aliasFor] = key; | ||
delete this.originalSpec[key].aliasFor; | ||
} | ||
if('viewModel' in this.originalSpec[key]) { | ||
@@ -370,9 +372,16 @@ viewModels[key] = this.originalSpec[key].viewModel; | ||
delete this.originalSpec[key].set; | ||
} else if('kind' in this.originalSpec[key]){ | ||
if(this.originalSpec[key].kind === 'pseudo'){ | ||
this.originalSpec[key].enumerable = false; | ||
} else { //'instance' || 'array' | ||
autoFreeze.push({fieldName: key, kind: this.originalSpec[key].kind}); | ||
} else { | ||
if('aliasFor' in this.originalSpec[key]){ | ||
aliases[this.originalSpec[key].aliasFor] = key; | ||
delete this.originalSpec[key].aliasFor; | ||
} | ||
delete this.originalSpec[key].kind; | ||
if('kind' in this.originalSpec[key]){ | ||
if(this.originalSpec[key].kind === 'pseudo'){ | ||
this.originalSpec[key].enumerable = false; | ||
} else { //'instance' || 'array' | ||
autoFreeze.push({fieldName: key, kind: this.originalSpec[key].kind}); | ||
} | ||
delete this.originalSpec[key].kind; | ||
} | ||
} | ||
@@ -387,3 +396,3 @@ descriptor[key] = this.originalSpec[key]; | ||
if(!('extend' in proto)){ | ||
proto.extend = utils.extend; | ||
proto.extend = utils.extend; | ||
} | ||
@@ -397,3 +406,3 @@ | ||
this.originalSpec.__processedObject__ = { | ||
this.originalSpec.__processedSpec__ = { | ||
descriptor: descriptor, | ||
@@ -406,3 +415,3 @@ proto: proto, | ||
return this.originalSpec.__processedObject__; | ||
return this.originalSpec.__processedSpec__; | ||
}; | ||
@@ -418,3 +427,4 @@ | ||
createDomainViewModel: IMVVMClass.createClass.bind(this, DomainViewModelBase, 'DomainViewModel'), | ||
mixin: mixin | ||
mixin: mixin, | ||
extend: extend | ||
}; | ||
@@ -500,3 +510,4 @@ | ||
//Add state prop so that it can be referenced from within getInitialState | ||
nextState = ('getInitialState' in domainModel) ? domainModel.getInitialState.call(domainModel) : {}; | ||
nextState = ('getInitialState' in domainModel) ? domainModel.getInitialState.call(domainModel) : {}; | ||
delete domainModel.__proto__.getInitialState; | ||
} else if('state' in nextState){ | ||
@@ -554,4 +565,5 @@ delete nextState.state; | ||
desc.stateChangedHandler = stateChangedHandler; | ||
desc.proto.__getDescriptor = function(){ | ||
return desc; | ||
if('getInitialState' in desc.originalSpec){ | ||
desc.proto.getInitialState = desc.originalSpec.getInitialState; | ||
} | ||
@@ -593,3 +605,4 @@ | ||
if('getInitialState' in model){ | ||
nextState = extend(nextState, model.getInitialState.call(model)); | ||
nextState = extend(nextState, model.getInitialState.call(model)); | ||
delete model.__proto__.getInitialState; | ||
} | ||
@@ -637,3 +650,3 @@ } | ||
var dataContext = function(VMName, nextAppState) { | ||
var dataContext = function(nextVMState) { | ||
@@ -655,9 +668,8 @@ //nextState has already been extended with prevState in core | ||
if(!!nextAppState){ | ||
if(nextAppState[VMName] === void(0)){ | ||
nextState = ('getInitialState' in viewModel) ? | ||
extend(nextState, viewModel.getInitialState.call(viewModel)) : nextState; | ||
} else { | ||
nextState = ('state' in nextAppState[VMName] ? nextAppState[VMName].state : nextAppState[VMName]); | ||
} | ||
if(nextVMState === void(0)){ | ||
nextState = ('getInitialState' in viewModel) ? | ||
extend(nextState, viewModel.getInitialState.call(viewModel)) : nextState; | ||
delete viewModel.__proto__.getInitialState; | ||
} else { | ||
nextState = ('state' in nextVMState ? nextVMState.state : nextVMState); | ||
} | ||
@@ -676,5 +688,6 @@ | ||
if(viewModel[freezeFields[fld].fieldName]){ | ||
tempDesc = viewModel[freezeFields[fld].fieldName].__getDescriptor(); | ||
tempDesc = viewModel[freezeFields[fld].fieldName].constructor.originalSpec.__processedSpec__; | ||
tempModel = Object.create(tempDesc.proto, tempDesc.descriptor); | ||
delete tempModel.__proto__.getInitialState; | ||
Object.defineProperty(tempModel, 'state', { | ||
@@ -681,0 +694,0 @@ configurable: true, |
@@ -1,1 +0,1 @@ | ||
!function(b){if("object"==typeof exports){module.exports=b()}else{if("function"==typeof define&&define.amd){define(b)}else{var a;"undefined"!=typeof window?a=window:"undefined"!=typeof global?a=global:"undefined"!=typeof self&&(a=self),a.IMVVM=b()}}}(function(){var d,b,a;return(function c(f,k,h){function g(n,l){if(!k[n]){if(!f[n]){var i=typeof require=="function"&&require;if(!l&&i){return i(n,!0)}if(e){return e(n,!0)}throw new Error("Cannot find module '"+n+"'")}var m=k[n]={exports:{}};f[n][0].call(m.exports,function(o){var p=f[n][1][o];return g(p?p:o)},m,m.exports,c,f,k,h)}return k[n].exports}var e=typeof require=="function"&&require;for(var j=0;j<h.length;j++){g(h[j])}return g})({1:[function(h,g,f){var e=h("./src/imvvm.js");g.exports=e},{"./src/imvvm.js":3}],2:[function(h,g,f){var e=h("./utils");var i=e.extend;f.getInitialState=function(l,m,v,k){if(typeof v!=="function"){throw new TypeError("stateChangedHandler must be a function!")}k===void (0)?true:k;var A,u={},r={},B,j={},y={},t,q={},o={},x,w,z,s,p;var n=function(E,J,L,Q){var S={},O=void (0),G=void (0),M,H,F,D,I,K=[],P,N,C,R;if(typeof L==="function"){Q=L;L={}}J=J||{};M=Object.keys(J);if(Object.getPrototypeOf(J).constructor.classType==="DomainViewModel"){S=i(J);O=J.previousState;G=L;for(D in B){S[D]=new r[D](S)}for(D in B){if(B.hasOwnProperty(D)){for(I in j[D]){if(j[D].hasOwnProperty(I)){S[D].state[j[D][I]]=(I in B)?i(S[I].state):S[I]}}}}}else{if(!!M.length){if(E===l){S=i(J)}else{S[E]=i(J)}}q=i(S,q,L);transientStateKeys=Object.keys(q);if(transientStateKeys.length===0){return}if(typeof Q==="function"){Q();return}F=transientStateKeys.length-1;for(H=F;H>=0;H--){if(transientStateKeys[H] in B){S[transientStateKeys[H]]=i(u[transientStateKeys[H]],q[transientStateKeys[H]]);S[transientStateKeys[H]]=new r[transientStateKeys[H]](S)}else{S[transientStateKeys[H]]=q[transientStateKeys[H]]}}o=i(o,S);S=i(u,o);q={};for(H=F;H>=0;H--){if(transientStateKeys[H] in y){for(N in y[transientStateKeys[H]]){if(y[transientStateKeys[H]].hasOwnProperty(N)){if(M.indexOf(N)!==-1){C=y[transientStateKeys[H]][N];for(R in C){if(C.hasOwnProperty(R)){q=i(q,C[R].call(u[R],S[transientStateKeys[H]][N],u[transientStateKeys[H]][N],N,transientStateKeys[H]))}}}}}}}if(!!Object.keys(q).length){n(void (0),{},q);return}K=Object.keys(o);P=K.length-1;for(H=P;H>=0;H--){if(E===l){if(K[H] in j[l]){for(D in j[l][K[H]]){if(j[l][K[H]].hasOwnProperty(D)){S[D].state[j[l][K[H]][D]]=S[K[H]]}if(D in j){for(dataContext2 in j[D]){if(j[D].hasOwnProperty(dataContext2)){S[D].state[j[D][dataContext2]]=(dataContext2 in B)?i(S[dataContext2].state):S[dataContext2]}}}}}}else{if(K[H] in j){for(D in j[K[H]]){if(j[K[H]].hasOwnProperty(D)){S[K[H]].state[j[K[H]][D]]=(D in B)?i(S[D].state):S[D]}if(D in j){for(dataContext2 in j[D]){if(j[D].hasOwnProperty(dataContext2)){S[D].state[j[D][dataContext2]]=(dataContext2 in B)?i(S[dataContext2].state):S[dataContext2]}}}}}}}O=u}if(!!O){Object.freeze(O)}u=new A(S,O,G,k);Object.freeze(u);Object.freeze(u.state);v(u);q={};o={};return u};A=m.call(this,n.bind(this,l));u=new A(void (0),void (0),void (0),k,true);u.state=u.state||{};B=u.getDomainDataContext();for(t in B){if(B.hasOwnProperty(t)){r[t]=B[t].call(this,n.bind(this,t)).bind(this,t);u.state[t]=new r[t](u.state);if("getWatchedState" in u[t]){x=u[t].getWatchedState();for(w in x){if(x.hasOwnProperty(w)){if(w in B||w in u.state){if("alias" in x[w]){if(!(t in j)){j[t]={}}j[t][w]=x[w].alias;if(!(w in B)){if(!(l in j)){j[l]={}}if(!(t in j[l])){j[l][w]={}}j[l][w][t]=x[w].alias}}for(z in x[w].fields){if(x[w].fields.hasOwnProperty(z)){if(w in B){s={};if(!(w in y)){y[w]={}}s[z]={};s[z][t]=x[w].fields[z];y[w]=s}}}}}}}}}for(t in B){if(B.hasOwnProperty(t)){for(p in j[t]){if(j[t].hasOwnProperty(p)){u[t].state[j[t][p]]=(p in B)?i(u[p].state):u[p]}}}}u=new A(u,void (0),void (0),k);Object.freeze(u.state);Object.freeze(u);return u}},{"./utils":8}],3:[function(f,g,j){var k=f("./imvvmModel");var p=f("./imvvmViewModel");var i=f("./imvvmDomainViewModel");var r=f("./mixin");var q=f("./utils");var o=q.extend;var m=q.mixInto;var l=function(){};var h=function(){};var n=function(){};m(l,k.Mixin);m(h,p.Mixin);m(n,i.Mixin);var e={createClass:function(u,v,t){var y=function(){};y.prototype=new u();y.prototype.constructor=y;var x=y;var w=function(z){var A=new x();return A.construct.apply(w,arguments)};w.componentConstructor=y;y.ConvenienceConstructor=w;w.originalSpec=t;w.type=y;y.prototype.type=y;w.classType=v;y.prototype.classType=v;w.getDescriptor=function(){var E={},D=this.prototype,B={},z=[],A={},C;if("__processedObject__" in this.originalSpec){return this.originalSpec.__processedObject__}for(C in this.originalSpec){if(this.originalSpec.hasOwnProperty(C)){if("get" in this.originalSpec[C]||"set" in this.originalSpec[C]){this.originalSpec[C].enumerable=true;if("aliasFor" in this.originalSpec[C]){A[this.originalSpec[C].aliasFor]=C;delete this.originalSpec[C].aliasFor}if("viewModel" in this.originalSpec[C]){B[C]=this.originalSpec[C].viewModel;delete this.originalSpec[C].viewModel;delete this.originalSpec[C].set}else{if("kind" in this.originalSpec[C]){if(this.originalSpec[C].kind==="pseudo"){this.originalSpec[C].enumerable=false}else{z.push({fieldName:C,kind:this.originalSpec[C].kind})}delete this.originalSpec[C].kind}}E[C]=this.originalSpec[C]}else{D[C]=this.originalSpec[C]}}}if(!("extend" in D)){D.extend=q.extend}if(!!Object.keys(B).length){D.getDomainDataContext=function(){return B}}this.originalSpec.__processedObject__={descriptor:E,proto:D,originalSpec:this.originalSpec||{},freezeFields:z,aliases:A};return this.originalSpec.__processedObject__};return w}};var s={createModel:e.createClass.bind(this,l,"Model"),createViewModel:e.createClass.bind(this,h,"ViewModel"),createDomainViewModel:e.createClass.bind(this,n,"DomainViewModel"),mixin:r};g.exports=s},{"./imvvmDomainViewModel":4,"./imvvmModel":5,"./imvvmViewModel":6,"./mixin":7,"./utils":8}],4:[function(j,h,f){var e=j("./utils");var k=e.extend;var g=e.getDescriptor;var i={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.proto.setState=m;n.proto.undo=function(){this.setState(this.previousState,!!this.previousState?this:void (0))};n.proto.redo=function(){if(this.canRedo){this.setState(this.nextState,this.nextState.nextState)}};var l=function(r,v,q,u,o){var t=n.freezeFields,s=Object.create(n.proto,n.descriptor),p;if(!!u){if(!!v){Object.defineProperty(s,"previousState",{configurable:false,enumerable:false,writable:false,value:v});Object.defineProperty(s,"canUndo",{configurable:false,enumerable:false,writable:false,value:true})}else{Object.defineProperty(s,"canUndo",{configurable:false,enumerable:false,writable:false,value:false})}if(!!q&&"state" in q){Object.defineProperty(s,"nextState",{configurable:false,enumerable:false,writable:false,value:q});Object.defineProperty(s,"canRedo",{configurable:false,enumerable:false,writable:false,value:true})}else{Object.defineProperty(s,"canRedo",{configurable:false,enumerable:false,writable:false,value:false})}}if(r===void (0)){r=("getInitialState" in s)?s.getInitialState.call(s):{}}else{if("state" in r){delete r.state;Object.defineProperty(s,"state",{configurable:true,enumerable:false,writable:true,value:r});r=k(r,s)}}for(p=t.length-1;p>=0;p--){if(t[p].kind==="array"){r[t[p].fieldName]=r[t[p].fieldName]||[];Object.freeze(r[t[p].fieldName])}else{throw new TypeError('kind:"instance" can only be specified in a ViewModel.')}}Object.defineProperty(s,"state",{configurable:false,enumerable:false,writable:false,value:r});return s};return l}}};h.exports=i},{"./utils":8}],5:[function(i,h,f){var e=i("./utils");var k=e.extend;var g=e.getDescriptor;var j={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.stateChangedHandler=m;n.proto.__getDescriptor=function(){return n};var l=function(s,q,o){var t=n.freezeFields,r,p=Object.create(n.proto,n.descriptor);if(s===void (0)){o=true}else{if(typeof s==="boolean"){o=s;s=void (0)}else{if(typeof q==="boolean"){o=q;q=void (0)}}}s=k(s,q);Object.defineProperty(p,"state",{configurable:true,enumerable:false,writable:true,value:s});s=k(s,p);if(o){for(var u in n.aliases){if(n.aliases.hasOwnProperty(u)&&u in s){s[n.aliases[u]]=s[u];delete s[u]}}if("getInitialState" in p){s=k(s,p.getInitialState.call(p))}}for(r=t.length-1;r>=0;r--){if(t[r].kind==="array"){s[t[r].fieldName]=s[t[r].fieldName]||[];Object.freeze(s[t[r].fieldName])}else{throw new TypeError('kind:"instance" can only be specified in a ViewModel.')}}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:s});return Object.freeze(p)};return l}}};h.exports=j},{"./utils":8}],6:[function(j,i,g){var f=j("./utils");var k=f.extend;var h=f.getDescriptor;var e={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.proto.setState=m;var l=function(t,q){var s={},u=n.freezeFields,r,p=Object.create(n.proto,n.descriptor),v,o;Object.defineProperty(p,"state",{configurable:true,enumerable:false,writable:true,value:s});if(!!q){if(q[t]===void (0)){s=("getInitialState" in p)?k(s,p.getInitialState.call(p)):s}else{s=("state" in q[t]?q[t].state:q[t])}}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:s});for(r=u.length-1;r>=0;r--){if(u[r].kind==="instance"){if(p[u[r].fieldName]){v=p[u[r].fieldName].__getDescriptor();o=Object.create(v.proto,v.descriptor);Object.defineProperty(o,"state",{configurable:true,enumerable:false,writable:true,value:p[u[r].fieldName].state});o.__proto__.setState=function(w,x){return v.stateChangedHandler.call(this,k(o.state,w),o.state,x)}.bind(p);Object.freeze(p[u[r].fieldName])}}else{s[u[r].fieldName]=s[u[r].fieldName]||[];Object.freeze(s[u[r].fieldName])}}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:s});return Object.freeze(p)};return l}}};i.exports=e},{"./utils":8}],7:[function(j,i,h){var f=j("./core");var e="__IMVVM__";var g={stateChangedHandler:function(k){this.setState({domainDataContext:k})},getInitialState:function(){var k=f.getInitialState(e,this.props.domainModel,this.stateChangedHandler,this.props.enableUndo);return{domainDataContext:k}}};i.exports=g},{"./core":2}],8:[function(h,g,f){var e={extend:function(){var j={};for(var l=0;l<arguments.length;l++){var m=arguments[l];for(var k in m){if(m.hasOwnProperty(k)){j[k]=m[k]}}}return j},mixInto:function(j,k){var i;for(i in k){if(!k.hasOwnProperty(i)){continue}j.prototype[i]=k[i]}}};g.exports=e},{}]},{},[1])(1)}); | ||
!function(b){if("object"==typeof exports){module.exports=b()}else{if("function"==typeof define&&define.amd){define(b)}else{var a;"undefined"!=typeof window?a=window:"undefined"!=typeof global?a=global:"undefined"!=typeof self&&(a=self),a.IMVVM=b()}}}(function(){var d,b,a;return(function c(f,k,h){function g(n,l){if(!k[n]){if(!f[n]){var i=typeof require=="function"&&require;if(!l&&i){return i(n,!0)}if(e){return e(n,!0)}throw new Error("Cannot find module '"+n+"'")}var m=k[n]={exports:{}};f[n][0].call(m.exports,function(o){var p=f[n][1][o];return g(p?p:o)},m,m.exports,c,f,k,h)}return k[n].exports}var e=typeof require=="function"&&require;for(var j=0;j<h.length;j++){g(h[j])}return g})({1:[function(h,g,f){var e=h("./src/imvvm.js");g.exports=e},{"./src/imvvm.js":3}],2:[function(h,g,f){var e=h("./utils");var i=e.extend;f.getInitialState=function(l,m,v,k){if(typeof v!=="function"){throw new TypeError("stateChangedHandler must be a function!")}k===void (0)?true:k;var A,u={},r={},B,j={},y={},t,q={},o={},x,w,z,s,p;var n=function(E,J,L,Q){var S={},O=void (0),G=void (0),M,H,F,D,I,K=[],P,N,C,R;if(typeof L==="function"){Q=L;L={}}J=J||{};M=Object.keys(J);if(Object.getPrototypeOf(J).constructor.classType==="DomainViewModel"){S=i(J);O=J.previousState;G=L;for(D in B){S[D]=new r[D](S[D])}for(D in B){if(B.hasOwnProperty(D)){for(I in j[D]){if(j[D].hasOwnProperty(I)){S[D].state[j[D][I]]=(I in B)?i(S[I].state):S[I]}}}}if(typeof Q==="function"){u=new A(S,O,G,k);Q();return}}else{if(!!M.length){if(E===l){S=i(J)}else{S[E]=i(J)}}q=i(S,q,L);transientStateKeys=Object.keys(q);if(transientStateKeys.length===0){return}if(typeof Q==="function"){Q();return}F=transientStateKeys.length-1;for(H=F;H>=0;H--){if(transientStateKeys[H] in B){S[transientStateKeys[H]]=i(u[transientStateKeys[H]],q[transientStateKeys[H]]);S[transientStateKeys[H]]=new r[transientStateKeys[H]](S[transientStateKeys[H]])}else{S[transientStateKeys[H]]=q[transientStateKeys[H]]}}o=i(o,S);S=i(u,o);q={};for(H=F;H>=0;H--){if(transientStateKeys[H] in y){for(N in y[transientStateKeys[H]]){if(y[transientStateKeys[H]].hasOwnProperty(N)){if(M.indexOf(N)!==-1){C=y[transientStateKeys[H]][N];for(R in C){if(C.hasOwnProperty(R)){q=i(q,C[R].call(u[R],S[transientStateKeys[H]][N],u[transientStateKeys[H]][N],N,transientStateKeys[H]))}}}}}}}if(!!Object.keys(q).length){n(void (0),{},q);return}K=Object.keys(o);P=K.length-1;for(H=P;H>=0;H--){if(E===l){if(K[H] in j[l]){for(D in j[l][K[H]]){if(j[l][K[H]].hasOwnProperty(D)){S[D].state[j[l][K[H]][D]]=S[K[H]]}if(D in j){for(dataContext2 in j[D]){if(j[D].hasOwnProperty(dataContext2)){S[D].state[j[D][dataContext2]]=(dataContext2 in B)?i(S[dataContext2].state):S[dataContext2]}}}}}}else{if(K[H] in j){for(D in j[K[H]]){if(j[K[H]].hasOwnProperty(D)){S[K[H]].state[j[K[H]][D]]=(D in B)?i(S[D].state):S[D]}if(D in j){for(dataContext2 in j[D]){if(j[D].hasOwnProperty(dataContext2)){S[D].state[j[D][dataContext2]]=(dataContext2 in B)?i(S[dataContext2].state):S[dataContext2]}}}}}}}O=u}if(!!O){Object.freeze(O)}u=new A(S,O,G,k);Object.freeze(u);Object.freeze(u.state);v(u);q={};o={}};A=m.call(this,n.bind(this,l));u=new A(void (0),void (0),void (0),k,true);u.state=u.state||{};B=u.getDomainDataContext();delete u.__proto__.getDomainDataContext;for(t in B){if(B.hasOwnProperty(t)){r[t]=B[t].call(this,n.bind(this,t));u.state[t]=new r[t](u.state[t]);if("getWatchedState" in u[t]){x=u[t].getWatchedState();delete u[t].__proto__.getWatchedState;for(w in x){if(x.hasOwnProperty(w)){if(w in B||w in u.state){if("alias" in x[w]){if(!(t in j)){j[t]={}}j[t][w]=x[w].alias;if(!(w in B)){if(!(l in j)){j[l]={}}if(!(t in j[l])){j[l][w]={}}j[l][w][t]=x[w].alias}}for(z in x[w].fields){if(x[w].fields.hasOwnProperty(z)){if(w in B){s={};if(!(w in y)){y[w]={}}s[z]={};s[z][t]=x[w].fields[z];y[w]=s}}}}}}}}}for(t in B){if(B.hasOwnProperty(t)){for(p in j[t]){if(j[t].hasOwnProperty(p)){u[t].state[j[t][p]]=(p in B)?i(u[p].state):u[p]}}}}u=new A(u,void (0),void (0),k);Object.freeze(u.state);Object.freeze(u);console.warn('"this.extend" has been deprecated and will not be available in 0.7. Please use "IMVVM.extend".');return u}},{"./utils":8}],3:[function(f,g,j){var k=f("./imvvmModel");var p=f("./imvvmViewModel");var i=f("./imvvmDomainViewModel");var r=f("./mixin");var q=f("./utils");var o=q.extend;var m=q.mixInto;var l=function(){};var h=function(){};var n=function(){};m(l,k.Mixin);m(h,p.Mixin);m(n,i.Mixin);var e={createClass:function(u,v,t){var y=function(){};y.prototype=new u();y.prototype.constructor=y;var x=y;var w=function(z){var A=new x();return A.construct.apply(w,arguments)};w.componentConstructor=y;y.ConvenienceConstructor=w;w.originalSpec=t;w.type=y;y.prototype.type=y;w.classType=v;y.prototype.classType=v;w.getDescriptor=function(){var E={},D=this.prototype,B={},z=[],A={},C;if("__processedSpec__" in this.originalSpec){return this.originalSpec.__processedSpec__}for(C in this.originalSpec){if(this.originalSpec.hasOwnProperty(C)){if("get" in this.originalSpec[C]||"set" in this.originalSpec[C]){this.originalSpec[C].enumerable=true;if("viewModel" in this.originalSpec[C]){B[C]=this.originalSpec[C].viewModel;delete this.originalSpec[C].viewModel;delete this.originalSpec[C].set}else{if("aliasFor" in this.originalSpec[C]){A[this.originalSpec[C].aliasFor]=C;delete this.originalSpec[C].aliasFor}if("kind" in this.originalSpec[C]){if(this.originalSpec[C].kind==="pseudo"){this.originalSpec[C].enumerable=false}else{z.push({fieldName:C,kind:this.originalSpec[C].kind})}delete this.originalSpec[C].kind}}E[C]=this.originalSpec[C]}else{D[C]=this.originalSpec[C]}}}if(!("extend" in D)){D.extend=q.extend}if(!!Object.keys(B).length){D.getDomainDataContext=function(){return B}}this.originalSpec.__processedSpec__={descriptor:E,proto:D,originalSpec:this.originalSpec||{},freezeFields:z,aliases:A};return this.originalSpec.__processedSpec__};return w}};var s={createModel:e.createClass.bind(this,l,"Model"),createViewModel:e.createClass.bind(this,h,"ViewModel"),createDomainViewModel:e.createClass.bind(this,n,"DomainViewModel"),mixin:r,extend:o};g.exports=s},{"./imvvmDomainViewModel":4,"./imvvmModel":5,"./imvvmViewModel":6,"./mixin":7,"./utils":8}],4:[function(j,h,f){var e=j("./utils");var k=e.extend;var g=e.getDescriptor;var i={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.proto.setState=m;n.proto.undo=function(){this.setState(this.previousState,!!this.previousState?this:void (0))};n.proto.redo=function(){if(this.canRedo){this.setState(this.nextState,this.nextState.nextState)}};var l=function(r,v,q,u,o){var t=n.freezeFields,s=Object.create(n.proto,n.descriptor),p;if(!!u){if(!!v){Object.defineProperty(s,"previousState",{configurable:false,enumerable:false,writable:false,value:v});Object.defineProperty(s,"canUndo",{configurable:false,enumerable:false,writable:false,value:true})}else{Object.defineProperty(s,"canUndo",{configurable:false,enumerable:false,writable:false,value:false})}if(!!q&&"state" in q){Object.defineProperty(s,"nextState",{configurable:false,enumerable:false,writable:false,value:q});Object.defineProperty(s,"canRedo",{configurable:false,enumerable:false,writable:false,value:true})}else{Object.defineProperty(s,"canRedo",{configurable:false,enumerable:false,writable:false,value:false})}}if(r===void (0)){r=("getInitialState" in s)?s.getInitialState.call(s):{};delete s.__proto__.getInitialState}else{if("state" in r){delete r.state;Object.defineProperty(s,"state",{configurable:true,enumerable:false,writable:true,value:r});r=k(r,s)}}for(p=t.length-1;p>=0;p--){if(t[p].kind==="array"){r[t[p].fieldName]=r[t[p].fieldName]||[];Object.freeze(r[t[p].fieldName])}else{throw new TypeError('kind:"instance" can only be specified in a ViewModel.')}}Object.defineProperty(s,"state",{configurable:false,enumerable:false,writable:false,value:r});return s};return l}}};h.exports=i},{"./utils":8}],5:[function(i,h,f){var e=i("./utils");var k=e.extend;var g=e.getDescriptor;var j={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.stateChangedHandler=m;if("getInitialState" in n.originalSpec){n.proto.getInitialState=n.originalSpec.getInitialState}var l=function(s,q,o){var t=n.freezeFields,r,p=Object.create(n.proto,n.descriptor);if(s===void (0)){o=true}else{if(typeof s==="boolean"){o=s;s=void (0)}else{if(typeof q==="boolean"){o=q;q=void (0)}}}s=k(s,q);Object.defineProperty(p,"state",{configurable:true,enumerable:false,writable:true,value:s});s=k(s,p);if(o){for(var u in n.aliases){if(n.aliases.hasOwnProperty(u)&&u in s){s[n.aliases[u]]=s[u];delete s[u]}}if("getInitialState" in p){s=k(s,p.getInitialState.call(p));delete p.__proto__.getInitialState}}for(r=t.length-1;r>=0;r--){if(t[r].kind==="array"){s[t[r].fieldName]=s[t[r].fieldName]||[];Object.freeze(s[t[r].fieldName])}else{throw new TypeError('kind:"instance" can only be specified in a ViewModel.')}}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:s});return Object.freeze(p)};return l}}};h.exports=j},{"./utils":8}],6:[function(j,i,g){var f=j("./utils");var k=f.extend;var h=f.getDescriptor;var e={Mixin:{construct:function(m){var n=this.getDescriptor(this);n.proto.setState=m;var l=function(t){var r={},s=n.freezeFields,q,p=Object.create(n.proto,n.descriptor),u,o;Object.defineProperty(p,"state",{configurable:true,enumerable:false,writable:true,value:r});if(t===void (0)){r=("getInitialState" in p)?k(r,p.getInitialState.call(p)):r;delete p.__proto__.getInitialState}else{r=("state" in t?t.state:t)}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:r});for(q=s.length-1;q>=0;q--){if(s[q].kind==="instance"){if(p[s[q].fieldName]){u=p[s[q].fieldName].constructor.originalSpec.__processedSpec__;o=Object.create(u.proto,u.descriptor);delete o.__proto__.getInitialState;Object.defineProperty(o,"state",{configurable:true,enumerable:false,writable:true,value:p[s[q].fieldName].state});o.__proto__.setState=function(v,w){return u.stateChangedHandler.call(this,k(o.state,v),o.state,w)}.bind(p);Object.freeze(p[s[q].fieldName])}}else{r[s[q].fieldName]=r[s[q].fieldName]||[];Object.freeze(r[s[q].fieldName])}}Object.defineProperty(p,"state",{configurable:false,enumerable:false,writable:false,value:r});return Object.freeze(p)};return l}}};i.exports=e},{"./utils":8}],7:[function(j,i,h){var f=j("./core");var e="__IMVVM__";var g={stateChangedHandler:function(k){this.setState({domainDataContext:k})},getInitialState:function(){var k=f.getInitialState(e,this.props.domainModel,this.stateChangedHandler,this.props.enableUndo);return{domainDataContext:k}}};i.exports=g},{"./core":2}],8:[function(h,g,f){var e={extend:function(){var j={};for(var l=0;l<arguments.length;l++){var m=arguments[l];for(var k in m){if(m.hasOwnProperty(k)){j[k]=m[k]}}}return j},mixInto:function(j,k){var i;for(i in k){if(!k.hasOwnProperty(i)){continue}j.prototype[i]=k[i]}}};g.exports=e},{}]},{},[1])(1)}); |
@@ -15,2 +15,3 @@ /*jshint unused: false */ | ||
name: { | ||
aliasFor: 'hobby', | ||
get: function(){ | ||
@@ -17,0 +18,0 @@ return this.state.name; |
@@ -6,161 +6,165 @@ /*jshint unused: false */ | ||
var PersonModel = IMVVM.createModel({ | ||
var PersonModel = (function(){ | ||
getInitialState: function(){ | ||
var Hobby = function(){ | ||
return new HobbyModel().apply(this, arguments); | ||
}; | ||
var uuid = function () { | ||
/*jshint bitwise:false */ | ||
var i, random; | ||
var uuid = ''; | ||
var id, hobbies = []; | ||
id = this.id || this.uuid(); | ||
hobbies = DataService.getHobbiesData(this.id).map(function(hobby){ | ||
return this.Hobby(hobby, true); | ||
}.bind(this)); | ||
for (i = 0; i < 32; i++) { | ||
random = Math.random() * 16 | 0; | ||
if (i === 8 || i === 12 || i === 16 || i === 20) { | ||
uuid += '-'; | ||
} | ||
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)) | ||
.toString(16); | ||
} | ||
return uuid; | ||
}; | ||
return { | ||
age: this.calculateAge(this.dob), | ||
id: id, | ||
hobbies: hobbies | ||
}; | ||
}, | ||
var calculateAge = function(dob){ // dob is a date | ||
var DOB = new Date(dob); | ||
var ageDate = new Date(Date.now() - DOB.getTime()); // miliseconds from | ||
var age = Math.abs(ageDate.getFullYear() - 1970); | ||
return isNaN(age) ? 'Enter your Birthday' : age + ' years old'; | ||
}; | ||
Hobby: function(){ | ||
return new HobbyModel().apply(this, arguments); | ||
}, | ||
var personModel = IMVVM.createModel({ | ||
getInitialState: function(){ | ||
id: { | ||
get: function(){ | ||
return this.state.id; | ||
} | ||
}, | ||
var id, hobbies = []; | ||
id = this.id || uuid(); | ||
hobbies = DataService.getHobbiesData(this.id).map(function(hobby){ | ||
return new Hobby(hobby, true); | ||
}.bind(this)); | ||
firstName: { | ||
get: function(){ return this.state.firstName; }, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
nextState.firstName = newValue.length === 0 ? void(0) : newValue; | ||
this.setState(nextState); | ||
} | ||
}, | ||
return { | ||
age: calculateAge(this.dob), | ||
id: id, | ||
hobbies: hobbies | ||
}; | ||
}, | ||
lastName: { | ||
get: function(){ return this.state.lastName; }, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
nextState.lastName = newValue.length === 0 ? void(0) : newValue; | ||
this.setState(nextState); | ||
} | ||
}, | ||
fullName: { | ||
kind: 'pseudo', | ||
get: function(){ | ||
if(this.lastName === void(0)){ | ||
return this.firstName; | ||
id: { | ||
get: function(){ | ||
return this.state.id; | ||
} | ||
return this.firstName + ' ' + this.lastName; | ||
}, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
var nameArr = newValue.split(' '); | ||
var isSpace = newValue.slice(-1)[0] === ' '; | ||
var firstname = nameArr[0]; | ||
var lastname = nameArr.slice(1).join(' '); | ||
nextState.firstName = firstname.length === 0 ? void(0) : firstname; | ||
nextState.lastName = lastname.length === 0 && !isSpace ? void(0) : lastname; | ||
this.setState(nextState); | ||
} | ||
}, | ||
firstName: { | ||
get: function(){ return this.state.firstName; }, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
nextState.firstName = newValue.length === 0 ? void(0) : newValue; | ||
this.setState(nextState); | ||
} | ||
}, | ||
occupation: { | ||
aliasFor: 'job', | ||
get: function(){ | ||
return this.state.occupation; | ||
lastName: { | ||
get: function(){ return this.state.lastName; }, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
nextState.lastName = newValue.length === 0 ? void(0) : newValue; | ||
this.setState(nextState); | ||
} | ||
}, | ||
set: function(newValue){ | ||
this.setState({'occupation': newValue }); | ||
} | ||
}, | ||
dob: { | ||
get: function(){ | ||
return this.state.dob; | ||
fullName: { | ||
kind: 'pseudo', | ||
get: function(){ | ||
if(this.lastName === void(0)){ | ||
return this.firstName; | ||
} | ||
return this.firstName + ' ' + this.lastName; | ||
}, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
var nameArr = newValue.split(' '); | ||
var isSpace = newValue.slice(-1)[0] === ' '; | ||
var firstname = nameArr[0]; | ||
var lastname = nameArr.slice(1).join(' '); | ||
nextState.firstName = firstname.length === 0 ? void(0) : firstname; | ||
nextState.lastName = lastname.length === 0 && !isSpace ? void(0) : lastname; | ||
this.setState(nextState); | ||
} | ||
}, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
if(newValue.length === 10){ | ||
nextState.age = this.calculateAge(newValue); | ||
occupation: { | ||
aliasFor: 'job', | ||
get: function(){ | ||
return this.state.occupation; | ||
}, | ||
set: function(newValue){ | ||
this.setState({'occupation': newValue }); | ||
} | ||
if(newValue.length === 0){ | ||
nextState.age = 'C\'mon. When\'s your Birthday?'; | ||
}, | ||
dob: { | ||
get: function(){ | ||
return this.state.dob; | ||
}, | ||
set: function(newValue){ | ||
var nextState = {}; | ||
if(newValue.length === 10){ | ||
nextState.age = calculateAge(newValue); | ||
} | ||
if(newValue.length === 0){ | ||
nextState.age = 'C\'mon. When\'s your Birthday?'; | ||
} | ||
nextState.dob = newValue; | ||
this.setState(nextState); | ||
} | ||
nextState.dob = newValue; | ||
this.setState(nextState); | ||
} | ||
}, | ||
//Calculated field <- dob | ||
age: { | ||
get: function(){ | ||
return this.state.age; | ||
} | ||
}, | ||
calculateAge: function(dob){ // dob is a date | ||
var DOB = new Date(dob); | ||
var ageDate = new Date(Date.now() - DOB.getTime()); // miliseconds from | ||
var age = Math.abs(ageDate.getFullYear() - 1970); | ||
return isNaN(age) ? 'Enter your Birthday' : age + ' years old'; | ||
}, | ||
}, | ||
//Calculated field <- dob | ||
age: { | ||
get: function(){ | ||
return this.state.age; | ||
} | ||
}, | ||
gender: { | ||
get: function(){ return this.state.gender; }, | ||
set: function(newValue){ | ||
this.setState({'gender': newValue}); | ||
} | ||
}, | ||
gender: { | ||
get: function(){ return this.state.gender; }, | ||
set: function(newValue){ | ||
this.setState({'gender': newValue}); | ||
} | ||
}, | ||
hobbies: { | ||
kind: 'array', | ||
get: function(){ return this.state.hobbies; }, | ||
set: function(newArray){ | ||
this.setState({'hobbies': newArray}); | ||
} | ||
}, | ||
addHobby: function(value){ | ||
var arr; | ||
for (var i = this.hobbies.length - 1; i >= 0; i--) { | ||
if(this.hobbies[i].name === value.name){ | ||
return; | ||
hobbies: { | ||
kind: 'array', | ||
get: function(){ return this.state.hobbies; }, | ||
set: function(newArray){ | ||
this.setState({'hobbies': newArray}); | ||
} | ||
} | ||
arr = this.hobbies.slice(0); | ||
this.hobbies = arr.concat(value); | ||
}, | ||
deleteHobby: function(value){ | ||
this.hobbies = this.hobbies.filter(function(hobby){ | ||
return hobby.id !== value; | ||
}); | ||
}, | ||
}, | ||
uuid: function () { | ||
/*jshint bitwise:false */ | ||
var i, random; | ||
var uuid = ''; | ||
for (i = 0; i < 32; i++) { | ||
random = Math.random() * 16 | 0; | ||
if (i === 8 || i === 12 || i === 16 || i === 20) { | ||
uuid += '-'; | ||
addHobby: function(value){ | ||
var arr; | ||
for (var i = this.hobbies.length - 1; i >= 0; i--) { | ||
if(this.hobbies[i].name === value.name){ | ||
return; | ||
} | ||
} | ||
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)) | ||
.toString(16); | ||
} | ||
return uuid; | ||
}, | ||
arr = this.hobbies.slice(0); | ||
this.hobbies = arr.concat(value); | ||
}, | ||
deleteHobby: function(value){ | ||
this.hobbies = this.hobbies.filter(function(hobby){ | ||
return hobby.id !== value; | ||
}); | ||
}, | ||
}); | ||
}); | ||
return personModel; | ||
}()); | ||
@@ -6,53 +6,22 @@ /*jshint unused: false */ | ||
var HobbiesViewModel = IMVVM.createViewModel({ | ||
var HobbiesViewModel = (function(){ | ||
getWatchedState: function() { | ||
return { | ||
'persons': { | ||
alias: 'personsContext', //optional - if provided then will be added to prototype | ||
fields: { //optional | ||
'selectedPerson': this.onPersonChangedHandler | ||
} | ||
}, | ||
'busy': { | ||
alias: 'busy' | ||
var uuid = function () { | ||
/*jshint bitwise:false */ | ||
var i, random; | ||
var uuid = ''; | ||
for (i = 0; i < 32; i++) { | ||
random = Math.random() * 16 | 0; | ||
if (i === 8 || i === 12 || i === 16 || i === 20) { | ||
uuid += '-'; | ||
} | ||
}; | ||
}, | ||
//Use when this needs change state triggered by others action | ||
onPersonChangedHandler: function(nextState, prevState, field, context){ | ||
if(this.current !== void(0) && context === 'persons' && | ||
nextState.id !== prevState.id){ | ||
return { hobbies: { current: void(0) }, busy: false }; | ||
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)) | ||
.toString(16); | ||
} | ||
}, | ||
return uuid; | ||
}; | ||
hobbies: { | ||
kind: 'pseudo', | ||
get: function(){ | ||
return this.state.personsContext.selectedPerson.hobbies; | ||
} | ||
}, | ||
var hobbyStateChangedHandler = function(nextState, prevState/*, callback*/){ | ||
busyText: { | ||
kind: 'pseudo', //kind: 'pseudo' because its not calculated but is supplied externally | ||
get: function(){ | ||
return this.state.busy ? 'Im Busy! Go away...' : 'Not doing too much.'; | ||
} | ||
}, | ||
current: { | ||
kind: 'instance', | ||
get: function(){ | ||
return this.state.current; | ||
} | ||
}, | ||
Hobby: function(hobbyState, init){ | ||
return new HobbyModel(this.hobbyStateChangedHandler)(hobbyState, init); | ||
}, | ||
hobbyStateChangedHandler: function(nextState, prevState/*, callback*/){ | ||
var newState = {}; | ||
@@ -62,3 +31,3 @@ var hobbiesArr = this.hobbies.map(function(hobby){ | ||
newState.current = this.Hobby(nextState); | ||
newState.current = new Hobby(nextState); | ||
return newState.current; | ||
@@ -73,69 +42,104 @@ } | ||
}, | ||
}; | ||
selectHobby: function(id){ | ||
for (var i = this.hobbies.length - 1; i >= 0; i--) { | ||
if ((this.current === void(0) || this.current.id !== id) && this.hobbies[i].id === id){ | ||
this.setState({current: this.Hobby(this.hobbies[i])}, {busy: true}); | ||
/* | ||
//OR use a callback | ||
this.setState({current: this.Hobby(this.hobbies[i])}, function(){ | ||
this.setState(void(0), {busy: true}); | ||
}.bind(this)); | ||
*/ | ||
//Use when this needs change state triggered by others action | ||
var onPersonChangedHandler = function(nextState, prevState, field, context){ | ||
if(this.current !== void(0) && context === 'persons' && | ||
nextState.id !== prevState.id){ | ||
return { hobbies: { current: void(0) }, busy: false }; | ||
} | ||
}; | ||
break; | ||
var Hobby = function(){ | ||
return new HobbyModel(hobbyStateChangedHandler).apply(this, arguments); | ||
}; | ||
var hobbiesViewModel = IMVVM.createViewModel({ | ||
getWatchedState: function() { | ||
return { | ||
'persons': { | ||
alias: 'personsContext', //optional - if provided then will be added to prototype | ||
fields: { //optional | ||
'selectedPerson': onPersonChangedHandler | ||
} | ||
}, | ||
'busy': { | ||
alias: 'busy' | ||
} | ||
}; | ||
}, | ||
hobbies: { | ||
kind: 'pseudo', | ||
get: function(){ | ||
return this.state.personsContext.selectedPerson.hobbies; | ||
} | ||
} | ||
}, | ||
addHobby: function(value){ | ||
if(value !== ''){ | ||
this.state.personsContext.selectedPerson. | ||
addHobby(this.Hobby({ id:this.uuid(), name:value }, true)); | ||
} | ||
}, | ||
deleteHobby: function(value){ | ||
/* | ||
}, | ||
If we were to simply call | ||
busyText: { | ||
kind: 'pseudo', //kind: 'pseudo' because its not calculated but is supplied externally | ||
get: function(){ | ||
return this.state.busy ? 'Im Busy! Go away...' : 'Not doing too much.'; | ||
} | ||
}, | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
current: { | ||
kind: 'instance', | ||
get: function(){ | ||
return this.state.current; | ||
} | ||
}, | ||
then IMVVM is notified that the call was made from the 'persons' context | ||
and not from the 'hobbies' context. Therefore any subscribers to 'hobbies.current' | ||
are unaware of changes to 'hobbies.current'. | ||
selectHobby: function(id){ | ||
for (var i = this.hobbies.length - 1; i >= 0; i--) { | ||
if ((this.current === void(0) || this.current.id !== id) && this.hobbies[i].id === id){ | ||
this.setState({current: new Hobby(this.hobbies[i])}, {busy: true}); | ||
/* | ||
//OR use a callback | ||
this.setState({current: Hobby(this.hobbies[i])}, function(){ | ||
this.setState(void(0), {busy: true}); | ||
}.bind(this)); | ||
*/ | ||
If the selected hobby is deleted, then call setState from 'hobbies' ViewModel, | ||
so that the 'persons' context gets updated and busy can be set on the 'domain' | ||
break; | ||
} | ||
} | ||
}, | ||
addHobby: function(value){ | ||
if(value !== ''){ | ||
this.state.personsContext.selectedPerson. | ||
addHobby(new Hobby({ id: uuid(), name:value }, true)); | ||
} | ||
}, | ||
deleteHobby: function(value){ | ||
/* | ||
*/ | ||
If we were to simply call | ||
if(this.current.id === value){ | ||
this.setState({ current: void(0) }, { busy: false }, function(){ | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
}.bind(this)); | ||
} else { | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
} | ||
}, | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
uuid: function () { | ||
/*jshint bitwise:false */ | ||
var i, random; | ||
var uuid = ''; | ||
then IMVVM is notified that the call was made from the 'persons' context | ||
and not from the 'hobbies' context. Therefore any subscribers to 'hobbies.current' | ||
are unaware of changes to 'hobbies.current'. | ||
for (i = 0; i < 32; i++) { | ||
random = Math.random() * 16 | 0; | ||
if (i === 8 || i === 12 || i === 16 || i === 20) { | ||
uuid += '-'; | ||
If the selected hobby is deleted, then call setState from 'hobbies' ViewModel, | ||
so that the 'persons' context gets updated and busy can be set on the 'domain' | ||
*/ | ||
if(this.current && this.current.id === value){ | ||
this.setState({ current: void(0) }, { busy: false }, function(){ | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
}.bind(this)); | ||
} else { | ||
this.state.personsContext.selectedPerson.deleteHobby(value); | ||
} | ||
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)) | ||
.toString(16); | ||
} | ||
return uuid; | ||
}, | ||
}); | ||
}); | ||
return hobbiesViewModel; | ||
}()); |
@@ -6,43 +6,9 @@ /*jshint unused: false */ | ||
var PersonsViewModel = IMVVM.createViewModel({ | ||
var PersonsViewModel = (function(){ | ||
getInitialState: function(){ | ||
var nextState = {}; | ||
nextState.collection = DataService.getPersonData().map(function(person, idx){ | ||
if (idx === 0){ | ||
nextState.selectedPerson = this.Person(person, true); | ||
return nextState.selectedPerson; | ||
} | ||
return this.Person(person, true); | ||
}.bind(this)); | ||
return nextState; | ||
}, | ||
getWatchedState: function() { | ||
return { | ||
'hobbies': { | ||
alias: 'hobbiesContext', | ||
}, | ||
'online': { | ||
alias: 'imOnline' | ||
} | ||
}; | ||
}, | ||
imOnline: { | ||
kind:'pseudo', | ||
get: function(){ | ||
return this.state.imOnline; | ||
} | ||
}, | ||
Person: function(){ | ||
return new PersonModel(this.personStateChangedHandler).apply(this, arguments); | ||
}, | ||
personStateChangedHandler: function(nextState, prevState/*, callback*/){ | ||
var personStateChangedHandler = function(nextState, prevState/*, callback*/){ | ||
var persons = {}; | ||
persons.collection = this.collection.map(function(person){ | ||
if(person.id === nextState.id){ | ||
persons.selectedPerson = this.Person(nextState); | ||
persons.selectedPerson = new Person(nextState); | ||
return persons.selectedPerson; | ||
@@ -53,62 +19,100 @@ } | ||
this.setState(persons); | ||
}, | ||
}; | ||
var Person = function(){ | ||
return new PersonModel(personStateChangedHandler).apply(this, arguments); | ||
}; | ||
selectedHobby: { | ||
kind: 'pseudo', | ||
get: function() { | ||
return this.state.hobbiesContext.current ? this.state.hobbiesContext.current.name: void(0); | ||
} | ||
}, | ||
var personsViewModel = IMVVM.createViewModel({ | ||
selectedPerson: { | ||
kind: 'instance', | ||
get: function() { return this.state.selectedPerson; } | ||
}, | ||
getInitialState: function(){ | ||
var nextState = {}; | ||
nextState.collection = DataService.getPersonData().map(function(person, idx){ | ||
if (idx === 0){ | ||
nextState.selectedPerson = new Person(person, true); | ||
return nextState.selectedPerson; | ||
} | ||
return new Person(person, true); | ||
}.bind(this)); | ||
return nextState; | ||
}, | ||
getWatchedState: function() { | ||
return { | ||
'hobbies': { | ||
alias: 'hobbiesContext', | ||
}, | ||
'online': { | ||
alias: 'imOnline' | ||
} | ||
}; | ||
}, | ||
collection: { | ||
kind: 'array', | ||
get: function(){ return this.state.collection; }, | ||
}, | ||
imOnline: { | ||
kind:'pseudo', | ||
get: function(){ | ||
return this.state.imOnline; | ||
} | ||
}, | ||
selectPerson: function(id){ | ||
for (var i = this.collection.length - 1; i >= 0; i--) { | ||
if(this.selectedPerson.id !== id && this.collection[i].id === id){ | ||
this.setState({ selectedPerson: this.Person(this.collection[i]) }); | ||
break; | ||
selectedHobby: { | ||
kind: 'pseudo', | ||
get: function() { | ||
return this.state.hobbiesContext.current ? this.state.hobbiesContext.current.name: void(0); | ||
} | ||
} | ||
}, | ||
}, | ||
addPerson: function(value){ | ||
var nextState = {}; | ||
var name; | ||
selectedPerson: { | ||
kind: 'instance', | ||
get: function() { return this.state.selectedPerson; } | ||
}, | ||
if(value && value.length > 0){ | ||
name = value.split(' '); | ||
nextState.selectedPerson = this.Person({ | ||
firstName: name[0], | ||
lastName: name.slice(1).join(' ') | ||
}, true); | ||
nextState.collection = this.collection.slice(0); | ||
nextState.collection = nextState.collection.concat(nextState.selectedPerson); | ||
this.setState(nextState); | ||
} | ||
}, | ||
collection: { | ||
kind: 'array', | ||
get: function(){ return this.state.collection; }, | ||
}, | ||
deletePerson: function(uid){ | ||
var nextState = {}; | ||
nextState.collection = this.collection.filter(function(person){ | ||
return person.id !== uid; | ||
}); | ||
nextState.selectedPerson = void(0); | ||
if(nextState.collection.length > 0){ | ||
if (this.selectedPerson.id === uid){ | ||
nextState.selectedPerson = this.Person(nextState.collection[0]); | ||
} else { | ||
nextState.selectedPerson = this.Person(this.selectedPerson); | ||
selectPerson: function(id){ | ||
for (var i = this.collection.length - 1; i >= 0; i--) { | ||
if(this.selectedPerson.id !== id && this.collection[i].id === id){ | ||
this.setState({ selectedPerson: new Person(this.collection[i]) }); | ||
break; | ||
} | ||
} | ||
} | ||
this.setState(nextState); | ||
}, | ||
}, | ||
}); | ||
addPerson: function(value){ | ||
var nextState = {}; | ||
var name; | ||
if(value && value.length > 0){ | ||
name = value.split(' '); | ||
nextState.selectedPerson = new Person({ | ||
firstName: name[0], | ||
lastName: name.slice(1).join(' ') | ||
}, true); | ||
nextState.collection = this.collection.slice(0); | ||
nextState.collection = nextState.collection.concat(nextState.selectedPerson); | ||
this.setState(nextState); | ||
} | ||
}, | ||
deletePerson: function(uid){ | ||
var nextState = {}; | ||
nextState.collection = this.collection.filter(function(person){ | ||
return person.id !== uid; | ||
}); | ||
nextState.selectedPerson = void(0); | ||
if(nextState.collection.length > 0){ | ||
if (this.selectedPerson.id === uid){ | ||
nextState.selectedPerson = new Person(nextState.collection[0]); | ||
} else { | ||
nextState.selectedPerson = new Person(this.selectedPerson); | ||
} | ||
} | ||
this.setState(nextState); | ||
}, | ||
}); | ||
return personsViewModel; | ||
}()); |
@@ -5,5 +5,5 @@ 'use strict'; | ||
getPersonData: function() { | ||
return [{id:'1', firstName:'Frank', lastName: "Smith", gender:'male', dob:'1980-03-03', job:'dentist', hobbies: ['reading', 'golfing', 'computer programming']}, | ||
{id:'2', firstName:'Lisa', lastName: "Jones", gender:'female', dob:'1985-02-22', job:'accountant', hobbies: ['reading']}, | ||
{id:'3', firstName: "John", lastName: "Citizen", gender:'male', dob:'1975-12-11', job:'unemployed', hobbies: ['watching TV']}]; | ||
return [{id:'1', firstName:'Frank', lastName: "Smith", gender:'male', dob:'1980-03-03', job:'Dentist'}, | ||
{id:'2', firstName:'Lisa', lastName: "Jones", gender:'female', dob:'1985-02-22', job:'Accountant'}, | ||
{id:'3', firstName: "John", lastName: "Citizen", gender:'male', dob:'1975-12-11', job:'Unemployed'}]; | ||
}, | ||
@@ -14,11 +14,11 @@ getHobbiesData: function(uid) { | ||
id:'1', | ||
hobbies: [{id:'1', name: 'reading'}, {id:'2', name: 'golfing'}, {id:'3', name: 'computer programming'}] | ||
hobbies: [{id:'1', hobby: 'reading'}, {id:'2', hobby: 'golfing'}, {id:'3', hobby: 'cutting code'}] | ||
}, | ||
{ | ||
id:'2', | ||
hobbies: [{id:'1', name: 'reading'}] | ||
hobbies: [{id:'1', hobby: 'reading'}] | ||
}, | ||
{ | ||
id:'3', | ||
hobbies: [{id:'1', name: 'watching TV'}] | ||
hobbies: [{id:'1', hobby: 'watching YouTube'}] | ||
}]; | ||
@@ -25,0 +25,0 @@ var personHobbies = hobbies.filter(function(person){ |
{ | ||
"name": "imvvm", | ||
"description": "Immutable MVVM for React", | ||
"version": "0.6.16", | ||
"version": "0.6.19", | ||
"keywords": [ | ||
@@ -10,3 +10,2 @@ "mvvm", | ||
"immutable", | ||
"node", | ||
"presentation model", | ||
@@ -16,3 +15,6 @@ "imvvm" | ||
"homepage": "https://github.com/entrendipity/imvvm", | ||
"author": "Frank Panetta <frank.panetta@entrendipity.com.au>", | ||
"author": { | ||
"name": "Frank Panetta", | ||
"email": "frank.panetta@entrendipity.com.au" | ||
}, | ||
"repository": { | ||
@@ -31,2 +33,2 @@ "type": "git", | ||
} | ||
} | ||
} |
217
README.md
@@ -54,3 +54,14 @@ IMVVM | ||
## Getting Started | ||
###Install and start the example application (which is intended to act as a reference implementation). | ||
The example application is a good starting place when figuring out how things work. To get it running, navigate to the `./example` directory and run the following commands. | ||
``` | ||
$ npm install | ||
$ cd app | ||
$ bower install | ||
$ bower install imvvm | ||
$ cd .. | ||
$ grunt serve | ||
``` | ||
### Create a Model | ||
@@ -63,4 +74,4 @@ | ||
return { | ||
age: this.calculateAge(this.dob), | ||
id: this.id ? this.id : this.uuid() | ||
age: calculateAge(this.dob), | ||
id: this.id ? this.id : uuid() | ||
}; | ||
@@ -91,3 +102,3 @@ }, | ||
if(newValue.length === 10){ | ||
age = this.calculateAge(newValue); | ||
age = calculateAge(newValue); | ||
} | ||
@@ -118,25 +129,3 @@ if(newValue.length === 0){ | ||
}, | ||
calculateAge: function(dob){ | ||
var DOB = new Date(dob); | ||
var ageDate = new Date(Date.now() - DOB.getTime()); | ||
var age = Math.abs(ageDate.getFullYear() - 1970); | ||
return isNaN(age) ? 'Enter your Birthday' : age + ' years old'; | ||
}, | ||
uuid: function () { | ||
var i, random; | ||
var uuid = ''; | ||
for (i = 0; i < 32; i++) { | ||
random = Math.random() * 16 | 0; | ||
if (i === 8 || i === 12 || i === 16 || i === 20) { | ||
uuid += '-'; | ||
} | ||
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)) | ||
.toString(16); | ||
} | ||
return uuid; | ||
}, | ||
}); | ||
@@ -150,3 +139,3 @@ ``` | ||
#####age | ||
`age` is a calculated field. It is set by setting `dob`. `dob` uses the calculateAge function to set the value of age and passes both the dob and age values to setState. Please note that `age` needed to be initialized in the getInitialState() function. | ||
`age` is a calculated field. It is set by setting `dob`. `dob` uses a calculateAge function to set the value of age and passes both the dob and age values to setState. Please note that `age` needed to be initialized in the getInitialState() function. | ||
@@ -156,2 +145,19 @@ ### Create a ViewModel | ||
```javascript | ||
var personStateChangedHandler = function(nextState, prevState){ | ||
var persons = {}; | ||
persons.collection = this.collection.map(function(person){ | ||
if(person.id === nextState.id){ | ||
persons.selectedPerson = new Person(nextState); | ||
return persons.selectedPerson; | ||
} | ||
return person; | ||
}.bind(this)); | ||
this.setState(persons); | ||
}; | ||
var Person = function(){ | ||
return new PersonModel(personStateChangedHandler).apply(this, arguments); | ||
}; | ||
var PersonsViewModel = IMVVM.createViewModel({ | ||
@@ -163,6 +169,6 @@ | ||
if (idx === 0){ | ||
nextState.selectedPerson = this.Person(person, true); | ||
nextState.selectedPerson = new Person(person, true); | ||
return nextState.selectedPerson; | ||
} | ||
return this.Person(person, true); | ||
return new Person(person, true); | ||
}.bind(this)); | ||
@@ -200,19 +206,2 @@ return nextState; | ||
personStateChangedHandler: function(nextState, prevState){ | ||
var persons = {}; | ||
persons.collection = this.collection.map(function(person){ | ||
if(person.id === nextState.id){ | ||
persons.selectedPerson = this.Person(nextState); | ||
return persons.selectedPerson; | ||
} | ||
return person; | ||
}.bind(this)); | ||
this.setState(persons); | ||
}, | ||
Person: function(){ | ||
return new PersonModel(this.personStateChangedHandler).apply(this, arguments); | ||
}, | ||
selectedHobby: { | ||
@@ -228,3 +217,3 @@ kind: 'pseudo', | ||
if(this.selectedPerson.id !== id && this.collection[i].id === id){ | ||
this.setState({ selectedPerson: this.Person(this.collection[i]) }); | ||
this.setState({ selectedPerson: new Person(this.collection[i]) }); | ||
break; | ||
@@ -241,3 +230,3 @@ } | ||
name = value.split(' '); | ||
nextState.selectedPerson = this.Person({ | ||
nextState.selectedPerson = new Person({ | ||
firstName: name[0], | ||
@@ -260,5 +249,5 @@ lastName: name.slice(1).join(' ') | ||
if (this.selectedPerson.id === uid){ | ||
nextState.selectedPerson = this.Person(nextState.collection[0]); | ||
nextState.selectedPerson = new Person(nextState.collection[0]); | ||
} else { | ||
nextState.selectedPerson = this.Person(this.selectedPerson); | ||
nextState.selectedPerson = new Person(this.selectedPerson); | ||
} | ||
@@ -302,2 +291,9 @@ } | ||
```javascript | ||
var onPersonChangedHandler = function(nextState, prevState, field, context){ | ||
if(this.current !== void(0) && context === 'persons' && | ||
nextState.id !== prevState.id){ | ||
return { hobbies: { current: void(0) }, busy: false }; | ||
} | ||
}; | ||
var HobbiesViewModel = IMVVM.createViewModel({ | ||
@@ -310,3 +306,3 @@ | ||
fields: { | ||
'selectedPerson': this.onPersonChangedHandler | ||
'selectedPerson': onPersonChangedHandler | ||
} | ||
@@ -319,9 +315,2 @@ }, | ||
}, | ||
onPersonChangedHandler: function(nextState, prevState, field, context){ | ||
if(this.current !== void(0) && context === 'persons' && | ||
nextState.id !== prevState.id){ | ||
return { hobbies: { current: void(0) }, busy: false }; | ||
} | ||
}, | ||
@@ -334,7 +323,7 @@ ... | ||
this.setState({current: this.Hobby(this.hobbies[i])}, {busy: true}); | ||
this.setState({current: new Hobby(this.hobbies[i])}, {busy: true}); | ||
/* | ||
//OR use a callback | ||
this.setState({current: this.Hobby(this.hobbies[i])}, function(){ | ||
this.setState({current: new Hobby(this.hobbies[i])}, function(){ | ||
this.setState(void(0), {busy: true}); | ||
@@ -357,3 +346,3 @@ }.bind(this)); | ||
Both the `alias` and `fields` properties are optional. | ||
Both the `alias` and `fields` properties are optional. However at least one must be present. | ||
@@ -366,3 +355,3 @@ #####onPersonChangedHandler | ||
For instance `this.setState({current: this.Hobby(this.hobbies[i])}, {busy: true});`. The first parameter is the next state for the `hobbies` data context, the second parameter specifies that `busy`, a property in the domain data context, should be changed to `true`. This second parameter also accepts other data contexts (e.g. `{persons: {selectedPerson: this.Person(personState)}}`). | ||
For instance `this.setState({current: this.Hobby(this.hobbies[i])}, {busy: true});`. The first parameter is the next state for the `hobbies` data context, the second parameter specifies that `busy`, a property in the domain data context, should be changed to `true`. This second parameter also accepts other data contexts (e.g. `{persons: {selectedPerson: new Person(personState)}}`). | ||
@@ -425,4 +414,17 @@ Also noted within comments, is that this can be achieved within a callback, ensuring to pass `void(0)` as the first parameter to `setState`. | ||
#####persons | ||
The `persons` property is setting up a data context called 'persons'. It has a special decorator called `viewModel` which specifies which ViewModel is associated to this data context. | ||
The `persons` property sets up a data context called 'persons'. It has a special decorator called `viewModel`, which specifies the associated ViewModel for this data context. | ||
___ | ||
>___This is probably a good time to explain a little about what gets exposed to the View.___ | ||
> | ||
>When a Model, ViewModel or DomainViewModel is instantiated, IMVVM takes all the defined functions and places them on the Object's prototype. It also takes all the field descriptors and assigns them as properties for the newly created object. | ||
> | ||
>So all functions and fields defined within a Model, ViewModel or DomainModel, are visible to other objects. This means that the View has visibility and access to these functions and fields, including any implementation specific functions, which probably should be kept separate from the View. | ||
> | ||
>What would be preferred, is to only expose the properties and functions the View needs. To accomplish this, define variables, properties or functions outside of your Models, ViewModels and DomainViewModels, and simply reference them. That way the View API is kept nice and clean and your implementation is kept separate. | ||
> | ||
>Refer to the reference implementation (i.e. example application), which uses this technique. | ||
___ | ||
### Hook up the View | ||
@@ -548,14 +550,2 @@ Once you have created your Models. ViewModels and DomainViewModel, you're ready to hook it up the the View. All you need to do is specify the mixin and IMVVM will attach a `domainDataContext` to the state object that will be kept in sync with you're ViewModel. | ||
##Running the example application | ||
The example application is a good starting place when figuring out how things work. To get it running, navigate to the `./example` directory and run the following commands. | ||
``` | ||
$ npm install | ||
$ cd app | ||
$ bower install | ||
$ bower install imvvm | ||
$ cd .. | ||
$ grunt serve | ||
``` | ||
##API | ||
@@ -579,2 +569,3 @@ | ||
__specification__ - see [Specification](#specification) | ||
___ | ||
@@ -618,17 +609,3 @@ #####function createModel(object specification) | ||
_Available in:_ DomainViewModel, ViewModel, Model | ||
___ | ||
#####object extend(object currentState[, object... nextState]) | ||
Creates a shallow copy of currentState. Adds/replaces properties with properties of subsequent objects. | ||
*parameters* | ||
__currentState__ | ||
Old state object. | ||
__nextState__ | ||
Next state objects. | ||
_Available in:_ DomainViewModel, ViewModel, Model | ||
___ | ||
@@ -662,2 +639,3 @@ #####object undo() | ||
_Available in:_ DomainViewModel | ||
___ | ||
@@ -701,3 +679,5 @@ #####canUndo | ||
######Watching DomainViewModel state | ||
___n.b. `alias` and `fields` are optional, however at least one must be present. This is intentional. `alias` is an indicator that the ViewModel should attach the specified dataContext to the `state` object. If `alias` is not specified then it will not be attached.___ | ||
######Watching Domain Data Context state | ||
field\: \{ | ||
@@ -707,2 +687,4 @@ alias\: preferredName | ||
___n.b. `alias` is not optional, in this istance, as only fields can be referenced to the Domain dataContext.___ | ||
___example___ | ||
@@ -777,3 +759,2 @@ ```javascript | ||
```javascript | ||
@@ -785,3 +766,3 @@ personStateChangedHandler: function(nextState, prevState){ | ||
persons.selected = this.Person(nextState, person, true); | ||
persons.selected = new Person(nextState, person, true); | ||
return persons.selected; | ||
@@ -826,7 +807,7 @@ } | ||
var nextState = this.extend(personObj, {firstName: 'Fred'}); | ||
persons.selectedPerson = this.Person(nextState); | ||
persons.selectedPerson = new Person(nextState); | ||
``` | ||
```javascript | ||
persons.selectedPerson = this.Person(personObj, {firstName: 'Fred'}); | ||
persons.selectedPerson = new Person(personObj, {firstName: 'Fred'}); | ||
``` | ||
@@ -840,3 +821,3 @@ | ||
__Usage example__ | ||
___Usage example___ | ||
@@ -846,5 +827,5 @@ ___n.b. This is suggested usage and not part of the API___ | ||
```javascript | ||
Person: function(){ | ||
return new PersonModel(this.personStateChangedHandler).apply(this, arguments); | ||
}, | ||
var Person: function(){ | ||
return new PersonModel(personStateChangedHandler).apply(this, arguments); | ||
}, | ||
``` | ||
@@ -858,4 +839,2 @@ | ||
___ | ||
####Descriptor | ||
@@ -903,11 +882,11 @@ ___ | ||
```javascript | ||
occupation: { | ||
aliasFor: 'job', | ||
get: function(){ | ||
return this.state.occupation; | ||
}, | ||
set: function(newValue){ | ||
this.setState({'occupation': newValue }); | ||
} | ||
occupation: { | ||
aliasFor: 'job', | ||
get: function(){ | ||
return this.state.occupation; | ||
}, | ||
set: function(newValue){ | ||
this.setState({'occupation': newValue }); | ||
} | ||
}, | ||
``` | ||
@@ -950,2 +929,26 @@ | ||
###Helpers | ||
####extend | ||
___ | ||
#####object extend(object currentState[, object... nextState]) | ||
Creates a shallow copy of currentState. Adds/replaces properties with properties of subsequent objects. | ||
*parameters* | ||
__currentState__ | ||
Old state object. | ||
__nextState__ | ||
Next state objects. | ||
___Usage example___ | ||
```javascript | ||
var nextState = IMVVM.extend(currentState, nextState); | ||
``` | ||
_Available in:_ DomainViewModel, ViewModel, Model | ||
## Browser Support | ||
@@ -952,0 +955,0 @@ Most ECMAScript 5 compliant browsers. |
@@ -67,3 +67,3 @@ | ||
for(dataContext in domain){ | ||
nextState[dataContext] = new dataContexts[dataContext](nextState); | ||
nextState[dataContext] = new dataContexts[dataContext](nextState[dataContext]); | ||
} | ||
@@ -84,3 +84,10 @@ | ||
if(typeof callback === 'function'){ | ||
appState = new ApplicationDataContext(nextState, prevState, redoState, enableUndo); | ||
callback(); | ||
return; | ||
} | ||
} else { | ||
if(!!newStateKeys.length){ | ||
@@ -109,3 +116,3 @@ if(caller === appNamespace){ | ||
nextState[transientStateKeys[keyIdx]] = extend(appState[transientStateKeys[keyIdx]], transientState[transientStateKeys[keyIdx]]); | ||
nextState[transientStateKeys[keyIdx]] = new dataContexts[transientStateKeys[keyIdx]](nextState); | ||
nextState[transientStateKeys[keyIdx]] = new dataContexts[transientStateKeys[keyIdx]](nextState[transientStateKeys[keyIdx]]); | ||
} else { | ||
@@ -196,3 +203,2 @@ nextState[transientStateKeys[keyIdx]] = transientState[transientStateKeys[keyIdx]]; | ||
} | ||
@@ -207,5 +213,3 @@ appState = new ApplicationDataContext(nextState, prevState, redoState, enableUndo); | ||
processedState = {}; | ||
//Provided for the main app to return to the View | ||
return appState; | ||
}; | ||
@@ -215,3 +219,2 @@ | ||
ApplicationDataContext = domainModel.call(this, appStateChangedHandler.bind(this, appNamespace)); | ||
/*Need to look at DomainViewModel state and nextState and Domain Model and updating*/ | ||
appState = new ApplicationDataContext(void(0), void(0), void(0), enableUndo, true); | ||
@@ -221,10 +224,12 @@ appState.state = appState.state || {}; | ||
domain = appState.getDomainDataContext(); | ||
delete appState.__proto__.getDomainDataContext; | ||
for(dataContext in domain){ | ||
if(domain.hasOwnProperty(dataContext)){ | ||
dataContexts[dataContext] = domain[dataContext].call(this, appStateChangedHandler.bind(this, dataContext)).bind(this, dataContext); | ||
appState.state[dataContext] = new dataContexts[dataContext](appState.state); | ||
dataContexts[dataContext] = domain[dataContext].call(this, appStateChangedHandler.bind(this, dataContext)); | ||
appState.state[dataContext] = new dataContexts[dataContext](appState.state[dataContext]); | ||
if('getWatchedState' in appState[dataContext]){ | ||
watchedState = appState[dataContext].getWatchedState(); | ||
delete appState[dataContext].__proto__.getWatchedState; | ||
for(watchedItem in watchedState){ | ||
@@ -283,3 +288,5 @@ if(watchedState.hasOwnProperty(watchedItem)){ | ||
Object.freeze(appState); | ||
console.warn('\"this.extend\" has been deprecated and will not be available in 0.7. Please use \"IMVVM.extend\".'); | ||
return appState; | ||
}; |
@@ -57,4 +57,4 @@ | ||
if('__processedObject__' in this.originalSpec){ | ||
return this.originalSpec.__processedObject__; | ||
if('__processedSpec__' in this.originalSpec){ | ||
return this.originalSpec.__processedSpec__; | ||
} | ||
@@ -67,7 +67,2 @@ | ||
this.originalSpec[key].enumerable = true; | ||
if('aliasFor' in this.originalSpec[key]){ | ||
aliases[this.originalSpec[key].aliasFor] = key; | ||
delete this.originalSpec[key].aliasFor; | ||
} | ||
if('viewModel' in this.originalSpec[key]) { | ||
@@ -77,9 +72,16 @@ viewModels[key] = this.originalSpec[key].viewModel; | ||
delete this.originalSpec[key].set; | ||
} else if('kind' in this.originalSpec[key]){ | ||
if(this.originalSpec[key].kind === 'pseudo'){ | ||
this.originalSpec[key].enumerable = false; | ||
} else { //'instance' || 'array' | ||
autoFreeze.push({fieldName: key, kind: this.originalSpec[key].kind}); | ||
} else { | ||
if('aliasFor' in this.originalSpec[key]){ | ||
aliases[this.originalSpec[key].aliasFor] = key; | ||
delete this.originalSpec[key].aliasFor; | ||
} | ||
delete this.originalSpec[key].kind; | ||
if('kind' in this.originalSpec[key]){ | ||
if(this.originalSpec[key].kind === 'pseudo'){ | ||
this.originalSpec[key].enumerable = false; | ||
} else { //'instance' || 'array' | ||
autoFreeze.push({fieldName: key, kind: this.originalSpec[key].kind}); | ||
} | ||
delete this.originalSpec[key].kind; | ||
} | ||
} | ||
@@ -94,3 +96,3 @@ descriptor[key] = this.originalSpec[key]; | ||
if(!('extend' in proto)){ | ||
proto.extend = utils.extend; | ||
proto.extend = utils.extend; | ||
} | ||
@@ -104,3 +106,3 @@ | ||
this.originalSpec.__processedObject__ = { | ||
this.originalSpec.__processedSpec__ = { | ||
descriptor: descriptor, | ||
@@ -113,3 +115,3 @@ proto: proto, | ||
return this.originalSpec.__processedObject__; | ||
return this.originalSpec.__processedSpec__; | ||
}; | ||
@@ -125,5 +127,6 @@ | ||
createDomainViewModel: IMVVMClass.createClass.bind(this, DomainViewModelBase, 'DomainViewModel'), | ||
mixin: mixin | ||
mixin: mixin, | ||
extend: extend | ||
}; | ||
module.exports = IMVVM; |
@@ -76,3 +76,4 @@ | ||
//Add state prop so that it can be referenced from within getInitialState | ||
nextState = ('getInitialState' in domainModel) ? domainModel.getInitialState.call(domainModel) : {}; | ||
nextState = ('getInitialState' in domainModel) ? domainModel.getInitialState.call(domainModel) : {}; | ||
delete domainModel.__proto__.getInitialState; | ||
} else if('state' in nextState){ | ||
@@ -79,0 +80,0 @@ delete nextState.state; |
@@ -12,4 +12,5 @@ | ||
desc.stateChangedHandler = stateChangedHandler; | ||
desc.proto.__getDescriptor = function(){ | ||
return desc; | ||
if('getInitialState' in desc.originalSpec){ | ||
desc.proto.getInitialState = desc.originalSpec.getInitialState; | ||
} | ||
@@ -51,3 +52,4 @@ | ||
if('getInitialState' in model){ | ||
nextState = extend(nextState, model.getInitialState.call(model)); | ||
nextState = extend(nextState, model.getInitialState.call(model)); | ||
delete model.__proto__.getInitialState; | ||
} | ||
@@ -54,0 +56,0 @@ } |
@@ -13,3 +13,3 @@ | ||
var dataContext = function(VMName, nextAppState) { | ||
var dataContext = function(nextVMState) { | ||
@@ -31,9 +31,8 @@ //nextState has already been extended with prevState in core | ||
if(!!nextAppState){ | ||
if(nextAppState[VMName] === void(0)){ | ||
nextState = ('getInitialState' in viewModel) ? | ||
extend(nextState, viewModel.getInitialState.call(viewModel)) : nextState; | ||
} else { | ||
nextState = ('state' in nextAppState[VMName] ? nextAppState[VMName].state : nextAppState[VMName]); | ||
} | ||
if(nextVMState === void(0)){ | ||
nextState = ('getInitialState' in viewModel) ? | ||
extend(nextState, viewModel.getInitialState.call(viewModel)) : nextState; | ||
delete viewModel.__proto__.getInitialState; | ||
} else { | ||
nextState = ('state' in nextVMState ? nextVMState.state : nextVMState); | ||
} | ||
@@ -52,5 +51,6 @@ | ||
if(viewModel[freezeFields[fld].fieldName]){ | ||
tempDesc = viewModel[freezeFields[fld].fieldName].__getDescriptor(); | ||
tempDesc = viewModel[freezeFields[fld].fieldName].constructor.originalSpec.__processedSpec__; | ||
tempModel = Object.create(tempDesc.proto, tempDesc.descriptor); | ||
delete tempModel.__proto__.getInitialState; | ||
Object.defineProperty(tempModel, 'state', { | ||
@@ -57,0 +57,0 @@ configurable: true, |
173856
2582
941