diff --git a/lib/mixins/property-effects.html b/lib/mixins/property-effects.html
index 15f9e5cdc7..b33b386b0b 100644
--- a/lib/mixins/property-effects.html
+++ b/lib/mixins/property-effects.html
@@ -13,7 +13,6 @@
-
@@ -821,6 +820,24 @@
const emptyArray = [];
+ // Regular expressions used for binding
+ const IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
+ const NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
+ const SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
+ const DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
+ const STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
+ const ARGUMENT = '(?:(' + IDENT + '|' + NUMBER + '|' + STRING + ')\\s*' + ')';
+ const ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
+ const ARGUMENT_LIST = '(?:' + '\\(\\s*' +
+ '(?:' + ARGUMENTS + '?' + ')' +
+ '\\)\\s*' + ')';
+ const BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
+ const OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
+ const CLOSE_BRACKET = '(?:]]|}})';
+ const NEGATE = '(?:(!)\\s*)?'; // Group 2
+ const EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
+ const bindingRegex = new RegExp(EXPRESSION, "g");
+
/**
* Create a string from binding parts of all the literal parts
*
@@ -2610,9 +2627,67 @@
* @protected
*/
static _parseBindings(text, templateInfo) {
- const parserParts = Polymer.BindingParser.parse(text, templateInfo);
- if (parserParts.length) {
- return parserParts;
+ let parts = [];
+ let lastIndex = 0;
+ let m;
+ // Example: "literal1{{prop}}literal2[[!compute(foo,bar)]]final"
+ // Regex matches:
+ // Iteration 1: Iteration 2:
+ // m[1]: '{{' '[['
+ // m[2]: '' '!'
+ // m[3]: 'prop' 'compute(foo,bar)'
+ while ((m = bindingRegex.exec(text)) !== null) {
+ // Add literal part
+ if (m.index > lastIndex) {
+ parts.push({literal: text.slice(lastIndex, m.index)});
+ }
+ // Add binding part
+ let mode = m[1][0];
+ let negate = Boolean(m[2]);
+ let source = m[3].trim();
+ let customEvent = false, notifyEvent = '', colon = -1;
+ if (mode == '{' && (colon = source.indexOf('::')) > 0) {
+ notifyEvent = source.substring(colon + 2);
+ source = source.substring(0, colon);
+ customEvent = true;
+ }
+ let signature = parseMethod(source);
+ let dependencies = [];
+ if (signature) {
+ // Inline computed function
+ let {args, methodName} = signature;
+ for (let i=0; i
+
\ No newline at end of file
diff --git a/lib/utils/binding-parser.html b/lib/utils/binding-parser.html
index 357d17a357..0e614d6a2b 100644
--- a/lib/utils/binding-parser.html
+++ b/lib/utils/binding-parser.html
@@ -9,117 +9,151 @@
-->
+
+
diff --git a/test/unit/property-effects.html b/test/unit/property-effects.html
index bef3730a68..40f93aa5c0 100644
--- a/test/unit/property-effects.html
+++ b/test/unit/property-effects.html
@@ -358,30 +358,6 @@
assert.equal(el.$.boundWithDash.textContent, 'yes');
});
- test('binding with slash', function() {
- el.objectWithSlash = {
- 'binding/with/slash': 'yes'
- };
- assert.equal(el.$.boundWithSlash.textContent, 'yes');
- });
-
- test('json should not be a binding', function() {
- assert.equal(el.$.jsonContent.textContent, '[["Jan", 31],["Feb", 28],["Mar", 31]]');
- });
-
- test('binding with non-English unicode', function() {
- el.objectWithNonEnglishUnicode = {
- 商品名: 'yes'
- };
- assert.equal(el.$.nonEnglishUnicode.textContent, 'yes');
- });
-
- test('binding with booleans', function() {
- el.otherValue = 10;
- assert.equal(el.$.booleanTrue.textContent, 'foo(field, true): 10');
- assert.equal(el.$.booleanFalse.textContent, 'foo(field, false): 20');
- });
-
test('class attribute without template scope not erased', function() {
var el = document.querySelector('.class1');
assert.notEqual(el, null, 'class without template scope is undefined');
@@ -443,6 +419,48 @@
assert.equal(el.__observerCalled, 1);
});
});
+
+ suite('can work with binding parser', function() {
+ setup(function() {
+ document.body.removeChild(el);
+ el = document.createElement('x-basic-binding-parser');
+ document.body.appendChild(el);
+ });
+
+ test('binding with slash', function() {
+ el.objectWithSlash = {
+ 'binding/with/slash': 'yes'
+ };
+ assert.equal(el.$.boundWithSlash.textContent, 'yes');
+ });
+
+ test('json should not be a binding', function() {
+ assert.equal(el.$.jsonContent.textContent, '[["Jan", 31],["Feb", 28],["Mar", 31]]');
+ });
+
+ test('binding with non-English unicode', function() {
+ el.objectWithNonEnglishUnicode = {
+ 商品名: 'yes'
+ };
+ assert.equal(el.$.nonEnglishUnicode.textContent, 'yes');
+ });
+
+ test('binding with booleans', function() {
+ el.otherValue = 10;
+ assert.equal(el.$.booleanTrue.textContent, 'foo(field, true): 10');
+ assert.equal(el.$.booleanFalse.textContent, 'foo(field, false): 20');
+ });
+
+ suite('equivalent behavior as regex', function() {
+ // Loop over the suite "single-element binding effects" (parent of the parent of this suite)
+ // And make sure that the tests there also pass on the binding-parser
+ //
+ // t.title is the name of the test and t.fn contains the test body
+ this.parent.parent.tests.forEach(t => {
+ test(t.title, t.fn);
+ });;
+ });
+ });
});
suite('computed bindings with dynamic functions', function() {