Skip to content

Commit

Permalink
fix(BindingLanguage+Let): enhance implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
bigopon committed Sep 28, 2018
1 parent 0f519b2 commit 863b6ef
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 34 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"type": "git",
"url": "http://github.com/aurelia/templating-binding"
},
"scripts": {
"test": "karma start"
},
"jspm": {
"registry": "npm",
"jspmPackage": true,
Expand Down
31 changes: 20 additions & 11 deletions src/binding-language.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class TemplatingBindingLanguage extends BindingLanguage {
this.emptyStringExpression = this.parser.parse('\'\'');
syntaxInterpreter.language = this;
this.attributeMap = attributeMap;
this.toBindingContextAttr = 'to-binding-context';
}

inspectAttribute(resources, elementName, attrName, attrValue) {
Expand Down Expand Up @@ -92,10 +93,9 @@ export class TemplatingBindingLanguage extends BindingLanguage {
/**
* @param {ViewResources} resources
* @param {Element} letElement
* @param {(LetExpression | LetInterpolationBindingExpression)[]} existingLetExpressions
*/
createLetExpressions(resources, letElement, existingLetExpressions) {
existingLetExpressions = existingLetExpressions || [];
createLetExpressions(resources, letElement) {
let expressions = [];
let attributes = letElement.attributes;
/**@type {Attr} */
let attr;
Expand All @@ -104,24 +104,31 @@ export class TemplatingBindingLanguage extends BindingLanguage {
let attrName;
let attrValue;
let command;
let toBindingContextAttr = this.toBindingContextAttr;
let toBindingContext = letElement.hasAttribute(toBindingContextAttr);
for (let i = 0, ii = attributes.length; ii > i; ++i) {
attr = attributes[i];
attrName = attr.name;
attrValue = attr.nodeValue;
parts = attrName.split('.');

if (attrName === toBindingContextAttr) {
continue;
}

if (parts.length === 2) {
command = parts[1];
if (command !== 'bind') {
LogManager.getLogger('templating-binding-language')
.warn(`Detected invalid let command. Expected "${part[0]}.bind", given "${attrName}"`);
.warn(`Detected invalid let command. Expected "${parts[0]}.bind", given "${attrName}"`);
continue;
}
existingLetExpressions.push(new LetExpression(
expressions.push(new LetExpression(
this.observerLocator,
camelCase(parts[0]),
this.parser.parse(attrValue),
resources.lookupFunctions
resources.lookupFunctions,
toBindingContext
));
} else {
attrName = camelCase(attrName);
Expand All @@ -131,23 +138,25 @@ export class TemplatingBindingLanguage extends BindingLanguage {
.warn(`Detected string literal in let bindings. Did you mean "${ attrName }.bind=${ attrValue }" or "${ attrName }=\${${ attrValue }}" ?`);
}
if (parts) {
existingLetExpressions.push(new LetInterpolationBindingExpression(
expressions.push(new LetInterpolationBindingExpression(
this.observerLocator,
attrName,
parts,
resources.lookupFunctions
resources.lookupFunctions,
toBindingContext
));
} else {
existingLetExpressions.push(new LetExpression(
expressions.push(new LetExpression(
this.observerLocator,
attrName,
new LiteralString(attrValue),
resources.lookupFunctions
resources.lookupFunctions,
toBindingContext
));
}
}
}
return existingLetExpressions;
return expressions;
}

inspectTextContent(resources, value) {
Expand Down
16 changes: 7 additions & 9 deletions src/let-expression.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
connectable,
enqueueBindingConnect,
createOverrideContext,
sourceContext
} from 'aurelia-binding';

Expand Down Expand Up @@ -35,12 +34,11 @@ export class LetExpression {
@connectable()
export class Let {
/**
*
* @param {ObserverLocator} observerLocator
* @param {Expression} sourceExpression
* @param {Function | Element} target
* @param {ObserverLocator} observerLocator
* @param {Expression} sourceExpression
* @param {Function | Element} target
* @param {string} targetProperty
* @param {*} lookupFunctions
* @param {*} lookupFunctions
* @param {boolean} toBindingContext indicates let binding result should be assigned to binding context
*/
constructor(observerLocator, sourceExpression, targetProperty, lookupFunctions, toBindingContext) {
Expand All @@ -53,7 +51,7 @@ export class Let {
this.toBindingContext = toBindingContext;
}

updateSource() {
updateTarget() {
const value = this.sourceExpression.evaluate(this.source, this.lookupFunctions);
this.target[this.targetProperty] = value;
}
Expand All @@ -63,7 +61,7 @@ export class Let {
return;
}
if (context === sourceContext) {
this.updateSource();
this.updateTarget();
return;
}
throw new Error(`Unexpected call context ${context}`);
Expand Down Expand Up @@ -108,7 +106,7 @@ export class Let {
if (!this.isBound) {
return;
}
this.updateSource();
this.updateTarget();
this.sourceExpression.connect(this, this.source);
}
}
5 changes: 2 additions & 3 deletions src/let-interpolation-expression.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {bindingMode, createOverrideContext} from 'aurelia-binding';

import {bindingMode} from 'aurelia-binding';
import {
InterpolationBinding,
ChildInterpolationBinding
Expand Down Expand Up @@ -61,7 +60,7 @@ export class LetInterpolationBinding {
}

this.isBound = true;
this.source = source
this.source = source;
this.target = this.toBindingContext ? source.bindingContext : source.overrideContext;

this.interpolationBinding = this.createInterpolationBinding();
Expand Down
50 changes: 39 additions & 11 deletions test/binding-language.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import './setup';
import {TemplatingBindingLanguage} from '../src/binding-language';
import {Container} from 'aurelia-dependency-injection';
import {NameExpression} from 'aurelia-binding';
import {Logger} from 'aurelia-logging';

import {
LetExpression,
Expand All @@ -17,7 +18,7 @@ describe('BindingLanguage', () => {
/**@type {TemplatingBindingLanguage} */
let language;

beforeAll(() => {
beforeEach(() => {
language = new Container().get(TemplatingBindingLanguage);
});

Expand Down Expand Up @@ -47,19 +48,46 @@ describe('BindingLanguage', () => {
resources = { lookupFunctions: {} };
});

it('creates correct let expressions', () => {
it('works with .bind command', () => {
let el = div();
el.setAttribute('foo.bind', 'bar');
const expressions = language.createLetExpressions(resources, el);
expect(expressions[0] instanceof LetExpression).toBe(true);
});

it('warns when binding command is not bind', () => {
const loggerSpy = spyOn(Logger.prototype, 'warn').and.callThrough();
let callCount = 0;
['one-way', 'two-way', 'one-time', 'from-view'].forEach(cmd => {
let el = div();
el.setAttribute(`foo.${cmd}`, 'bar');
language.createLetExpressions(resources, el);
expect(loggerSpy.calls.count()).toBe(++callCount, `It should have had been called ${callCount} times`);
});
});

let el1 = div();
el1.setAttribute('foo.bind', 'bar');
expect(language.createLetExpressions(resources, el1)[0] instanceof LetExpression).toBe(true);
it('works with interpolation', () => {
let el = div();
el.setAttribute('foo', '${bar}');
const expressions = language.createLetExpressions(resources, el);
expect(expressions.length).toBe(1, 'It should have had 1 instruction');
expect(expressions[0] instanceof LetInterpolationBindingExpression).toBe(true);
});

it('creates correct let expressions', () => {
let el = div();
el.setAttribute('foo', 'bar');
expect(language.createLetExpressions(resources, el)[0] instanceof LetExpression).toBe(true);
});

let el2 = div();
el2.setAttribute('foo', '${bar}');
expect(language.createLetExpressions(resources, el2)[0] instanceof LetInterpolationBindingExpression).toBe(true);
it('understands to-binding-context', () => {
let el = div();
el.setAttribute('foo.bind', 'bar');
el.setAttribute(language.toBindingContextAttr, '');

let el3 = div();
el3.setAttribute('foo', 'bar');
expect(language.createLetExpressions(resources, el3)[0] instanceof LetExpression).toBe(true);
const expressions = language.createLetExpressions(resources, el);
expect(expressions.length).toBe(1, 'It should have not created expression from to-binding-context');
expect(expressions[0].toBindingContext).toBe(true);
});

function div() {
Expand Down

0 comments on commit 863b6ef

Please sign in to comment.