Skip to content

Commit

Permalink
v1.0.2 release
Browse files Browse the repository at this point in the history
Several minor bug fixes

Additional and improved documentation topics and samples...
Additional unit tests...
  • Loading branch information
BorisMoore committed Feb 11, 2019
1 parent 8230694 commit fab7e4e
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 359 deletions.
67 changes: 37 additions & 30 deletions jsrender-node.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*! JsRender v1.0.1: http://jsviews.com/#jsrender */
/*! JsRender v1.0.2: http://jsviews.com/#jsrender */
/*! **VERSION FOR NODE.JS** (For WEB see http://jsviews.com/download/jsrender.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 2018, Boris Moore
* Copyright 2019, Boris Moore
* Released under the MIT License.
*/

Expand All @@ -19,7 +19,7 @@ if (typeof exports !== 'object' ) {

//========================== Top-level vars ==========================

var versionNumber = "v1.0.1",
var versionNumber = "v1.0.2",

// global var is the this object, which is window when running in the usual browser environment

Expand Down Expand Up @@ -468,7 +468,6 @@ function contextParameter(key, value, get) {
return res.apply((!this || this === global) ? callView : this, arguments);
};
$extend(wrapped, res); // Attach same expandos (if any) to the wrapped function
wrapped._vw = callView;
}
return wrapped || res;
}
Expand All @@ -488,10 +487,9 @@ function getTemplate(tmpl) {
function convertVal(converter, view, tagCtx, onError) {
// Called from compiled template code for {{:}}
// self is template object or linkCtx object
var tag, value, argsLen, bindTo,
var tag, linkCtx, value, argsLen, bindTo,
// If tagCtx is an integer, then it is the key for the compiled function to return the boundTag tagCtx
boundTag = typeof tagCtx === "number" && view.tmpl.bnds[tagCtx-1],
linkCtx = view._lc; // For data-link="{cvt:...}"...
boundTag = typeof tagCtx === "number" && view.tmpl.bnds[tagCtx-1];

if (onError === undefined && boundTag && boundTag._lr) { // lateRender
onError = "";
Expand All @@ -503,6 +501,7 @@ function convertVal(converter, view, tagCtx, onError) {
}
boundTag = boundTag._bd && boundTag;
if (converter || boundTag) {
linkCtx = view._lc; // For data-link="{cvt:...}"... See onDataLinkedTagChange
tag = linkCtx && linkCtx.tag;
tagCtx.view = view;
if (!tag) {
Expand Down Expand Up @@ -663,7 +662,7 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) {
content, callInit, mapDef, thisMap, args, bdArgs, props, tagDataMap, contentCtx, key, bindFromLength, bindToLength, linkedElement, defaultCtx,
i = 0,
ret = "",
linkCtx = parentView._lc || false,
linkCtx = parentView._lc || false, // For data-link="{myTag...}"... See onDataLinkedTagChange
ctx = parentView.ctx,
parentTmpl = tmpl || parentView.tmpl,
// If tagCtxs is an integer, then it is the key for the compiled function to return the boundTag tagCtxs
Expand Down Expand Up @@ -1457,10 +1456,6 @@ function registerStore(storeName, storeSettings) {
return item || $views;
}
// Adding a single unnamed item to the store
if (item === undefined) {
item = name;
name = undefined;
}
if (name && "" + name !== name) { // name must be a string
parentTmpl = item;
item = name;
Expand All @@ -1473,6 +1468,10 @@ function registerStore(storeName, storeSettings) {
: theStore;
compile = storeSettings.compile;

if (item === undefined) {
item = compile ? name : thisStore[name];
name = undefined;
}
if (item === null) {
// If item is null, delete this entry
if (name) {
Expand Down Expand Up @@ -1776,8 +1775,7 @@ function onRenderError(e, view, fallback) {
if ($subSettings.onError && (fallback = $subSettings.onError.call(view.data, e, fallback && message, view)) !== undefined) {
message = fallback; // There is a settings.debugMode(handler) onError override. Call it, and use return value (if any) to replace message
}

return view && !view._lc ? $converters.html(message) : message;
return view && !view._lc ? $converters.html(message) : message; // For data-link=\"{... onError=...}"... See onDataLinkedTagChange
}

function error(message) {
Expand Down Expand Up @@ -2140,7 +2138,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) {
if (bindings && rtPrnDot && !aposed && !quoted) {
// 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)
if (parenDepth && (!named || boundName || bindto)) {
if (parenDepth) {
expr = pathStart[parenDepth - 1];
if (full.length - 1 > index - (expr || 0)) { // We need to compile a subexpression
expr = full.slice(expr, index + all.length);
Expand Down Expand Up @@ -2470,17 +2468,24 @@ function getTargetProps(source, tagCtx) {
// this pointer is theMap - which has tagCtx.props too
// arguments: tagCtx.args.
var key, prop,
props = [];

if (typeof source === OBJECT || $isFunction(source)) {
for (key in source) {
prop = source[key];
if (key !== $.expando && source.hasOwnProperty(key) && (!tagCtx.props.noFunctions || !$.isFunction(prop))) {
props.push({key: key, prop: prop});
map = tagCtx.map,
propsArr = map && map.propsArr;

if (!propsArr) { // map.propsArr is the full array of {key:..., prop:...} objects
propsArr = [];
if (typeof source === OBJECT || $isFunction(source)) {
for (key in source) {
prop = source[key];
if (key !== $.expando && source.hasOwnProperty(key) && (!tagCtx.props.noFunctions || !$.isFunction(prop))) {
propsArr.push({key: key, prop: prop});
}
}
}
if (map) {
map.propsArr = map.options && propsArr; // If bound {^{props}} and not isRenderCall, store propsArr on map (map.options is defined only for bound, && !isRenderCall)
}
}
return getTargetSorted(props, tagCtx);
return getTargetSorted(propsArr, tagCtx); // Obtains map.tgt, by filtering, sorting and splicing the full propsArr
}

function getTargetSorted(value, tagCtx) {
Expand Down Expand Up @@ -2516,9 +2521,11 @@ function getTargetSorted(value, tagCtx) {
value = value.slice(); // Clone array first if not already a new array
}
if ($isFunction(sort)) {
value = value.sort(sort);
value = value.sort(function() { // Wrap the sort function to provide tagCtx as 'this' pointer
return sort.apply(tagCtx, arguments);
});
}
if (reverse < 0 && !sort) { // Reverse result if not already reversed in sort
if (reverse < 0 && (!sort || $isFunction(sort))) { // Reverse result if not already reversed in sort
value = value.reverse();
}

Expand Down Expand Up @@ -2712,18 +2719,18 @@ $viewsSettings = $views.settings;
"for": {
sortDataMap: dataMap(getTargetSorted),
init: function(val, cloned) {
var l, tagCtx, props, sort,
var l, tagCtx, paramsProps, sort,
self = this,
tagCtxs = self.tagCtxs;
l = tagCtxs.length;
while (l--) {
tagCtx = tagCtxs[l];
props = tagCtx.props;
tagCtx.argDefault = props.end === undefined || tagCtx.args.length > 0; // Default to #data except for auto-create range scenario {{for start=xxx end=yyy step=zzz}}
paramsProps = tagCtx.params.props;
tagCtx.argDefault = tagCtx.props.end === undefined || tagCtx.args.length > 0; // Default to #data except for auto-create range scenario {{for start=xxx end=yyy step=zzz}}

if (tagCtx.argDefault !== false && $isArray(tagCtx.args[0])
&& (props.sort !== undefined || tagCtx.params.props.start || tagCtx.params.props.end || props.step !== undefined || props.filter || props.reverse)) {
props.dataMap = self.sortDataMap;
&& (paramsProps.sort !== undefined || paramsProps.start || paramsProps.end || paramsProps.step || paramsProps.filter || paramsProps.reverse)) {
tagCtx.props.dataMap = self.sortDataMap;
}
}
},
Expand Down
67 changes: 37 additions & 30 deletions jsrender.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*! JsRender v1.0.1: http://jsviews.com/#jsrender */
/*! JsRender v1.0.2: 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 2018, Boris Moore
* Copyright 2019, 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.1",
var versionNumber = "v1.0.2",
jsvStoreName, rTag, rTmplString, topView, $views, $expando,
_ocp = "_ocp", // Observable contextual parameter

Expand Down Expand Up @@ -493,7 +493,6 @@ function contextParameter(key, value, get) {
return res.apply((!this || this === global) ? callView : this, arguments);
};
$extend(wrapped, res); // Attach same expandos (if any) to the wrapped function
wrapped._vw = callView;
}
return wrapped || res;
}
Expand All @@ -513,10 +512,9 @@ function getTemplate(tmpl) {
function convertVal(converter, view, tagCtx, onError) {
// Called from compiled template code for {{:}}
// self is template object or linkCtx object
var tag, value, argsLen, bindTo,
var tag, linkCtx, value, argsLen, bindTo,
// If tagCtx is an integer, then it is the key for the compiled function to return the boundTag tagCtx
boundTag = typeof tagCtx === "number" && view.tmpl.bnds[tagCtx-1],
linkCtx = view._lc; // For data-link="{cvt:...}"...
boundTag = typeof tagCtx === "number" && view.tmpl.bnds[tagCtx-1];

if (onError === undefined && boundTag && boundTag._lr) { // lateRender
onError = "";
Expand All @@ -528,6 +526,7 @@ function convertVal(converter, view, tagCtx, onError) {
}
boundTag = boundTag._bd && boundTag;
if (converter || boundTag) {
linkCtx = view._lc; // For data-link="{cvt:...}"... See onDataLinkedTagChange
tag = linkCtx && linkCtx.tag;
tagCtx.view = view;
if (!tag) {
Expand Down Expand Up @@ -688,7 +687,7 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) {
content, callInit, mapDef, thisMap, args, bdArgs, props, tagDataMap, contentCtx, key, bindFromLength, bindToLength, linkedElement, defaultCtx,
i = 0,
ret = "",
linkCtx = parentView._lc || false,
linkCtx = parentView._lc || false, // For data-link="{myTag...}"... See onDataLinkedTagChange
ctx = parentView.ctx,
parentTmpl = tmpl || parentView.tmpl,
// If tagCtxs is an integer, then it is the key for the compiled function to return the boundTag tagCtxs
Expand Down Expand Up @@ -1505,10 +1504,6 @@ function registerStore(storeName, storeSettings) {
return item || $views;
}
// Adding a single unnamed item to the store
if (item === undefined) {
item = name;
name = undefined;
}
if (name && "" + name !== name) { // name must be a string
parentTmpl = item;
item = name;
Expand All @@ -1521,6 +1516,10 @@ function registerStore(storeName, storeSettings) {
: theStore;
compile = storeSettings.compile;

if (item === undefined) {
item = compile ? name : thisStore[name];
name = undefined;
}
if (item === null) {
// If item is null, delete this entry
if (name) {
Expand Down Expand Up @@ -1824,8 +1823,7 @@ function onRenderError(e, view, fallback) {
if ($subSettings.onError && (fallback = $subSettings.onError.call(view.data, e, fallback && message, view)) !== undefined) {
message = fallback; // There is a settings.debugMode(handler) onError override. Call it, and use return value (if any) to replace message
}

return view && !view._lc ? $converters.html(message) : message;
return view && !view._lc ? $converters.html(message) : message; // For data-link=\"{... onError=...}"... See onDataLinkedTagChange
}

function error(message) {
Expand Down Expand Up @@ -2188,7 +2186,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) {
if (bindings && rtPrnDot && !aposed && !quoted) {
// 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)
if (parenDepth && (!named || boundName || bindto)) {
if (parenDepth) {
expr = pathStart[parenDepth - 1];
if (full.length - 1 > index - (expr || 0)) { // We need to compile a subexpression
expr = full.slice(expr, index + all.length);
Expand Down Expand Up @@ -2512,17 +2510,24 @@ function getTargetProps(source, tagCtx) {
// this pointer is theMap - which has tagCtx.props too
// arguments: tagCtx.args.
var key, prop,
props = [];

if (typeof source === OBJECT || $isFunction(source)) {
for (key in source) {
prop = source[key];
if (key !== $expando && source.hasOwnProperty(key) && (!tagCtx.props.noFunctions || !$.isFunction(prop))) {
props.push({key: key, prop: prop});
map = tagCtx.map,
propsArr = map && map.propsArr;

if (!propsArr) { // map.propsArr is the full array of {key:..., prop:...} objects
propsArr = [];
if (typeof source === OBJECT || $isFunction(source)) {
for (key in source) {
prop = source[key];
if (key !== $expando && source.hasOwnProperty(key) && (!tagCtx.props.noFunctions || !$.isFunction(prop))) {
propsArr.push({key: key, prop: prop});
}
}
}
if (map) {
map.propsArr = map.options && propsArr; // If bound {^{props}} and not isRenderCall, store propsArr on map (map.options is defined only for bound, && !isRenderCall)
}
}
return getTargetSorted(props, tagCtx);
return getTargetSorted(propsArr, tagCtx); // Obtains map.tgt, by filtering, sorting and splicing the full propsArr
}

function getTargetSorted(value, tagCtx) {
Expand Down Expand Up @@ -2558,9 +2563,11 @@ function getTargetSorted(value, tagCtx) {
value = value.slice(); // Clone array first if not already a new array
}
if ($isFunction(sort)) {
value = value.sort(sort);
value = value.sort(function() { // Wrap the sort function to provide tagCtx as 'this' pointer
return sort.apply(tagCtx, arguments);
});
}
if (reverse < 0 && !sort) { // Reverse result if not already reversed in sort
if (reverse < 0 && (!sort || $isFunction(sort))) { // Reverse result if not already reversed in sort
value = value.reverse();
}

Expand Down Expand Up @@ -2787,18 +2794,18 @@ if (!(jsr || $ && $.render)) {
"for": {
sortDataMap: dataMap(getTargetSorted),
init: function(val, cloned) {
var l, tagCtx, props, sort,
var l, tagCtx, paramsProps, sort,
self = this,
tagCtxs = self.tagCtxs;
l = tagCtxs.length;
while (l--) {
tagCtx = tagCtxs[l];
props = tagCtx.props;
tagCtx.argDefault = props.end === undefined || tagCtx.args.length > 0; // Default to #data except for auto-create range scenario {{for start=xxx end=yyy step=zzz}}
paramsProps = tagCtx.params.props;
tagCtx.argDefault = tagCtx.props.end === undefined || tagCtx.args.length > 0; // Default to #data except for auto-create range scenario {{for start=xxx end=yyy step=zzz}}

if (tagCtx.argDefault !== false && $isArray(tagCtx.args[0])
&& (props.sort !== undefined || tagCtx.params.props.start || tagCtx.params.props.end || props.step !== undefined || props.filter || props.reverse)) {
props.dataMap = self.sortDataMap;
&& (paramsProps.sort !== undefined || paramsProps.start || paramsProps.end || paramsProps.step || paramsProps.filter || paramsProps.reverse)) {
tagCtx.props.dataMap = self.sortDataMap;
}
}
},
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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jsrender",
"version": "v1.0.1",
"version": "v1.0.2",
"description": "Best-of-breed templating in browser or on Node.js (with Express 4, Hapi and Browserify integration)",
"main": "./jsrender-node.js",
"browser": "./jsrender.js",
Expand Down
Loading

0 comments on commit fab7e4e

Please sign in to comment.