Skip to content

Commit

Permalink
v1.0.10 release
Browse files Browse the repository at this point in the history
Minor bug fixes:

See #451

- Binding to a computed function with no getter, such as <input data-link="name()"/>
  with name.set undefined leads to an exception: "name is not a function".
- Tag two-way binding to a computed observable, such as {^{mytag name()/}}
  can trigger onBind callback twice.2
  • Loading branch information
BorisMoore committed Jan 10, 2021
1 parent 51c1947 commit 0eb921e
Show file tree
Hide file tree
Showing 29 changed files with 438 additions and 263 deletions.
22 changes: 12 additions & 10 deletions jquery.observable.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*! JsObservable v1.0.9: http://jsviews.com/#jsobservable */
/*! JsObservable v1.0.10: http://jsviews.com/#jsobservable */
/*
* Subcomponent of JsViews
* Data change events for data-linking
*
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -44,7 +44,7 @@ if (!$ || !$.fn) {
throw "jquery.observable.js requires jQuery"; // We require jQuery
}

var versionNumber = "v1.0.9",
var versionNumber = "v1.0.10",
_ocp = "_ocp", // Observable contextual parameter
$observe, $observable,

Expand Down Expand Up @@ -897,7 +897,7 @@ if (!$.observe) {
return this._data;
},

setProperty: function(path, value, nonStrict) {
setProperty: function(path, value, nonStrict, isCpfn) {
path = path || "";
var key, pair, parts, tempBatch,
multi = path + "" !== path, // Hash of paths
Expand Down Expand Up @@ -937,7 +937,7 @@ if (!$.observe) {
object = object[parts.shift()];
}
if (object) {
self._setProperty(object, parts[0], value, nonStrict);
self._setProperty(object, parts[0], value, nonStrict, isCpfn);
}
}
}
Expand All @@ -949,12 +949,13 @@ if (!$.observe) {
return this;
},

_setProperty: function(leaf, path, value, nonStrict) {
_setProperty: function(leaf, path, value, nonStrict, isCpfn) {
var setter, getter, removeProp, eventArgs, view,
property = path ? leaf[path] : leaf;

if (property !== value || nonStrict && property != value) {
if ($isFunction(property) && property.set) {
if ($isFunction(property) && !$isFunction(value)) {
if (isCpfn && !property.set) {
return; // getter function with no setter defined. So will not trigger update
} else if (property.set) {
// Case of property setter/getter - with convention that property is getter and property.set is setter
view = leaf._vw // Case of JsViews 2-way data-linking to an observable context parameter, with a setter.
// The view will be the this pointer for getter and setter. Note: this is the one scenario where path is "".
Expand All @@ -964,7 +965,8 @@ if (!$.observe) {
property = getter.call(view); // get - only treated as getter if also a setter. Otherwise it is simply a property of type function.
// See unit tests 'Can observe properties of type function'.
}

}
if (property !== value || nonStrict && property != value) {
// Optional non-strict equality, since serializeArray, and form-based editors can map numbers to strings, etc.
// Date objects don't support != comparison. Treat as special case.
if (!(property instanceof Date && value instanceof Date) || property > value || property < value) {
Expand Down
4 changes: 2 additions & 2 deletions jquery.observable.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jquery.observable.min.js.map

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions jquery.views.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! jquery.views.js v1.0.9: http://jsviews.com/ */
/*! jquery.views.js v1.0.10: http://jsviews.com/ */
/*
* Interactive data-driven views using JsRender templates.
* Subcomponent of JsViews
Expand All @@ -7,7 +7,7 @@
* Also requires jquery.observable.js
* See JsObservable at http://jsviews.com/#download and http://github.com/BorisMoore/jsviews
*
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -44,7 +44,7 @@ var setGlobals = $ === false; // Only set globals if script block in browser (no
jsr = jsr || setGlobals && global.jsrender;
$ = $ || global.jQuery;

var versionNumber = "v1.0.9",
var versionNumber = "v1.0.10",
requiresStr = "jquery.views.js requires ";

if (!$ || !$.fn) {
Expand Down Expand Up @@ -294,7 +294,7 @@ function updateValues(sourceValues, tagElse, async, bindId, ev) {
exprOb = exprOb.sb;
}
}
$observable(target, async).setProperty(to[1], sourceValue); // 2way binding change event - observably updating bound object
$observable(target, async).setProperty(to[1], sourceValue, undefined, to.isCpfn); // 2way binding change event - observably updating bound object
}
}
}
Expand Down Expand Up @@ -2156,7 +2156,7 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
// we bind to the path on the returned object, exprOb.ob, as target. Otherwise our target is the first path, paths[0], which we will convert
// with contextCb() for paths like ~a.b.c or #x.y.z

var pathIndex, path, lastPath, bindtoOb, to, bindTo, paths, k, obsCtxPrm, linkedCtxParam, contextCb, targetPaths, bindTos, fromIndex,
var pathIndex, path, lastPath, bindtoOb, to, bindTo, paths, k, obsCtxPrm, linkedCtxParam, contextCb, targetPaths, bindTos, fromIndex, isCpfn,
tagElse = 1,
tos = [],
linkCtx = binding.linkCtx,
Expand Down Expand Up @@ -2194,11 +2194,12 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
path = lastPath = lastPath.sb;
}
path = lastPath.sb || path && path.path;
isCpfn = lastPath._cpfn && !lastPath.sb; // leaf binding to computed property/function "a.b.c()"
lastPath = path ? path.slice(1) : bindtoOb.path;
}
to = path
? [bindtoOb, // 'exprOb' for this expression and view-binding. So bindtoOb.ob is current object returned by expression.
lastPath]
lastPath]
: resolveDataTargetPath(lastPath, source, contextCb); // Get 'to' for target path: lastPath
} else {
// Contextual parameter ~foo with no external binding - has ctx.foo = [{_ocp: xxx}] and binds to ctx.foo._ocp
Expand All @@ -2214,6 +2215,7 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
// This is a binding for a tag contextual parameter (e.g. <input data-link="~wd"/> within a tag block content
to = obsCtxPrm;
}
to.isCpfn = isCpfn;
bindTos.unshift(to);
}
}
Expand Down Expand Up @@ -2761,7 +2763,7 @@ function addLinkMethods(tagOrView) { // tagOrView is View prototype or tag insta
indexFrom = indexFrom || 0;
tagElse = tagElse || 0;

var linkedElem, linkedEl, linkedCtxParam, linkedCtxPrmKey, indexTo, linkedElems, newVal,
var linkedElem, linkedEl, linkedCtxParam, indexTo, linkedElems, newVal,
tagCtx = theTag.tagCtxs[tagElse];

if (tagCtx._bdArgs && (eventArgs || val !== undefined) && tagCtx._bdArgs[indexFrom]===val
Expand All @@ -2782,12 +2784,10 @@ function addLinkMethods(tagOrView) { // tagOrView is View prototype or tag insta
}
}

if (val !== undefined && (linkedCtxParam = theTag.linkedCtxParam) && linkedCtxParam[indexFrom]
if (val !== undefined && (linkedCtxParam = theTag.linkedCtxParam) && linkedCtxParam[indexFrom]) {
// If this setValue call corresponds to a tag contextual parameter and the tag has a converter, then we need to set the
// value of this contextual parameter (since it is not directly bound to the tag argument/property when there is a converter).
&& (linkedCtxPrmKey = linkedCtxParam[indexFrom])
) {
tagCtx.ctxPrm(linkedCtxPrmKey, val);
tagCtx.ctxPrm(linkedCtxParam[indexFrom], val);
}
indexTo = theTag._.toIndex[indexFrom];
if (indexTo !== undefined) {
Expand Down
6 changes: 3 additions & 3 deletions jquery.views.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jquery.views.min.js.map

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions jsrender.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*! JsRender v1.0.9: http://jsviews.com/#jsrender */
/*! JsRender v1.0.10: http://jsviews.com/#jsrender */
/*! **VERSION FOR WEB** (For NODE.JS see http://jsviews.com/download/jsrender-node.js) */
/*
* Best-of-breed templating in browser or on Node.js.
* Does not require jQuery, or HTML DOM
* Integrates with JsViews (http://jsviews.com/#jsviews)
*
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -44,7 +44,7 @@ var setGlobals = $ === false; // Only set globals if script block in browser (no

$ = $ && $.fn ? $ : global.jQuery; // $ is jQuery passed in by CommonJS loader (Browserify), or global jQuery.

var versionNumber = "v1.0.9",
var versionNumber = "v1.0.10",
jsvStoreName, rTag, rTmplString, topView, $views, $expando,
_ocp = "_ocp", // Observable contextual parameter

Expand Down Expand Up @@ -2231,7 +2231,8 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) {
}
if (rtPrnDot && bindings) {
// This is a binding to a path in which an object is returned by a helper/data function/expression, e.g. foo()^x.y or (a?b:c)^x.y
// We create a compiled function to get the object instance (which will be called when the dependent data of the subexpression changes, to return the new object, and trigger re-binding of the subsequent path)
// We create a compiled function to get the object instance (which will be called when the dependent data of the subexpression changes,
// to return the new object, and trigger re-binding of the subsequent path)
expr = pathStart[fnDp-1];
if (full.length - 1 > ind - (expr || 0)) { // We need to compile a subexpression
expr = $.trim(full.slice(expr, ind + all.length));
Expand Down
4 changes: 2 additions & 2 deletions jsrender.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jsrender.min.js.map

Large diffs are not rendered by default.

45 changes: 24 additions & 21 deletions jsviews.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*! jsviews.js v1.0.9 single-file version: http://jsviews.com/ */
/*! jsviews.js v1.0.10 single-file version: http://jsviews.com/ */
/*! includes JsRender, JsObservable and JsViews - see: http://jsviews.com/#download */

/* Interactive data-driven views using JsRender templates */

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< JsRender >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/* JsRender:
* See http://jsviews.com/#jsrender and http://github.com/BorisMoore/jsrender
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -47,7 +47,7 @@ if (!$ || !$.fn) {
throw "JsViews requires jQuery"; // We require jQuery
}

var versionNumber = "v1.0.9",
var versionNumber = "v1.0.10",

jsvStoreName, rTag, rTmplString, topView, $views, $observe, $observable, $expando,
_ocp = "_ocp", // Observable contextual parameter
Expand Down Expand Up @@ -2235,7 +2235,8 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) {
}
if (rtPrnDot && bindings) {
// This is a binding to a path in which an object is returned by a helper/data function/expression, e.g. foo()^x.y or (a?b:c)^x.y
// We create a compiled function to get the object instance (which will be called when the dependent data of the subexpression changes, to return the new object, and trigger re-binding of the subsequent path)
// We create a compiled function to get the object instance (which will be called when the dependent data of the subexpression changes,
// to return the new object, and trigger re-binding of the subsequent path)
expr = pathStart[fnDp-1];
if (full.length - 1 > ind - (expr || 0)) { // We need to compile a subexpression
expr = $.trim(full.slice(expr, ind + all.length));
Expand Down Expand Up @@ -3021,7 +3022,7 @@ if (jsrToJq) { // Moving from jsrender namespace to jQuery namepace - copy over
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< JsObservable >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/* JsObservable:
* See https://www.jsviews.com/#jsobservable and http://github.com/borismoore/jsviews
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -3847,7 +3848,7 @@ if (!$.observe) {
return this._data;
},

setProperty: function(path, value, nonStrict) {
setProperty: function(path, value, nonStrict, isCpfn) {
path = path || "";
var key, pair, parts, tempBatch,
multi = path + "" !== path, // Hash of paths
Expand Down Expand Up @@ -3887,7 +3888,7 @@ if (!$.observe) {
object = object[parts.shift()];
}
if (object) {
self._setProperty(object, parts[0], value, nonStrict);
self._setProperty(object, parts[0], value, nonStrict, isCpfn);
}
}
}
Expand All @@ -3899,12 +3900,13 @@ if (!$.observe) {
return this;
},

_setProperty: function(leaf, path, value, nonStrict) {
_setProperty: function(leaf, path, value, nonStrict, isCpfn) {
var setter, getter, removeProp, eventArgs, view,
property = path ? leaf[path] : leaf;

if (property !== value || nonStrict && property != value) {
if ($isFunction(property) && property.set) {
if ($isFunction(property) && !$isFunction(value)) {
if (isCpfn && !property.set) {
return; // getter function with no setter defined. So will not trigger update
} else if (property.set) {
// Case of property setter/getter - with convention that property is getter and property.set is setter
view = leaf._vw // Case of JsViews 2-way data-linking to an observable context parameter, with a setter.
// The view will be the this pointer for getter and setter. Note: this is the one scenario where path is "".
Expand All @@ -3914,7 +3916,8 @@ if (!$.observe) {
property = getter.call(view); // get - only treated as getter if also a setter. Otherwise it is simply a property of type function.
// See unit tests 'Can observe properties of type function'.
}

}
if (property !== value || nonStrict && property != value) {
// Optional non-strict equality, since serializeArray, and form-based editors can map numbers to strings, etc.
// Date objects don't support != comparison. Treat as special case.
if (!(property instanceof Date && value instanceof Date) || property > value || property < value) {
Expand Down Expand Up @@ -4308,7 +4311,7 @@ if (!$.observe) {
/* JsViews:
* Interactive data-driven views using templates and data-linking.
* See https://www.jsviews.com/#jsviews and http://github.com/BorisMoore/jsviews
* Copyright 2020, Boris Moore
* Copyright 2021, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -4519,7 +4522,7 @@ function updateValues(sourceValues, tagElse, async, bindId, ev) {
exprOb = exprOb.sb;
}
}
$observable(target, async).setProperty(to[1], sourceValue); // 2way binding change event - observably updating bound object
$observable(target, async).setProperty(to[1], sourceValue, undefined, to.isCpfn); // 2way binding change event - observably updating bound object
}
}
}
Expand Down Expand Up @@ -6381,7 +6384,7 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
// we bind to the path on the returned object, exprOb.ob, as target. Otherwise our target is the first path, paths[0], which we will convert
// with contextCb() for paths like ~a.b.c or #x.y.z

var pathIndex, path, lastPath, bindtoOb, to, bindTo, paths, k, obsCtxPrm, linkedCtxParam, contextCb, targetPaths, bindTos, fromIndex,
var pathIndex, path, lastPath, bindtoOb, to, bindTo, paths, k, obsCtxPrm, linkedCtxParam, contextCb, targetPaths, bindTos, fromIndex, isCpfn,
tagElse = 1,
tos = [],
linkCtx = binding.linkCtx,
Expand Down Expand Up @@ -6419,11 +6422,12 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
path = lastPath = lastPath.sb;
}
path = lastPath.sb || path && path.path;
isCpfn = lastPath._cpfn && !lastPath.sb; // leaf binding to computed property/function "a.b.c()"
lastPath = path ? path.slice(1) : bindtoOb.path;
}
to = path
? [bindtoOb, // 'exprOb' for this expression and view-binding. So bindtoOb.ob is current object returned by expression.
lastPath]
lastPath]
: resolveDataTargetPath(lastPath, source, contextCb); // Get 'to' for target path: lastPath
} else {
// Contextual parameter ~foo with no external binding - has ctx.foo = [{_ocp: xxx}] and binds to ctx.foo._ocp
Expand All @@ -6439,6 +6443,7 @@ function defineBindToDataTargets(binding, tag, cvtBk) {
// This is a binding for a tag contextual parameter (e.g. <input data-link="~wd"/> within a tag block content
to = obsCtxPrm;
}
to.isCpfn = isCpfn;
bindTos.unshift(to);
}
}
Expand Down Expand Up @@ -6983,7 +6988,7 @@ function addLinkMethods(tagOrView) { // tagOrView is View prototype or tag insta
indexFrom = indexFrom || 0;
tagElse = tagElse || 0;

var linkedElem, linkedEl, linkedCtxParam, linkedCtxPrmKey, indexTo, linkedElems, newVal,
var linkedElem, linkedEl, linkedCtxParam, indexTo, linkedElems, newVal,
tagCtx = theTag.tagCtxs[tagElse];

if (tagCtx._bdArgs && (eventArgs || val !== undefined) && tagCtx._bdArgs[indexFrom]===val
Expand All @@ -7004,12 +7009,10 @@ function addLinkMethods(tagOrView) { // tagOrView is View prototype or tag insta
}
}

if (val !== undefined && (linkedCtxParam = theTag.linkedCtxParam) && linkedCtxParam[indexFrom]
if (val !== undefined && (linkedCtxParam = theTag.linkedCtxParam) && linkedCtxParam[indexFrom]) {
// If this setValue call corresponds to a tag contextual parameter and the tag has a converter, then we need to set the
// value of this contextual parameter (since it is not directly bound to the tag argument/property when there is a converter).
&& (linkedCtxPrmKey = linkedCtxParam[indexFrom])
) {
tagCtx.ctxPrm(linkedCtxPrmKey, val);
tagCtx.ctxPrm(linkedCtxParam[indexFrom], val);
}
indexTo = theTag._.toIndex[indexFrom];
if (indexTo !== undefined) {
Expand Down
8 changes: 4 additions & 4 deletions jsviews.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion jsviews.min.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jsviews",
"version": "v1.0.9",
"version": "v1.0.10",
"description": "Next-generation MVVM and MVP framework - built on top of JsRender templates. Bringing templates to life...",
"main": "./jsviews.js",
"author": {
Expand Down Expand Up @@ -35,7 +35,7 @@
"browserify": "^11.0.1",
"glob-stream": "^5.0.0",
"gulp": "^3.9.0",
"jsrender": "^1.0.9",
"jsrender": "^1.0.10",
"qunit": "^0.7.6"
},
"dependencies": {
Expand Down
9 changes: 5 additions & 4 deletions test/browserify/bundles/1-bundle.js

Large diffs are not rendered by default.

Loading

0 comments on commit 0eb921e

Please sign in to comment.