Skip to content

Commit

Permalink
Commit 62 (Beta Candidate)
Browse files Browse the repository at this point in the history
- Improved support for data-linked element expressions
  using tags
  e.g. <div data-link="{if foo tmpl='...'}">

  This now supports one or more {else} expressions

  <div data-link="{if a tmpl='...'}{else b tmpl='...'}">

  It also supports linking tag expressions to different
  targets, such as title{... css-color{... class{... etc.

  e.g.
  data-link="title{for items tmpl='...'}{else tmpl='...'}"

  See BorisMoore#293
  http://stackoverflow.com/a/28060034/1054484

- Tag inheritance now supports multi-level inheritance with
  easy invocation of the base class implementation using
  this.base(...) or this.baseApply(arguments):
  e.g.
  {
    baseTag: "for",
    onAfterLink: function() {
      ...
      this.baseApply(arguments);
    }
    ...
  }

  Similarly for callbacks declared declaratively on tags:
  e.g.
  {{for items onAfterLink=~myHelper onUpdate=~dbg}}...

  The above uses the built in ~dbg helper, and a user-provided
  helper, such as:

  function myHelper() {
    ...
    this.baseApply(arguments);
  }

- Many new unit tests added for the above new features.

- Some small additional bug fixes.
  • Loading branch information
BorisMoore committed Feb 9, 2015
1 parent 3c83204 commit 074f8b2
Show file tree
Hide file tree
Showing 20 changed files with 795 additions and 495 deletions.
2 changes: 1 addition & 1 deletion MIT-LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2013 Boris Moore https://github.com/BorisMoore/jsviews
Copyright (c) 2015 Boris Moore https://github.com/BorisMoore/jsviews

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand Down
5 changes: 2 additions & 3 deletions jquery.observable.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*! JsObservable v1.0.0-alpha: http://github.com/BorisMoore/jsviews and http://jsviews.com/jsviews
informal pre V1.0 commit counter: 61 (Beta Candidate) */
informal pre V1.0 commit counter: 62 (Beta Candidate) */
/*
* Subcomponent of JsViews
* Data change events for data-linking
*
* Copyright 2014, Boris Moore
* Copyright 2015, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -492,7 +492,6 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
allowArray = this != false, // If this === false, this is a call from observeAndBind - doing binding of datalink expressions. We don't bind
// arrayChange events in this scenario. Instead, {^{for}} and similar do specific arrayChange binding to the tagCtx.args[0] value, in onAfterLink.
// Note deliberately using this != false, rather than this !== false because of IE<10 bug- see https://github.com/BorisMoore/jsviews/issues/237
ns = observeStr,
paths = Array.apply(0, arguments),
origRoot = paths[0];

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.

65 changes: 36 additions & 29 deletions jquery.views.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*! JsViews v1.0.0-alpha: http://github.com/BorisMoore/jsviews and http://jsviews.com/jsviews
informal pre V1.0 commit counter: 61 (Beta Candidate) */
informal pre V1.0 commit counter: 62 (Beta Candidate) */
/*
* Interactive data-driven views using templates and data-linking.
* Requires jQuery and jsrender.js (next-generation jQuery Templates, optimized for pure string-based rendering)
* See JsRender at http://github.com/BorisMoore/jsrender and http://jsviews.com/jsrender
* Also requires jquery.observable.js
* See JsObservable at http://github.com/BorisMoore/jsviews and http://jsviews.com/jsviews
* Copyright 2014, Boris Moore
* Copyright 2015, Boris Moore
* Released under the MIT License.
*/

Expand Down Expand Up @@ -256,7 +256,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
if (attr === htmlStr) {
tag.onBeforeLink && tag.onBeforeLink();
}
callAfterLink(tag, tag.tagCtx);
callAfterLink(tag);
observeAndBind(linkCtx, source, target);
view.linkCtx = oldLinkCtx;
return;
Expand Down Expand Up @@ -289,7 +289,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */

if (tag) {
tag._er = hasError;
callAfterLink(tag, tag.tagCtx);
callAfterLink(tag);
}
}

Expand Down Expand Up @@ -523,7 +523,6 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
var self = this,
onBeforeChange = self.hlp(onBeforeChangeStr),
onAfterChange = self.hlp(onAfterChangeStr);

if (!onBeforeChange || onBeforeChange.call(this, ev, eventArgs) !== false) {
if (eventArgs) {
// This is an observable action (not a trigger/handler call from pushValues, or similar, for which eventArgs will be null)
Expand All @@ -544,7 +543,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
case "refresh":
self.refresh();
break;
// Othercases: (e.g.undefined, for setProperty on observable object) etc. do nothing
// Other cases: (e.g.undefined, for setProperty on observable object) etc. do nothing
}
}
if (onAfterChange) {
Expand Down Expand Up @@ -572,7 +571,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
$([arrayBinding[1]]).off(arrayChangeStr, arrayBinding[0]);
view._.bndArr = undefined;
}
if (bound !== !!bound && bound._.inline) {
if (bound !== !!bound) {
// bound is not a boolean, so it is the data-linked tag that 'owns' this array binding - e.g. {^{for...}}
if (type) {
bound._.arrVws[view._.id] = view;
Expand Down Expand Up @@ -1205,6 +1204,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
for (j = 0; j < len; j++) {
vwInfo = vwInfos[j];
// This is an open marker for a data-linked tag {^{...}}, within the content of the tag whose id is get.id. Add it to bindEls.
// Note - if bindingStore[vwInfo.id]._is === "tag" then getViewInfos is being called too soon - during first linking pass
parentTag = tag = bindingStore[vwInfo.id].linkCtx.tag;
if (!tag.flow) {
if (!deep) {
Expand Down Expand Up @@ -1353,27 +1353,17 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
tag._prv = elem;
}
tag._elCnt = linkInfo.elCnt;
if (tag && (!tag.onBeforeLink || tag.onBeforeLink() !== false) && !tag._.bound) {
// By default we data-link depth-last ("on the way in"), which is better for perf. But if a tag needs nested tags to be linked (refreshed)
// first, before linking its content, then make onBeforeLink() return false. In that case we data-link depth-first ("on the way out"), so nested tags will have already refreshed.
tag._.bound = true;
view = tag.tagCtx.view;
addDataBinding(undefined, tag._prv, view, linkInfo.id);
}

tag._.linking = true;
tag.onBeforeLink && tag.onBeforeLink();
// We data-link depth-last ("on the way in"), which is better for perf - and allows setting parent tags etc.
view = tag.tagCtx.view;
addDataBinding(undefined, tag._prv, view, linkInfo.id);
} else {
tag._nxt = elem;
if (tag._.linking) {
if (tag._.unlinked) {
// This is a 'close linked tag' binding annotation
// Add data binding
tagCtx = tag.tagCtx;
view = tagCtx.view;
delete tag._.linking;
if (!tag._.bound) {
tag._.bound = true;
addDataBinding(undefined, tag._prv, view, linkInfo.id); // Not top view, id, no outer data or context
}
callAfterLink(tag, tagCtx);
}
}
Expand Down Expand Up @@ -1521,7 +1511,8 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */

function addDataBinding(linkMarkup, node, currentView, boundTagId, isLink, data, context) {
// Add data binding for data-linked elements or {^{...}} data-linked tags
var tmpl, tokens, attr, convertBack, params, trimLen, tagExpr, linkFn, linkCtx, tag, rTagIndex;
var tmpl, tokens, attr, convertBack, params, trimLen, tagExpr, linkFn, linkCtx, tag, rTagIndex, hasElse,
linkExpressions = [];

if (boundTagId) {
// boundTagId is a string for {^{...}} data-linked tag. So only one linkTag in linkMarkup
Expand Down Expand Up @@ -1558,13 +1549,24 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */

linkMarkup = normalizeLinkTag(linkMarkup, defaultAttr(node));
rTag.lastIndex = 0;

while (tokens = rTag.exec(linkMarkup)) { // TODO require } to be followed by whitespace or $, and remove the \}(!\}) option.
linkExpressions.push(tokens);
}
while (tokens = linkExpressions.shift()) {
// Iterate over the data-link expressions, for different target attrs,
// e.g. <input data-link="{:firstName:} title{>~description(firstName, lastName)}"
// tokens: [all, attr, bindOnly, tagExpr, tagName, converter, colon, html, comment, code, params]
rTagIndex = rTag.lastIndex;
attr = tokens[1];
tagExpr = tokens[3];
while (linkExpressions[0] && linkExpressions[0][4] === "else") { // If this is {someTag...} and is followed by linkExpression is an {else...} add to tagExpr
tagExpr += "}{" + linkExpressions.shift()[3];
hasElse = true;
}
if (hasElse) { // If an {else} has been added, need also to add closing {{/someTag}}
tagExpr += "}{{/" + tokens[4] + "}";
}
params = tokens[10];
convertBack = undefined;

Expand Down Expand Up @@ -1603,7 +1605,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
linkCtx.expr = attr + tagExpr;
linkFn = tmpl.links[tagExpr];
if (!linkFn) {
tmpl.links[tagExpr] = linkFn = $sub.tmplFn(tagExpr, tmpl, true, convertBack);
tmpl.links[tagExpr] = linkFn = $sub.tmplFn(tagExpr, tmpl, true, convertBack, hasElse);
}
linkCtx.fn = linkFn;
if (!attr && convertBack !== undefined) {
Expand Down Expand Up @@ -1824,7 +1826,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
promise = updateContent(sourceValue, linkCtx, attr, tag);
}

callAfterLink(tag, tag.tagCtx);
callAfterLink(tag);
return promise || tag;
},

Expand All @@ -1838,8 +1840,9 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
}
};

function callAfterLink(tag, tagCtx) {
function callAfterLink(tag) {
var $linkedElem, linkedElem, radioButtons, val, bindings, i, l, linkedTag, oldTrig, newTrig,
tagCtx = tag.tagCtx,
view = tagCtx.view,
linkCtx = tag.linkCtx = tag.linkCtx || {
tag: tag,
Expand All @@ -1851,6 +1854,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
if (tag.onAfterLink) {
tag.onAfterLink(tagCtx, linkCtx);
}
delete tag._.unlinked;
$linkedElem = tag.targetTag ? tag.targetTag.linkedElem : tag.linkedElem;
if (linkedElem = $linkedElem && $linkedElem[0]) {
if (radioButtons = tag._.radio) {
Expand Down Expand Up @@ -2527,6 +2531,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
if (self._evs) {
self.onDispose();
}

$(linkCtx.elem).on(
self._evs = args[0] || "click", // events defaults to "click"
self._sel = args[1],
Expand Down Expand Up @@ -2558,7 +2563,8 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
var arrayView,
self = this,
change = eventArgs.change;
if (self.tagCtxs[1] && ( // There is an {{else}}
if (self._.noVws // Child views not supported because target is not html - e.g. data-link="title{for ...}"
|| self.tagCtxs[1] && ( // There is an {{else}}
change === "insert" && ev.target.length === eventArgs.items.length // inserting, and new length is same as inserted length, so going from 0 to n
|| change === "remove" && !ev.target.length // removing , and new length 0, so going from n to 0
|| change === "refresh" && !eventArgs.oldItems.length !== !ev.target.length // refreshing, and length is going from 0 to n or from n to 0
Expand All @@ -2573,6 +2579,7 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
}
}
ev.done = true;
// TODO - plus similar for if, etc. $(self.parentElem).trigger("forArrayChange") https://github.com/BorisMoore/jsviews/issues/299
},
onAfterLink: function() {
var i, tagCtx, arrHandler, arrBinding, data,
Expand Down Expand Up @@ -2805,8 +2812,8 @@ informal pre V1.0 commit counter: 61 (Beta Candidate) */
unlink: function(expr) {
return $unlink(expr, this);
},
view: function(type) {
return $view(this[0], type);
view: function(inner, type) {
return $view(this[0], inner, type);
}
});

Expand Down
4 changes: 2 additions & 2 deletions jquery.views.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions jquery.views.min.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit 074f8b2

Please sign in to comment.