11/**
22 * API Bound Models for AngularJS
3- * @version v0.12.2 - 2014-02-27
3+ * @version v0.13.0 - 2014-03-14
44 * @link https://github.com/angular-platanus/restmod
55 * @author Ignacio Baixas <[email protected] > 66 * @license MIT License, http://www.opensource.org/licenses/MIT
@@ -95,39 +95,7 @@ var Utils = {
9595// make this available as a restmod constant
9696angular . module ( 'plRestmod' ) . constant ( 'Utils' , Utils ) ;
9797
98- /**
99- * @class SyncMask
100- * @memberOf constants
101- *
102- * @description The object property synchronization mask.
103- */
104- var SyncMask = {
105- NONE : 0x00 ,
106- ALL : 0xFFFF ,
107- SYSTEM_ALL : 0x1FFFF ,
108-
109- SYSTEM : 0x10000 ,
110-
111- DECODE_CREATE : 0x0001 ,
112- DECODE_UPDATE : 0x0002 ,
113- DECODE_USER : 0x0004 ,
114- DECODE_SAVE : 0x0003 ,
115-
116- ENCODE_CREATE : 0x0100 ,
117- ENCODE_UPDATE : 0x0200 ,
118- ENCODE_USER : 0x0400 ,
119- ENCODE_SAVE : 0x0300 ,
120-
121- // Compound masks
122- DECODE : 0x00FF ,
123- ENCODE : 0xFF00 ,
124- CREATE : 0x0101 ,
125- UPDATE : 0x0202 ,
126- USER : 0x0404 ,
127- SAVE : 0x0303
128- } ;
129-
130- // Cache some angular stuff
98+ // Preload some angular stuff
13199var bind = angular . bind ,
132100 forEach = angular . forEach ,
133101 extend = angular . extend ,
@@ -136,6 +104,13 @@ var bind = angular.bind,
136104 isFunction = angular . isFunction ,
137105 arraySlice = Array . prototype . slice ;
138106
107+ // Constants
108+ var CREATE_MASK = 'C' ,
109+ UPDATE_MASK = 'U' ,
110+ READ_MASK = 'R' ,
111+ WRITE_MASK = 'CU' ,
112+ FULL_MASK = 'CRU' ;
113+
139114/**
140115 * @class $restmodProvider
141116 * @memberOf providers
@@ -193,15 +168,7 @@ angular.module('plRestmod').provider('$restmod', function() {
193168 */
194169 model : function ( _baseUrl /* , _mix */ ) {
195170
196- var masks = {
197- $type : SyncMask . SYSTEM_ALL ,
198- $scope : SyncMask . SYSTEM_ALL ,
199- $promise : SyncMask . SYSTEM_ALL ,
200- $pending : SyncMask . SYSTEM_ALL ,
201- $response : SyncMask . SYSTEM_ALL ,
202- $status : SyncMask . SYSTEM_ALL ,
203- $cb : SyncMask . SYSTEM_ALL
204- } ,
171+ var masks = { } ,
205172 urlPrefix = null ,
206173 primaryKey = 'id' ,
207174 defaults = [ ] ,
@@ -317,32 +284,34 @@ angular.module('plRestmod').provider('$restmod', function() {
317284 // recursive transformation function, used by $decode and $encode.
318285 function transform ( _data , _ctx , _prefix , _mask , _decode , _into ) {
319286
320- var key , decodedName , encodedName , fullName , filter , value , result = _into || { } ;
287+ var key , decodedName , encodedName , fullName , mask , filter , value , result = _into || { } ;
321288
322289 for ( key in _data ) {
323- if ( _data . hasOwnProperty ( key ) && ! ( ! _decode && key [ 0 ] === '$' && key [ 1 ] === '$' ) ) {
290+ if ( _data . hasOwnProperty ( key ) && key [ 0 ] !== '$' ) {
324291
325292 decodedName = ( _decode && nameDecoder ) ? nameDecoder ( key ) : key ;
326293 fullName = _prefix + decodedName ;
327294
328- // check if property is masked for this operation
329- if ( ! ( ( masks [ fullName ] || 0 ) & _mask ) ) {
330-
331- value = _data [ key ] ;
332- filter = _decode ? decoders [ fullName ] : encoders [ fullName ] ;
295+ // skip property if masked for this operation
296+ mask = masks [ fullName ] ;
297+ if ( mask && mask . indexOf ( _mask ) !== - 1 ) {
298+ continue ;
299+ }
333300
334- if ( filter ) {
335- value = filter . call ( _ctx , value ) ;
336- if ( value === undefined ) continue ; // ignore value if filter returns undefined
337- } else if ( typeof value === 'object' && value &&
338- ( _decode || typeof value . toJSON !== 'function' ) ) {
339- // IDEA: make extended decoding/encoding optional, could be a little taxxing for some apps
340- value = transformExtended ( value , _ctx , fullName , _mask , _decode ) ;
341- }
301+ value = _data [ key ] ;
302+ filter = _decode ? decoders [ fullName ] : encoders [ fullName ] ;
342303
343- encodedName = ( ! _decode && nameEncoder ) ? nameEncoder ( decodedName ) : decodedName ;
344- result [ encodedName ] = value ;
304+ if ( filter ) {
305+ value = filter . call ( _ctx , value ) ;
306+ if ( value === undefined ) continue ; // ignore value if filter returns undefined
307+ } else if ( typeof value === 'object' && value &&
308+ ( _decode || typeof value . toJSON !== 'function' ) ) {
309+ // IDEA: make extended decoding/encoding optional, could be a little taxing for some apps
310+ value = transformExtended ( value , _ctx , fullName , _mask , _decode ) ;
345311 }
312+
313+ encodedName = ( ! _decode && nameEncoder ) ? nameEncoder ( decodedName ) : decodedName ;
314+ result [ encodedName ] = value ;
346315 }
347316 }
348317
@@ -494,7 +463,11 @@ angular.module('plRestmod').provider('$restmod', function() {
494463
495464 // sets an attribute mask at runtime
496465 Model . $$setMask = function ( _attr , _mask ) {
497- masks [ _attr ] = _mask ;
466+ if ( ! _mask ) {
467+ delete masks [ _attr ] ;
468+ } else {
469+ masks [ _attr ] = _mask === true ? FULL_MASK : _mask ;
470+ }
498471 } ;
499472
500473 // registers a new global hook
@@ -587,21 +560,15 @@ angular.module('plRestmod').provider('$restmod', function() {
587560 /**
588561 * @memberof Model#
589562 *
590- * @description Iterates over the object properties
563+ * @description Iterates over the object non-private properties
591564 *
592565 * @param {function } _fun Function to call for each
593- * @param {SyncMask } _mask Mask used to filter the returned properties, defaults to SyncMask.SYSTEM
594566 * @return {Model } self
595567 */
596- $each : function ( _fun , _mask , _ctx ) {
597- if ( _mask === undefined ) _mask = SyncMask . SYSTEM ;
598-
568+ $each : function ( _fun , _ctx ) {
599569 for ( var key in this ) {
600- if ( this . hasOwnProperty ( key ) ) {
601- // Only iterate at base level for now
602- if ( ! ( ( masks [ key ] || 0 ) & _mask ) ) {
603- _fun . call ( _ctx || this [ key ] , this [ key ] , key ) ;
604- }
570+ if ( this . hasOwnProperty ( key ) && key [ 0 ] !== '$' ) {
571+ _fun . call ( _ctx || this [ key ] , this [ key ] , key ) ;
605572 }
606573 }
607574
@@ -703,11 +670,10 @@ angular.module('plRestmod').provider('$restmod', function() {
703670 * @description Feed raw data to this instance.
704671 *
705672 * @param {object } _raw Raw data to be fed
706- * @param {string } _mask Action mask
707673 * @return {Model } this
708674 */
709675 $decode : function ( _raw , _mask ) {
710- transform ( _raw , this , '' , _mask || SyncMask . DECODE_USER , true , this ) ;
676+ transform ( _raw , this , '' , _mask || READ_MASK , true , this ) ;
711677 if ( ! this . $pk ) this . $pk = Model . $inferKey ( this ) ; // TODO: improve this, warn if key changes
712678 callback ( 'after-feed' , this , _raw ) ;
713679 return this ;
@@ -722,7 +688,7 @@ angular.module('plRestmod').provider('$restmod', function() {
722688 * @return {Model } this
723689 */
724690 $encode : function ( _mask ) {
725- var raw = transform ( this , this , '' , _mask || SyncMask . ENCODE_USER , false ) ;
691+ var raw = transform ( this , this , '' , _mask || CREATE_MASK , false ) ;
726692 callback ( 'before-render' , this , raw ) ;
727693 return raw ;
728694 } ,
@@ -772,12 +738,12 @@ angular.module('plRestmod').provider('$restmod', function() {
772738
773739 if ( url ) {
774740 // If bound, update
775- request = { method : 'PUT' , url : url , data : this . $encode ( SyncMask . ENCODE_UPDATE ) } ;
741+ request = { method : 'PUT' , url : url , data : this . $encode ( CREATE_MASK ) } ;
776742 callback ( 'before-update' , this , request ) ;
777743 callback ( 'before-save' , this , request ) ;
778744 return this . $send ( request , function ( _response ) {
779745 var data = _response . data ;
780- if ( data && ! isArray ( data ) ) this . $decode ( data , SyncMask . DECODE_UPDATE ) ;
746+ if ( data && ! isArray ( data ) ) this . $decode ( data ) ;
781747 callback ( 'after-update' , this , _response ) ;
782748 callback ( 'after-save' , this , _response ) ;
783749 } , function ( _response ) {
@@ -788,12 +754,12 @@ angular.module('plRestmod').provider('$restmod', function() {
788754 // If not bound create.
789755 url = this . $scope . $createUrlFor ? this . $scope . $createUrlFor ( this . $pk ) : ( this . $scope . $url && this . $scope . $url ( ) ) ;
790756 if ( ! url ) throw new Error ( 'Create is not supported by this resource' ) ;
791- request = { method : 'POST' , url : url , data : this . $encode ( SyncMask . ENCODE_CREATE ) } ;
757+ request = { method : 'POST' , url : url , data : this . $encode ( UPDATE_MASK ) } ;
792758 callback ( 'before-save' , this , request ) ;
793759 callback ( 'before-create' , this , request ) ;
794760 return this . $send ( request , function ( _response ) {
795761 var data = _response . data ;
796- if ( data && ! isArray ( data ) ) this . $decode ( data , SyncMask . DECODE_CREATE ) ;
762+ if ( data && ! isArray ( data ) ) this . $decode ( data ) ;
797763 callback ( 'after-create' , this , _response ) ;
798764 callback ( 'after-save' , this , _response ) ;
799765 } , function ( _response ) {
@@ -1508,23 +1474,28 @@ angular.module('plRestmod').provider('$restmod', function() {
15081474 *
15091475 * @description Sets an attribute mask.
15101476 *
1477+ * An attribute mask prevents the attribute to be loaded from or sent to the server on certain operations.
1478+ *
1479+ * The attribute mask is a string composed by:
1480+ * * C: To prevent attribute from being sent on create
1481+ * * R: To prevent attribute from being loaded from server
1482+ * * U: To prevent attribute from being sent on update
1483+ *
1484+ * For example, the following will prevent an attribute to be send on create or update:
1485+ *
1486+ * ```javascript
1487+ * builder.attrMask('readOnly', 'CU');
1488+ * ```
1489+ *
1490+ * If a true boolean value is passed as mask, then 'CRU' will be used
1491+ * If a false boolean valus is passed as mask, then mask will be removed
1492+ *
15111493 * @param {string } _attr Attribute name
1512- * @param {boolean|integer } _mask Ignore mask or true to use SyncMask.ALL
1513- * @param {boolean } _reset If set to true, old mask is reset.
1494+ * @param {boolean|string } _mask Attribute mask
15141495 * @return {ModelBuilder } self
15151496 */
1516- attrMask : function ( _attr , _mask , _reset ) {
1517-
1518- if ( _mask === true ) {
1519- masks [ _attr ] = SyncMask . ALL ;
1520- } else if ( _mask === false ) {
1521- delete masks [ _attr ] ;
1522- } else if ( _reset ) {
1523- masks [ _attr ] = _mask ;
1524- } else {
1525- masks [ _attr ] |= _mask ;
1526- }
1527-
1497+ attrMask : function ( _attr , _mask ) {
1498+ Model . $$setMask ( _attr , _mask ) ;
15281499 return this ;
15291500 } ,
15301501
@@ -1617,7 +1588,7 @@ angular.module('plRestmod').provider('$restmod', function() {
16171588 _model = $injector . get ( _model ) ;
16181589
16191590 if ( _inverseOf ) {
1620- _model . $$setMask ( _inverseOf , SyncMask . ENCODE ) ;
1591+ _model . $$setMask ( _inverseOf , WRITE_MASK ) ;
16211592 }
16221593 }
16231594
@@ -1642,7 +1613,7 @@ angular.module('plRestmod').provider('$restmod', function() {
16421613 // simple support for inline data, TODO: maybe deprecate this.
16431614 } ) . attrDecoder ( _source || _url || _attr , function ( _raw ) {
16441615 this [ _attr ] . $reset ( ) . $feed ( _raw ) ;
1645- } ) . attrMask ( _attr , SyncMask . ENCODE ) ;
1616+ } ) . attrMask ( _attr , WRITE_MASK ) ;
16461617 } ,
16471618
16481619 /**
@@ -1666,7 +1637,7 @@ angular.module('plRestmod').provider('$restmod', function() {
16661637 _model = $injector . get ( _model ) ;
16671638
16681639 if ( _inverseOf ) {
1669- _model . $$setMask ( _inverseOf , SyncMask . ENCODE ) ;
1640+ _model . $$setMask ( _inverseOf , WRITE_MASK ) ;
16701641 }
16711642 }
16721643
@@ -1685,7 +1656,7 @@ angular.module('plRestmod').provider('$restmod', function() {
16851656 . attrDecoder ( _source || _url || _attr , function ( _raw ) {
16861657 this [ _attr ] . $decode ( _raw ) ;
16871658 } )
1688- . attrMask ( _attr , SyncMask . ENCODE ) ;
1659+ . attrMask ( _attr , WRITE_MASK ) ;
16891660 } ,
16901661
16911662 /**
@@ -1707,7 +1678,7 @@ angular.module('plRestmod').provider('$restmod', function() {
17071678 var watch = _inline ? ( _source || _attr ) : ( _key || ( _attr + 'Id' ) ) ;
17081679 this
17091680 . attrDefault ( _attr , null )
1710- . attrMask ( _attr , SyncMask . ENCODE )
1681+ . attrMask ( _attr , WRITE_MASK )
17111682 . attrDecoder ( watch , function ( _raw ) {
17121683
17131684 // load model
@@ -1892,8 +1863,6 @@ angular.module('plRestmod').provider('$restmod', function() {
18921863} ] )
18931864. factory ( 'mixin' , [ '$restmod' , function ( $restmod ) {
18941865 return $restmod . mixin ;
1895- } ] )
1896- // make SyncMask available as constant
1897- . constant ( 'SyncMask' , SyncMask ) ;
1866+ } ] ) ;
18981867
18991868} ) ( angular ) ;
0 commit comments