@@ -65,6 +65,81 @@ angular.module('schemaForm').provider('sfPath',
6565 } ;
6666} ] ) ;
6767
68+ /**
69+ * @ngdoc service
70+ * @name sfSelect
71+ * @kind function
72+ *
73+ */
74+ angular . module ( 'schemaForm' ) . factory ( 'sfSelect' , [ 'sfPath' , function ( sfPath ) {
75+ var numRe = / ^ \d + $ / ;
76+
77+ /**
78+ * @description
79+ * Utility method to access deep properties without
80+ * throwing errors when things are not defined.
81+ * Can also set a value in a deep structure, creating objects when missing
82+ * ex.
83+ * var foo = Select('address.contact.name',obj)
84+ * Select('address.contact.name',obj,'Leeroy')
85+ *
86+ * @param {string } projection A dot path to the property you want to get/set
87+ * @param {object } obj (optional) The object to project on, defaults to 'this'
88+ * @param {Any } valueToSet (opional) The value to set, if parts of the path of
89+ * the projection is missing empty objects will be created.
90+ * @returns {Any|undefined } returns the value at the end of the projection path
91+ * or undefined if there is none.
92+ */
93+ return function ( projection , obj , valueToSet ) {
94+ if ( ! obj ) {
95+ obj = this ;
96+ }
97+ //Support [] array syntax
98+ var parts = typeof projection === 'string' ? sfPath . parse ( projection ) : projection ;
99+
100+ if ( typeof valueToSet !== 'undefined' && parts . length === 1 ) {
101+ //special case, just setting one variable
102+ obj [ parts [ 0 ] ] = valueToSet ;
103+ return obj ;
104+ }
105+
106+ if ( typeof valueToSet !== 'undefined' &&
107+ typeof obj [ parts [ 0 ] ] === 'undefined' ) {
108+ // We need to look ahead to check if array is appropriate
109+ obj [ parts [ 0 ] ] = parts . length > 2 && numRe . test ( parts [ 1 ] ) ? [ ] : { } ;
110+ }
111+
112+ var value = obj [ parts [ 0 ] ] ;
113+ for ( var i = 1 ; i < parts . length ; i ++ ) {
114+ // Special case: We allow JSON Form syntax for arrays using empty brackets
115+ // These will of course not work here so we exit if they are found.
116+ if ( parts [ i ] === '' ) {
117+ return undefined ;
118+ }
119+ if ( typeof valueToSet !== 'undefined' ) {
120+ if ( i === parts . length - 1 ) {
121+ //last step. Let's set the value
122+ value [ parts [ i ] ] = valueToSet ;
123+ return valueToSet ;
124+ } else {
125+ // Make sure to create new objects on the way if they are not there.
126+ // We need to look ahead to check if array is appropriate
127+ var tmp = value [ parts [ i ] ] ;
128+ if ( typeof tmp === 'undefined' || tmp === null ) {
129+ tmp = numRe . test ( parts [ i + 1 ] ) ? [ ] : { } ;
130+ value [ parts [ i ] ] = tmp ;
131+ }
132+ value = tmp ;
133+ }
134+ } else if ( value ) {
135+ //Just get nex value.
136+ value = value [ parts [ i ] ] ;
137+ }
138+ }
139+ return value ;
140+ } ;
141+ } ] ) ;
142+
68143
69144// FIXME: type template (using custom builder)
70145angular . module ( 'schemaForm' ) . provider ( 'sfBuilder' , [ 'sfPathProvider' , function ( sfPathProvider ) {
@@ -78,9 +153,19 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
78153 } ;
79154 var formId = 0 ;
80155
156+ if ( ! ( "firstElementChild" in document . createDocumentFragment ( ) ) ) {
157+ Object . defineProperty ( DocumentFragment . prototype , "firstElementChild" , {
158+ get : function ( ) {
159+ for ( var nodes = this . childNodes , n , i = 0 , l = nodes . length ; i < l ; ++ i )
160+ if ( n = nodes [ i ] , 1 === n . nodeType ) return n ;
161+ return null ;
162+ }
163+ } ) ;
164+ }
165+
81166 var builders = {
82167 sfField : function ( args ) {
83- args . fieldFrag . firstChild . setAttribute ( 'sf-field' , formId ) ;
168+ args . fieldFrag . firstElementChild . setAttribute ( 'sf-field' , formId ) ;
84169
85170 // We use a lookup table for easy access to our form.
86171 args . lookup [ 'f' + formId ] = args . form ;
@@ -183,24 +268,27 @@ angular.module('schemaForm').provider('sfBuilder', ['sfPathProvider', function(s
183268 }
184269
185270 var children = args . fieldFrag . children || args . fieldFrag . childNodes ;
271+ var child ;
272+ var ngIf ;
186273 for ( var i = 0 ; i < children . length ; i ++ ) {
187- var child = children [ i ] ;
188- var ngIf = child . getAttribute ( 'ng-if' ) ;
189- child . setAttribute (
190- 'ng-if' ,
191- ngIf ?
192- '(' + ngIf +
193- ') || (' + evalExpr + ')'
194- : evalExpr
195- ) ;
274+ child = children [ i ] ;
275+ ngIf = false ;
276+
277+ if ( child . hasAttribute && child . hasAttribute ( 'ng-if' ) ) {
278+ ngIf = child . getAttribute ( 'ng-if' ) ;
279+ } ;
280+
281+ if ( child . setAttribute ) {
282+ child . setAttribute ( 'ng-if' , ngIf ? '(' + ngIf + ') || (' + evalExpr + ')' : evalExpr ) ;
283+ } ;
196284 }
197285 }
198286 } ,
199287 array : function ( args ) {
200288 var items = args . fieldFrag . querySelector ( '[schema-form-array-items]' ) ;
201289 if ( items ) {
202290 state = angular . copy ( args . state ) ;
203- state . keyRedaction = state . keyRedaction || 0 ;
291+ state . keyRedaction = 0 ;
204292 state . keyRedaction += args . form . key . length + 1 ;
205293
206294 // Special case, an array with just one item in it that is not an object.
@@ -489,8 +577,14 @@ angular.module('schemaForm').provider('schemaFormDecorators',
489577 if ( ! scope . ngModel ) {
490578 return false ;
491579 }
492- return scope . ngModel . $valid &&
493- ( ! scope . ngModel . $pristine || ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
580+ if ( scope . options && scope . options . pristine &&
581+ scope . options . pristine . success === false ) {
582+ return scope . ngModel . $valid &&
583+ ( ! scope . ngModel . $pristine && ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
584+ } else {
585+ return scope . ngModel . $valid &&
586+ ( ! scope . ngModel . $pristine || ! scope . ngModel . $isEmpty ( scope . ngModel . $modelValue ) ) ;
587+ }
494588 } ;
495589
496590 scope . hasError = function ( ) {
@@ -580,12 +674,20 @@ angular.module('schemaForm').provider('schemaFormDecorators',
580674 // It looks better with dot notation.
581675 scope . $on (
582676 'schemaForm.error.' + form . key . join ( '.' ) ,
583- function ( event , error , validationMessage , validity ) {
677+ function ( event , error , validationMessage , validity , formName ) {
678+ // validationMessage and validity are mutually exclusive
679+ formName = validity ;
584680 if ( validationMessage === true || validationMessage === false ) {
585681 validity = validationMessage ;
586682 validationMessage = undefined ;
587683 }
588684
685+ // If we have specified a form name, and this model is not within
686+ // that form, then leave things be.
687+ if ( formName != undefined && scope . ngModel . $$parentForm . $name !== formName ) {
688+ return ;
689+ }
690+
589691 if ( scope . ngModel && error ) {
590692 if ( scope . ngModel . $setDirty ) {
591693 scope . ngModel . $setDirty ( ) ;
@@ -1171,6 +1273,7 @@ angular.module('schemaForm').provider('schemaForm',
11711273 if ( stripNullType ( schema . type ) === 'object' ) {
11721274 var f = stdFormObj ( name , schema , options ) ;
11731275 f . type = 'fieldset' ;
1276+ f . key = options . path ;
11741277 f . items = [ ] ;
11751278 options . lookup [ sfPathProvider . stringify ( options . path ) ] = f ;
11761279
@@ -1389,7 +1492,7 @@ angular.module('schemaForm').provider('schemaForm',
13891492 if ( obj . type === 'checkbox' && angular . isUndefined ( obj . schema [ 'default' ] ) ) {
13901493 obj . schema [ 'default' ] = false ;
13911494 }
1392-
1495+
13931496 // Special case: template type with tempplateUrl that's needs to be loaded before rendering
13941497 // TODO: this is not a clean solution. Maybe something cleaner can be made when $ref support
13951498 // is introduced since we need to go async then anyway
@@ -1481,81 +1584,6 @@ angular.module('schemaForm').provider('schemaForm',
14811584
14821585} ] ) ;
14831586
1484- /**
1485- * @ngdoc service
1486- * @name sfSelect
1487- * @kind function
1488- *
1489- */
1490- angular . module ( 'schemaForm' ) . factory ( 'sfSelect' , [ 'sfPath' , function ( sfPath ) {
1491- var numRe = / ^ \d + $ / ;
1492-
1493- /**
1494- * @description
1495- * Utility method to access deep properties without
1496- * throwing errors when things are not defined.
1497- * Can also set a value in a deep structure, creating objects when missing
1498- * ex.
1499- * var foo = Select('address.contact.name',obj)
1500- * Select('address.contact.name',obj,'Leeroy')
1501- *
1502- * @param {string } projection A dot path to the property you want to get/set
1503- * @param {object } obj (optional) The object to project on, defaults to 'this'
1504- * @param {Any } valueToSet (opional) The value to set, if parts of the path of
1505- * the projection is missing empty objects will be created.
1506- * @returns {Any|undefined } returns the value at the end of the projection path
1507- * or undefined if there is none.
1508- */
1509- return function ( projection , obj , valueToSet ) {
1510- if ( ! obj ) {
1511- obj = this ;
1512- }
1513- //Support [] array syntax
1514- var parts = typeof projection === 'string' ? sfPath . parse ( projection ) : projection ;
1515-
1516- if ( typeof valueToSet !== 'undefined' && parts . length === 1 ) {
1517- //special case, just setting one variable
1518- obj [ parts [ 0 ] ] = valueToSet ;
1519- return obj ;
1520- }
1521-
1522- if ( typeof valueToSet !== 'undefined' &&
1523- typeof obj [ parts [ 0 ] ] === 'undefined' ) {
1524- // We need to look ahead to check if array is appropriate
1525- obj [ parts [ 0 ] ] = parts . length > 2 && numRe . test ( parts [ 1 ] ) ? [ ] : { } ;
1526- }
1527-
1528- var value = obj [ parts [ 0 ] ] ;
1529- for ( var i = 1 ; i < parts . length ; i ++ ) {
1530- // Special case: We allow JSON Form syntax for arrays using empty brackets
1531- // These will of course not work here so we exit if they are found.
1532- if ( parts [ i ] === '' ) {
1533- return undefined ;
1534- }
1535- if ( typeof valueToSet !== 'undefined' ) {
1536- if ( i === parts . length - 1 ) {
1537- //last step. Let's set the value
1538- value [ parts [ i ] ] = valueToSet ;
1539- return valueToSet ;
1540- } else {
1541- // Make sure to create new objects on the way if they are not there.
1542- // We need to look ahead to check if array is appropriate
1543- var tmp = value [ parts [ i ] ] ;
1544- if ( typeof tmp === 'undefined' || tmp === null ) {
1545- tmp = numRe . test ( parts [ i + 1 ] ) ? [ ] : { } ;
1546- value [ parts [ i ] ] = tmp ;
1547- }
1548- value = tmp ;
1549- }
1550- } else if ( value ) {
1551- //Just get nex value.
1552- value = value [ parts [ i ] ] ;
1553- }
1554- }
1555- return value ;
1556- } ;
1557- } ] ) ;
1558-
15591587/* Common code for validating a value against its form and schema definition */
15601588/* global tv4 */
15611589angular . module ( 'schemaForm' ) . factory ( 'sfValidator' , [ function ( ) {
@@ -2085,12 +2113,20 @@ angular.module('schemaForm').directive('sfField',
20852113 // It looks better with dot notation.
20862114 scope . $on (
20872115 'schemaForm.error.' + form . key . join ( '.' ) ,
2088- function ( event , error , validationMessage , validity ) {
2116+ function ( event , error , validationMessage , validity , formName ) {
2117+ // validationMessage and validity are mutually exclusive
2118+ formName = validity ;
20892119 if ( validationMessage === true || validationMessage === false ) {
20902120 validity = validationMessage ;
20912121 validationMessage = undefined ;
20922122 }
20932123
2124+ // If we have specified a form name, and this model is not within
2125+ // that form, then leave things be.
2126+ if ( formName != undefined && scope . ngModel . $$parentForm . $name !== formName ) {
2127+ return ;
2128+ }
2129+
20942130 if ( scope . ngModel && error ) {
20952131 if ( scope . ngModel . $setDirty ) {
20962132 scope . ngModel . $setDirty ( ) ;
@@ -2388,15 +2424,12 @@ function(sel, sfPath, schemaForm) {
23882424 if ( vals && vals !== old ) {
23892425 var arr = getOrCreateModel ( ) ;
23902426
2391- // Apparently the fastest way to clear an array, readable too.
2392- // http://jsperf.com/array-destroy/32
2393- while ( arr . length > 0 ) {
2394- arr . pop ( ) ;
2395- }
2396- form . titleMap . forEach ( function ( item , index ) {
2397- if ( vals [ index ] ) {
2427+ form . titleMap . forEach ( function ( item , index ) {
2428+ var arrIndex = arr . indexOf ( item . value ) ;
2429+ if ( arrIndex === - 1 && vals [ index ] )
23982430 arr . push ( item . value ) ;
2399- }
2431+ if ( arrIndex !== - 1 && ! vals [ index ] )
2432+ arr . splice ( arrIndex , 1 ) ;
24002433 } ) ;
24012434
24022435 // Time to validate the rebuilt array.
0 commit comments