1- /*! jquery.views.js v1.0.1 : http://jsviews.com/ */
1+ /*! jquery.views.js v1.0.2 : http://jsviews.com/ */
22/*
33 * Interactive data-driven views using JsRender templates.
44 * Subcomponent of JsViews
77 * Also requires jquery.observable.js
88 * See JsObservable at http://jsviews.com/#download and http://github.com/BorisMoore/jsviews
99 *
10- * Copyright 2018 , Boris Moore
10+ * Copyright 2019 , Boris Moore
1111 * Released under the MIT License.
1212 */
1313
@@ -44,7 +44,7 @@ var setGlobals = $ === false; // Only set globals if script block in browser (no
4444jsr = jsr || setGlobals && global . jsrender ;
4545$ = $ || global . jQuery ;
4646
47- var versionNumber = "v1.0.1 " ,
47+ var versionNumber = "v1.0.2 " ,
4848 requiresStr = "JsViews requires " ;
4949
5050if ( ! $ || ! $ . fn ) {
@@ -167,7 +167,7 @@ function updateValues(sourceValues, tagElse, bindId, ev) {
167167// Called when linkedElem of a tag control changes: as updateValue(val, index, tagElse, bindId, ev) - this: undefined
168168// Called directly as tag.updateValues(val1, val2, val3, ...) - this: tag
169169 var linkCtx , cvtBack , cnvtName , target , view , binding , sourceValue , origVals , sourceElem , sourceEl ,
170- oldLinkCtx , tos , to , tcpTag , exprOb , contextCb , l , m , tag ;
170+ tos , to , tcpTag , exprOb , contextCb , l , m , tag ;
171171
172172 if ( bindId && bindId . _tgId ) {
173173 tag = bindId ;
@@ -223,9 +223,6 @@ function updateValues(sourceValues, tagElse, bindId, ev) {
223223 // the first arg, but all of them by returning an array.
224224 }
225225
226- // Set linkCtx on view, dynamically, just during this handler call
227- oldLinkCtx = view . _lc ;
228- view . _lc = linkCtx ;
229226 l = tos . length ;
230227 while ( l -- ) {
231228 if ( to = tos [ l ] ) {
@@ -273,7 +270,6 @@ function updateValues(sourceValues, tagElse, bindId, ev) {
273270 }
274271 }
275272 }
276- view . _lc = oldLinkCtx ;
277273 }
278274 if ( tag ) {
279275 tag . _ . chg = undefined ; // Clear marker
@@ -319,12 +315,12 @@ function onDataLinkedTagChange(ev, eventArgs) {
319315 oldLinkCtx = view . _lc ,
320316 onEvent = eventArgs && changeHandler ( view , onBeforeChangeStr , tag ) ;
321317
322- // Set linkCtx on view, dynamically, just during this handler call
323- view . _lc = linkCtx ;
324318 if ( parentElem && ( ! onEvent || onEvent . call ( tag || linkCtx , ev , eventArgs ) !== false )
325319 // If data changed, the ev.data is set to be the path. Use that to filter the handler action...
326320 && ( ! eventArgs || ev . data . prop === "*" || ev . data . prop === eventArgs . path ) ) {
327321
322+ // Set linkCtx on view, dynamically, just during this handler call
323+ view . _lc = linkCtx ;
328324 if ( eventArgs ) {
329325 linkCtx . eventArgs = eventArgs ;
330326 }
@@ -371,12 +367,13 @@ function onDataLinkedTagChange(ev, eventArgs) {
371367 // from the sourceValue (which may optionally have been modifed in onUpdate()...) and then bind, and we are done
372368 observeAndBind ( linkCtx , source , target ) ;
373369 }
370+ // Remove dynamically added linkCtx from view
374371 view . _lc = oldLinkCtx ;
375372 if ( eventArgs && ( onEvent = changeHandler ( view , onAfterChangeStr , tag ) ) ) {
376373 onEvent . call ( tag || linkCtx , ev , eventArgs ) ;
377374 }
378375 if ( tag . tagCtx . props . dataMap ) {
379- tag . tagCtx . props . dataMap . map ( tag . tagCtx . args [ 0 ] , tag . tagCtx , tag . tagCtx . map , ! tag . _ . bnd ) ;
376+ tag . tagCtx . props . dataMap . map ( tag . tagCtx . args [ 0 ] , tag . tagCtx , tag . tagCtx . map , isRenderCall || ! tag . _ . bnd ) ;
380377 }
381378 return ;
382379 }
@@ -456,7 +453,6 @@ function updateContent(sourceValue, linkCtx, attr, tag) {
456453 $target = $ ( target ) ,
457454 view = linkCtx . view ,
458455 targetVal = linkCtx . _val ,
459- oldLinkCtx = view . _lc ,
460456 change = tag ;
461457
462458 if ( tag ) {
@@ -545,8 +541,6 @@ function updateContent(sourceValue, linkCtx, attr, tag) {
545541
546542 if ( setter = fnSetters [ attr ] ) {
547543 if ( attr === HTML ) {
548- // Set linkCtx on view, dynamically, just during this handler call
549- view . _lc = linkCtx ;
550544 if ( tag && tag . inline ) {
551545 nodesToRemove = tag . nodes ( true ) ;
552546 if ( tag . _elCnt ) {
@@ -595,8 +589,6 @@ function updateContent(sourceValue, linkCtx, attr, tag) {
595589 late = view . link ( source , target , prevNode , nextNode , sourceValue , tag && { tag : tag . _tgId } ) ;
596590 }
597591 }
598- // Remove dynamically added linkCtx and ctx from view
599- view . _lc = oldLinkCtx ;
600592 } else {
601593 if ( change = change || targetVal !== sourceValue ) {
602594 if ( attr === "text" && target . children && ! target . children [ 0 ] ) {
@@ -865,15 +857,15 @@ function observeAndBind(linkCtx, source, target) {
865857 $observable . _apply ( 1 , [ source ] , exprFnDeps , linkCtx . _depends , handler , linkCtx . _ctxCb , true ) ;
866858 }
867859
868- if ( tag && tag . boundProps ) {
860+ if ( tag ) {
869861 // Add dependency paths for declared boundProps (so no need to write ^myprop=... to get binding) and for linkedProp too if there is one
870862 l = tag . boundProps . length ;
871863 while ( l -- ) {
872864 prop = tag . boundProps [ l ] ;
873865 k = tag . _ . bnd . paths . length ;
874- while ( k -- ) {
866+ while ( k -- ) { // Iterate across tagCtxs
875867 propDeps = tag . _ . bnd . paths [ k ] [ "_" + prop ] ;
876- if ( propDeps && propDeps . skp ) { // Not already a bound prop ^prop=expression;
868+ if ( propDeps && propDeps . length && propDeps . skp ) { // Not already a bound prop ^prop=expression;
877869 exprFnDeps = exprFnDeps . concat ( propDeps ) ; // Add dependencies for this prop expression
878870 }
879871 }
@@ -1901,7 +1893,8 @@ function callAfterLink(tag, ev, eventArgs) {
19011893 }
19021894 }
19031895
1904- var linkedElems , linkedElements , linkedElem , l , m , $linkCtxElem , linkCtxElem , linkedEl , linkedTag , tagCtxElse , props , val , oldVal , indexTo ,
1896+ var linkedElems , linkedElements , linkedElem , l , m , $linkCtxElem , linkCtxElem , linkedEl , linkedTag ,
1897+ tagCtxElse , props , val , oldVal , indexTo , i , mapDeps , propDeps ,
19051898 tagCtx = tag . tagCtx ,
19061899 tagCtxs = tag . tagCtxs ,
19071900 tagCtxslength = tagCtxs && tagCtxs . length ,
@@ -1970,6 +1963,22 @@ function callAfterLink(tag, ev, eventArgs) {
19701963 tagCtxElse = tagCtxs [ m ] ;
19711964 props = tagCtxElse . props ;
19721965
1966+ if ( tag . _ . unlinked && tagCtxElse . map && tag . mapProps ) {
1967+ // Compile the dependency paths for observable changes in mapProps (e.g. start, end, filter)
1968+ i = tag . mapProps . length ;
1969+ mapDeps = props . mapDepends || tag . mapDepends || [ ] ; // dependency paths
1970+ mapDeps = $isArray ( mapDeps ) ? mapDeps : [ mapDeps ] ;
1971+ while ( i -- ) { // Iterate through mapProps
1972+ var prop = tag . mapProps [ i ] ;
1973+ propDeps = tag . _ . bnd . paths [ m ] [ "_" + prop ] ; // paths for mapProps on this tagCtx
1974+ if ( propDeps && propDeps . length && propDeps . skp ) { // Not already a bound prop ^prop=expression;
1975+ mapDeps = mapDeps . concat ( propDeps ) ; // Add dependencies for this prop expression
1976+ }
1977+ }
1978+ if ( mapDeps . length ) {
1979+ tagCtxElse . map . observe ( mapDeps , linkCtx ) ; // Listen to observable changes of mapProps, and call map.update when change happens
1980+ }
1981+ }
19731982 if ( linkedElem = tagCtxElse . mainElem || ! tag . mainElement && tagCtxElse . linkedElems && tagCtxElse . linkedElems [ 0 ] ) {
19741983 // linkedElem is the mainElem (defaulting to linkedElem)
19751984 if ( linkedElem [ 0 ] && props . id && ! linkedElem [ 0 ] . id ) {
@@ -3264,12 +3273,12 @@ $extend($tags["for"], {
32643273 }
32653274 }
32663275 } ) ,
3267- boundProps : [ "filter" , "sort" , "reverse" , "start" , "end" ] ,
3276+ mapProps : [ "filter" , "sort" , "reverse" , "start" , "end" , "step "] ,
32683277 bindTo : [ "paged" , "sorted" ] ,
32693278 bindFrom : [ 0 ] ,
32703279
32713280 onArrayChange : function ( ev , eventArgs , tagCtx , linkCtx ) {
3272- var arrayView ,
3281+ var arrayView , propsArr ,
32733282 targetLength = ev . target . length ,
32743283 tag = this ;
32753284 if ( ! tag . rendering ) {
@@ -3278,7 +3287,11 @@ $extend($tags["for"], {
32783287 eventArgs . change === "insert" && targetLength === eventArgs . items . length // inserting, and new length is same as inserted length, so going from 0 to n
32793288 || eventArgs . change === "remove" && ! targetLength ) // removing, and new length 0, so going from n to 0
32803289 ) {
3290+ propsArr = tagCtx . map && tagCtx . map . propsArr ; // Used by {{props}}, which derives from {{for}}
32813291 tag . refresh ( ) ;
3292+ if ( propsArr ) {
3293+ tagCtx . map . propsArr = propsArr ; // Keep previous propsArr with new map
3294+ }
32823295 } else for ( arrayView in tag . _ . arrVws ) {
32833296 arrayView = tag . _ . arrVws [ arrayView ] ;
32843297 if ( arrayView . data === ev . target ) {
@@ -3317,7 +3330,6 @@ $extend($tags["for"], {
33173330 : tagCtx . args . length
33183331 ? tagCtx . args [ 0 ] // or args[0]
33193332 : tagCtx . view . data ; // or defaults to current data.
3320-
33213333 if ( arrayBindings [ i ] ) { // Is there was a previous binding on this tagCtx, (maybe with data different from new data)
33223334 $observe ( arrayBindings [ i ] , true ) ; //unobserve previous array
33233335 delete arrayBindings [ i ] ;
@@ -3402,17 +3414,14 @@ $extend($tags["if"], {
34023414} ) ;
34033415
34043416function observeProps ( map , ev , eventArgs ) {
3405- var props = map . options . tag . tagCtx . props ;
3417+ var target , l , props = map . options . props ;
3418+ updatePropsArr ( map . propsArr , eventArgs . path , eventArgs . value , eventArgs . remove ) ;
34063419 if ( props . sort !== undefined || props . start !== undefined || props . end !== undefined || props . step !== undefined || props . filter || props . reverse ) {
34073420 map . update ( ) ; // refresh sorting and filtering
34083421 } else if ( eventArgs . change === "set" ) {
3409- var target = map . tgt ,
3410- l = target . length ;
3411- while ( l -- ) {
3412- if ( target [ l ] . key === eventArgs . path ) {
3413- break ;
3414- }
3415- }
3422+ target = map . tgt ;
3423+ l = target . length ;
3424+ while ( l -- && target [ l ] . key !== eventArgs . path ) { }
34163425 if ( l === - 1 ) {
34173426 if ( eventArgs . path && ! eventArgs . remove ) {
34183427 $observable ( target ) . insert ( { key : eventArgs . path , prop : eventArgs . value } ) ;
@@ -3426,7 +3435,7 @@ function observeProps(map, ev, eventArgs) {
34263435}
34273436
34283437function observeMappedProps ( map , ev , eventArgs ) {
3429- var items , l , key ,
3438+ var items , l , key , remove ,
34303439 source = map . src ,
34313440 change = eventArgs . change ;
34323441
@@ -3437,12 +3446,13 @@ function observeMappedProps(map, ev, eventArgs) {
34373446 $observable ( source ) . removeProperty ( eventArgs . oldValue ) ; // When key is modified observably, remove old one and set new one
34383447 $observable ( source ) . setProperty ( eventArgs . value , ev . target . prop ) ;
34393448 }
3440- } else if ( change === "insert" || change === "remove" ) {
3449+ } else if ( change === "insert" || ( remove = change === "remove" ) ) {
34413450 items = eventArgs . items ;
34423451 l = items . length ;
34433452 while ( l -- ) {
34443453 if ( key = items [ l ] . key ) {
3445- if ( change === "remove" ) {
3454+ updatePropsArr ( map . propsArr , key , items [ l ] . prop , remove ) ;
3455+ if ( remove ) {
34463456 $observable ( source ) . removeProperty ( key ) ;
34473457 delete source [ key ] ;
34483458 } else {
@@ -3453,6 +3463,18 @@ function observeMappedProps(map, ev, eventArgs) {
34533463 }
34543464}
34553465
3466+ function updatePropsArr ( propsArr , key , prop , remove ) {
3467+ var l = propsArr . length ;
3468+ while ( l -- && propsArr [ l ] . key !== key ) { }
3469+ if ( l === - 1 ) {
3470+ if ( key && ! remove ) {
3471+ propsArr . push ( { key : key , prop : prop } ) ;
3472+ }
3473+ } else if ( remove ) {
3474+ propsArr . splice ( l , 1 ) ;
3475+ }
3476+ }
3477+
34563478function shallowArrayFilter ( path /*, object, parentObs*/ ) { // Filter used by {{props}} for the mappedProps target array
34573479 return rShallowArrayPath . test ( path ) ; // No '.' in path
34583480}
0 commit comments