@pacem/pacem-core 1.0.6-ricci → 2.0.0-abel
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/pacem-core.js +289 -161
- package/dist/browser/pacem-core.js.map +1 -1
- package/dist/browser/pacem-core.min.js +2 -2
- package/dist/bundle/pacem-core.min.mjs +6 -6
- package/dist/bundle/pacem-core.mjs +276 -104
- package/dist/bundle/pacem-core.mjs.map +4 -4
- package/dist/docs/pacem-core.json +1 -1
- package/dist/esm/adapter.js +1 -1
- package/dist/esm/binding-parser.js +259 -0
- package/dist/esm/command.js +1 -1
- package/dist/esm/comparers.js +1 -1
- package/dist/esm/converters.js +1 -1
- package/dist/esm/decorators-next.js +1 -1
- package/dist/esm/decorators.js +1 -1
- package/dist/esm/defaults.js +1 -1
- package/dist/esm/events.js +1 -1
- package/dist/esm/eventtarget.js +1 -1
- package/dist/esm/expression.js +36 -161
- package/dist/esm/index-animations.js +1 -1
- package/dist/esm/index-behaviors.js +1 -1
- package/dist/esm/index-components.js +1 -1
- package/dist/esm/index-iife.js +1 -1
- package/dist/esm/index-logging.js +1 -1
- package/dist/esm/index-net.js +1 -1
- package/dist/esm/index-root.js +1 -1
- package/dist/esm/index-ui.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/logger.js +1 -1
- package/dist/esm/prefix.js +1 -1
- package/dist/esm/promise.js +1 -1
- package/dist/esm/regex.js +1 -1
- package/dist/esm/storage.js +1 -1
- package/dist/esm/template.js +1 -1
- package/dist/esm/transforms.js +1 -1
- package/dist/esm/types.js +1 -1
- package/dist/esm/utils-customelement.js +1 -1
- package/dist/esm/utils-customevent.js +1 -1
- package/dist/esm/utils.js +1 -1
- package/package.json +1 -1
- package/typings/index.d.ts +6 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @pacem/pacem-core
|
|
2
|
+
* @pacem/pacem-core v2.0.0-abel (https://js.pacem.it)
|
|
3
3
|
* Pacem (https://pacem.it)
|
|
4
4
|
* Licensed under Apache-2.0
|
|
5
5
|
*/
|
|
@@ -1463,45 +1463,264 @@
|
|
|
1463
1463
|
const PCSS = root?.Configuration?.css ?? P;
|
|
1464
1464
|
//}
|
|
1465
1465
|
|
|
1466
|
+
//namespace Pacem {
|
|
1467
|
+
/** Name of the argument object binding expressions are compiled against (see {@link Expression}). */
|
|
1468
|
+
const BINDING_CONTEXT_PREFIX = '__context_pacem';
|
|
1469
|
+
const HOST_REFERENCE = '__host_pacem';
|
|
1470
|
+
/** The foundation vocabulary binding expressions are tokenized with. */
|
|
1471
|
+
const BINDING_SYNTAX = 'pacem-binding';
|
|
1472
|
+
/** Tokenizations are cached by expression text, up to this many entries. */
|
|
1473
|
+
const MAX_CACHED_ANALYSES = 4096;
|
|
1474
|
+
const INSIGNIFICANT = new Set(['space', 'newline', 'comment', 'doc-comment']);
|
|
1475
|
+
const MEMBER_ACCESS = new Set(['.', '?.']);
|
|
1476
|
+
/** Globals whose members are off limits. */
|
|
1477
|
+
const UNSAFE_OWNERS = new Set(['window', 'document']);
|
|
1478
|
+
function isReference(token) {
|
|
1479
|
+
return token.type.startsWith('binding-');
|
|
1480
|
+
}
|
|
1481
|
+
function isMemberName(token) {
|
|
1482
|
+
return token?.type === 'identifier' || token?.type === 'keyword';
|
|
1483
|
+
}
|
|
1484
|
+
/** Whether `raw` (and the significant token after it) call what precedes them: `(` or `?.(`. */
|
|
1485
|
+
function isInvocation(raw, next) {
|
|
1486
|
+
if (raw === '(') {
|
|
1487
|
+
return true;
|
|
1488
|
+
}
|
|
1489
|
+
return raw === '?.' && next === '(';
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Pure parser of Pacem binding expressions (the content of `{{ … }}` attributes and `on-*` handlers), built on the
|
|
1493
|
+
* `pacem-binding` vocabulary of foundation's language-agnostic `Compile.Scanner`: Pacem references (`:host.`, `::name`,
|
|
1494
|
+
* `^item`, `^index`, `#id`, `$this`) are recognized wherever the JavaScript grammar allows an expression, and never
|
|
1495
|
+
* inside strings or template literal text.
|
|
1496
|
+
*/
|
|
1497
|
+
class BindingParser {
|
|
1498
|
+
static { this._scanner = new pacemFoundation.Compile.Scanner(); }
|
|
1499
|
+
static { this._cache = new Map(); }
|
|
1500
|
+
/** Tokenizes `expression` (cached) and detects its references and unsafe constructs. */
|
|
1501
|
+
static analyze(expression) {
|
|
1502
|
+
const text = expression ?? '';
|
|
1503
|
+
const cache = BindingParser._cache;
|
|
1504
|
+
const cached = cache.get(text);
|
|
1505
|
+
if (cached != null) {
|
|
1506
|
+
return cached;
|
|
1507
|
+
}
|
|
1508
|
+
if (cache.size >= MAX_CACHED_ANALYSES) {
|
|
1509
|
+
cache.clear();
|
|
1510
|
+
}
|
|
1511
|
+
const tokens = BindingParser._scanner.tokenize(text, BINDING_SYNTAX);
|
|
1512
|
+
const significant = [];
|
|
1513
|
+
tokens.forEach((t, i) => {
|
|
1514
|
+
if (!INSIGNIFICANT.has(t.type)) {
|
|
1515
|
+
significant.push(i);
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
const hasReferences = tokens.some(isReference);
|
|
1519
|
+
const unsafe = BindingParser._findUnsafe(tokens, significant);
|
|
1520
|
+
const analysis = { tokens, significant, hasReferences, unsafe };
|
|
1521
|
+
cache.set(text, analysis);
|
|
1522
|
+
return analysis;
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Finds the first unsafe construct: `new`, members of `window`/`document`, `eval(…)`. Member names (`x.window`),
|
|
1526
|
+
* object keys (`{ new: 1 }`) and string contents never count.
|
|
1527
|
+
*/
|
|
1528
|
+
static _findUnsafe(tokens, significant) {
|
|
1529
|
+
for (let k = 0; k < significant.length; k++) {
|
|
1530
|
+
const token = tokens[significant[k]];
|
|
1531
|
+
const previous = tokens[significant[k - 1]];
|
|
1532
|
+
const next = tokens[significant[k + 1]];
|
|
1533
|
+
if (MEMBER_ACCESS.has(previous?.raw)) {
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
// (`{ new: … }` is an object key, not an instantiation)
|
|
1537
|
+
const instantiation = token.type === 'keyword' && token.raw === 'new' && next?.raw !== ':';
|
|
1538
|
+
if (instantiation) {
|
|
1539
|
+
return 'new';
|
|
1540
|
+
}
|
|
1541
|
+
if (token.type !== 'identifier') {
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
const accessed = next?.raw === '[' || MEMBER_ACCESS.has(next?.raw);
|
|
1545
|
+
if (UNSAFE_OWNERS.has(token.raw) && accessed) {
|
|
1546
|
+
return token.raw + next.raw;
|
|
1547
|
+
}
|
|
1548
|
+
if (token.raw === 'eval' && next?.raw === '(') {
|
|
1549
|
+
return 'eval(';
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Parses a binding expression against a scope.
|
|
1556
|
+
* @param expression The bare expression text (no `{{ }}` delimiters, no `, twoway`/`, once` modifier).
|
|
1557
|
+
* @param scope What the references resolve to.
|
|
1558
|
+
* @throws When the expression is unsafe (see {@link analyze}).
|
|
1559
|
+
*/
|
|
1560
|
+
static parse(expression, scope) {
|
|
1561
|
+
const analysis = BindingParser.analyze(expression);
|
|
1562
|
+
if (analysis.unsafe != null) {
|
|
1563
|
+
throw `Unsafe expression detected: "${analysis.unsafe}" in "${expression}".`;
|
|
1564
|
+
}
|
|
1565
|
+
if (!analysis.hasReferences) {
|
|
1566
|
+
return { kind: 'constant', functionBody: `return ${expression};`, voidBody: expression, dependencies: [] };
|
|
1567
|
+
}
|
|
1568
|
+
if (!scope.ready) {
|
|
1569
|
+
return { kind: 'pending', dependencies: [] };
|
|
1570
|
+
}
|
|
1571
|
+
const rewriter = new BindingRewriter(analysis, scope);
|
|
1572
|
+
return rewriter.run();
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
/** One rewrite pass: replaces the Pacem references with `__context_pacem` lookups, collecting args and dependencies. */
|
|
1576
|
+
class BindingRewriter {
|
|
1577
|
+
constructor(_analysis, _scope) {
|
|
1578
|
+
this._analysis = _analysis;
|
|
1579
|
+
this._scope = _scope;
|
|
1580
|
+
this._dependencies = [];
|
|
1581
|
+
this._args = { '$this': _scope.self };
|
|
1582
|
+
}
|
|
1583
|
+
run() {
|
|
1584
|
+
const tokens = this._analysis.tokens;
|
|
1585
|
+
let expression = '';
|
|
1586
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1587
|
+
const token = tokens[i];
|
|
1588
|
+
expression += isReference(token) ? this._rewrite(token, i) : token.raw;
|
|
1589
|
+
}
|
|
1590
|
+
// some referenced element/item/host isn't available (yet)
|
|
1591
|
+
for (let key in this._args) {
|
|
1592
|
+
if (this._args[key] == null) {
|
|
1593
|
+
return { kind: 'pending', dependencies: [] };
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
const dependencies = this._dependencies;
|
|
1597
|
+
// a single dependency on a plain property path can be bound two-way
|
|
1598
|
+
const trimmed = expression.trim();
|
|
1599
|
+
if (dependencies.length === 1 && !/[^\w\.\$]+/.test(trimmed)) {
|
|
1600
|
+
dependencies[0].twowayAllowed = true;
|
|
1601
|
+
}
|
|
1602
|
+
return {
|
|
1603
|
+
kind: 'resolved',
|
|
1604
|
+
functionBody: `try{ var ___$$$r = ${expression}; return ___$$$r; }catch(e){ }`,
|
|
1605
|
+
voidBody: `try{ ${expression} }catch(e){ }`,
|
|
1606
|
+
dependencies,
|
|
1607
|
+
args: this._args
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* The member values read directly after the token at `index` (`.a.b`, `?.a`), e.g. `['a', 'b']`.
|
|
1612
|
+
* As in javascript, `?.` is a member access like `.`; a member that gets invoked (`.map(`, `?.map(`, `.fn?.(`)
|
|
1613
|
+
* is a method, not a value, so the chain stops before it. Spaces and comments in between are skipped, as in javascript.
|
|
1614
|
+
*/
|
|
1615
|
+
_memberChain(index) {
|
|
1616
|
+
const tokens = this._analysis.tokens;
|
|
1617
|
+
const names = [];
|
|
1618
|
+
let k = this._significantAfter(index);
|
|
1619
|
+
while (MEMBER_ACCESS.has(this._significantRaw(k)) && isMemberName(tokens[this._significant(k + 1)])) {
|
|
1620
|
+
const following = this._significantRaw(k + 2);
|
|
1621
|
+
const afterFollowing = this._significantRaw(k + 3);
|
|
1622
|
+
if (isInvocation(following, afterFollowing)) {
|
|
1623
|
+
return names;
|
|
1624
|
+
}
|
|
1625
|
+
const name = tokens[this._significant(k + 1)].raw;
|
|
1626
|
+
names.push(name);
|
|
1627
|
+
k += 2;
|
|
1628
|
+
}
|
|
1629
|
+
return names;
|
|
1630
|
+
}
|
|
1631
|
+
/** The position, in the significant tokens, of the first one after the token at `index`. */
|
|
1632
|
+
_significantAfter(index) {
|
|
1633
|
+
const significant = this._analysis.significant;
|
|
1634
|
+
let k = 0;
|
|
1635
|
+
while (k < significant.length && significant[k] <= index) {
|
|
1636
|
+
k++;
|
|
1637
|
+
}
|
|
1638
|
+
return k;
|
|
1639
|
+
}
|
|
1640
|
+
/** The token index of the `k`-th significant token, if any. */
|
|
1641
|
+
_significant(k) {
|
|
1642
|
+
return this._analysis.significant[k] ?? -1;
|
|
1643
|
+
}
|
|
1644
|
+
_significantRaw(k) {
|
|
1645
|
+
const index = this._significant(k);
|
|
1646
|
+
return this._analysis.tokens[index]?.raw;
|
|
1647
|
+
}
|
|
1648
|
+
_ensureArg(key, factory) {
|
|
1649
|
+
const args = this._args;
|
|
1650
|
+
if (args[key] == null) {
|
|
1651
|
+
args[key] = factory();
|
|
1652
|
+
}
|
|
1653
|
+
return args[key];
|
|
1654
|
+
}
|
|
1655
|
+
_host() {
|
|
1656
|
+
return this._ensureArg(HOST_REFERENCE, () => this._scope.host());
|
|
1657
|
+
}
|
|
1658
|
+
_rewrite(token, index) {
|
|
1659
|
+
const chain = this._memberChain(index);
|
|
1660
|
+
switch (token.type) {
|
|
1661
|
+
case 'binding-host': {
|
|
1662
|
+
const host = this._host();
|
|
1663
|
+
this._addDependency(host, chain);
|
|
1664
|
+
return `${BINDING_CONTEXT_PREFIX}.${HOST_REFERENCE}`;
|
|
1665
|
+
}
|
|
1666
|
+
case 'binding-host-property': {
|
|
1667
|
+
const name = token.raw.slice(2);
|
|
1668
|
+
const host = this._host();
|
|
1669
|
+
const element = host == null ? null : host[name];
|
|
1670
|
+
this._addDependency(element, chain);
|
|
1671
|
+
return `${BINDING_CONTEXT_PREFIX}.${HOST_REFERENCE}.${name}`;
|
|
1672
|
+
}
|
|
1673
|
+
case 'binding-item':
|
|
1674
|
+
case 'binding-index': {
|
|
1675
|
+
// `^item` is 0 levels up, `^^item` 1, …
|
|
1676
|
+
const upLevels = token.raw.lastIndexOf('^');
|
|
1677
|
+
const member = token.type === 'binding-item' ? 'item' : 'index';
|
|
1678
|
+
const reference = `__item_${upLevels}_up_pacem`;
|
|
1679
|
+
const placeholder = this._ensureArg(reference, () => this._scope.item(upLevels));
|
|
1680
|
+
// the dependency is the `item`/`index` property itself, the path goes on with the item members
|
|
1681
|
+
const memberChain = member === 'item' ? [member].concat(chain) : [member];
|
|
1682
|
+
this._addDependency(placeholder, memberChain);
|
|
1683
|
+
return `${BINDING_CONTEXT_PREFIX}.${reference}.${member}`;
|
|
1684
|
+
}
|
|
1685
|
+
case 'binding-element': {
|
|
1686
|
+
const id = token.raw.slice(1);
|
|
1687
|
+
const element = this._ensureArg(id, () => this._scope.element(id));
|
|
1688
|
+
this._addDependency(element, chain);
|
|
1689
|
+
return `${BINDING_CONTEXT_PREFIX}.${id}`;
|
|
1690
|
+
}
|
|
1691
|
+
default: {
|
|
1692
|
+
// `$this`/`this`
|
|
1693
|
+
this._addDependency(this._scope.self, chain);
|
|
1694
|
+
return `${BINDING_CONTEXT_PREFIX}.$this`;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Registers a dependency on the first member of `chain` of `element`, unless it's a method, it doesn't exist,
|
|
1700
|
+
* or it's already registered.
|
|
1701
|
+
*/
|
|
1702
|
+
_addDependency(element, chain) {
|
|
1703
|
+
const property = chain[0];
|
|
1704
|
+
if (property == null || element == null || typeof element !== 'object' && typeof element !== 'function') {
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
if (!(property in element) || typeof element[property] === 'function') {
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
const dependencies = this._dependencies;
|
|
1711
|
+
const duplicate = dependencies.some(d => d.element === element && d.property === property);
|
|
1712
|
+
if (duplicate) {
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
const path = chain.join('.');
|
|
1716
|
+
dependencies.push({ element, property, path, twowayAllowed: false });
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1466
1720
|
/// <reference path="types.ts" />
|
|
1467
1721
|
/// <reference path="utils.ts" />
|
|
1468
1722
|
/// <reference path="utils-customelement.ts" />
|
|
1469
|
-
const CONTEXT_PREFIX =
|
|
1470
|
-
/** the following pattern matches:
|
|
1471
|
-
* -------------------------------
|
|
1472
|
-
* ciao "a tutti \"quanti\" voi" -> "a tutti \"quanti\" voi"
|
|
1473
|
-
* ciao 'a tutti "quanti" voi'+ mysel.value + 'e a nessun\' altra' -> 'a tutti "quanti" voi'
|
|
1474
|
-
* 'e a nessun\' altra'
|
|
1475
|
-
*/
|
|
1476
|
-
const stringPattern = /'(\\'|[^'])*[^\\]?'|"(\\"|[^"])*[^\\]?"/g;
|
|
1477
|
-
/** the following pattern matches:
|
|
1478
|
-
* -------------------------------
|
|
1479
|
-
* var l = new Date(); -> new
|
|
1480
|
-
* window.eval( -> window.
|
|
1481
|
-
* eval( -> eval(
|
|
1482
|
-
* eval ( -> eval (
|
|
1483
|
-
*/
|
|
1484
|
-
const safetyPattern = /[^\w]new\s|[^\w]window\s*[\.\[]|[^\w]document\s*\.|[^\w]eval\s*\(/;
|
|
1485
|
-
/** the following pattern matches:
|
|
1486
|
-
* -------------------------------
|
|
1487
|
-
* ^^^item.ciao -> ^^^item
|
|
1488
|
-
* !ciao.value -> !ciao.
|
|
1489
|
-
* :host.value -> :host.
|
|
1490
|
-
* ::child.prop -> ::child.
|
|
1491
|
-
* _connectTo(me.value) -> (me.
|
|
1492
|
-
* 009.ciao ->
|
|
1493
|
-
* this[that.value] -> [that.
|
|
1494
|
-
*/
|
|
1495
|
-
const variablePattern = /(^|[\s\(\[\+\-\*\/!])(:host\.|\^+item[\s\.,;\)\]]|\^+item$|\^+index[^\w\.]|\^+index$|\$?this[\.\s$]?|#[a-zA-Z_][\w]*|::[a-zA-Z_][\w]*)/g;
|
|
1496
|
-
///** the following pattern tests:
|
|
1497
|
-
// * -------------------------------
|
|
1498
|
-
// * __context.$this.myself.value -> true
|
|
1499
|
-
// * !__context.myelem.value -> false
|
|
1500
|
-
// * fn(myelem.value) -> false
|
|
1501
|
-
// * $this == that -> false
|
|
1502
|
-
// * ...
|
|
1503
|
-
// */
|
|
1504
|
-
//const purePropertyPathPattern = /^[\w\.\$]+/;
|
|
1723
|
+
const CONTEXT_PREFIX = BINDING_CONTEXT_PREFIX;
|
|
1505
1724
|
/**
|
|
1506
1725
|
* A parsed, compiled binding expression (the content of a `{{ ... }}` attribute value). Parsing
|
|
1507
1726
|
* (see {@link parse}) rewrites special tokens found in the source text - `:host.`, `^item`/`^^item`/...,
|
|
@@ -1591,136 +1810,45 @@
|
|
|
1591
1810
|
* Parses a binding expression's source text (the bare content of a `{{ ... }}` attribute, without the
|
|
1592
1811
|
* delimiters - see {@link CustomElementUtils.extractBindingAttributeExpression}) into an {@link Expression},
|
|
1593
1812
|
* resolving its special tokens against `element`'s scope (see {@link CustomElementUtils.findScopeContext}).
|
|
1594
|
-
*
|
|
1813
|
+
* Tokenization and rewriting are delegated to {@link BindingParser} (cached per expression text).
|
|
1814
|
+
* Throws if the expression uses an unsafe construct (`new`, members of `window`/`document`, `eval(`).
|
|
1595
1815
|
* @param expression Bare expression source text.
|
|
1596
1816
|
* @param element Element the expression is bound to; provides the scope special tokens (`:host.`, `#id`, `^item`, ...) resolve against.
|
|
1597
|
-
* @returns A constant expression if it has no
|
|
1817
|
+
* @returns A constant expression if it has no special tokens; a shared pending placeholder if `element` isn't attached to a scope yet; otherwise a fully resolved expression.
|
|
1598
1818
|
*/
|
|
1599
1819
|
static parse(expression, element) {
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
throw `Unsafe expression detected: "${trunk}".`;
|
|
1622
|
-
if (context == null) {
|
|
1623
|
-
// context is null, means viewActivated event still to be fired.
|
|
1624
|
-
// check whether this is a constant expression (then no need to instantiate actual binding listeners)
|
|
1625
|
-
// or not.
|
|
1626
|
-
if (new RegExp(variablePattern).test(trunk) === true) {
|
|
1627
|
-
independent = false;
|
|
1628
|
-
break;
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
else {
|
|
1632
|
-
let processedTrunk = trunk.replace(variablePattern, (mwhole, mstart, melem, index, input) => {
|
|
1633
|
-
independent = false;
|
|
1634
|
-
const cmpRef = `__host_pacem`;
|
|
1635
|
-
// default initialization := assumes `this`
|
|
1636
|
-
let retval = CONTEXT_PREFIX + '.$this' + (melem.endsWith('.') ? '.' : ''), el = element, dotIndex = input.indexOf('.', index), furtherParts = dotIndex > index ? input.substr(dotIndex + 1).trim() : '', pathRegexArray = /^[\w\.\$]+/.exec(furtherParts), path = pathRegexArray && pathRegexArray.length > 0 && pathRegexArray[0], propArray, prop = path && (propArray = path.split('.')).length > 0 && propArray[0];
|
|
1637
|
-
if (melem === ':host.') {
|
|
1638
|
-
el = args[cmpRef] = args[cmpRef] || CustomElementUtils.findHostContext(element);
|
|
1639
|
-
retval = `${CONTEXT_PREFIX}.${cmpRef}.`;
|
|
1640
|
-
}
|
|
1641
|
-
else if (melem.endsWith('^item') || melem.substr(0, melem.length - 1).endsWith('^item')) {
|
|
1642
|
-
let lastChar = melem.endsWith('^item') ? '' : melem.substr(melem.length - 1, 1);
|
|
1643
|
-
let upLevels = melem.length - (lastChar.length > 0 ? 6 : 5); // 5 = 'item'.length + 1 (zero-based)
|
|
1644
|
-
let itemRef = `__item_${upLevels}_up_pacem`;
|
|
1645
|
-
let item = Repeater.findItemContext(element, upLevels);
|
|
1646
|
-
el = args[itemRef] = args[itemRef] || (item && item.placeholder);
|
|
1647
|
-
path = 'item' + (path ? ('.' + path) : '');
|
|
1648
|
-
prop = 'item';
|
|
1649
|
-
retval = `${CONTEXT_PREFIX}.${itemRef}.item${lastChar}`;
|
|
1650
|
-
}
|
|
1651
|
-
else if (melem.endsWith('^index') || melem.substr(0, melem.length - 1).endsWith('^index')) {
|
|
1652
|
-
let lastChar = melem.endsWith('^index') ? '' : melem.substr(melem.length - 1, 1);
|
|
1653
|
-
let upLevels = melem.length - (lastChar.length > 0 ? 7 : 6); // 6 = 'index'.length + 1 (zero-based)
|
|
1654
|
-
let itemRef = `__item_${upLevels}_up_pacem`;
|
|
1655
|
-
let item = Repeater.findItemContext(element, upLevels);
|
|
1656
|
-
el = args[itemRef] = args[itemRef] || (item && item.placeholder);
|
|
1657
|
-
path = 'index';
|
|
1658
|
-
prop = 'index';
|
|
1659
|
-
retval = `${CONTEXT_PREFIX}.${itemRef}.index${lastChar}`;
|
|
1660
|
-
}
|
|
1661
|
-
else if (melem.startsWith('::')) {
|
|
1662
|
-
let melem0 = melem.substr(2, melem.length - 2);
|
|
1663
|
-
let host = args[cmpRef] = args[cmpRef] || CustomElementUtils.findHostContext(element);
|
|
1664
|
-
if (!Utils.isNull(host)) {
|
|
1665
|
-
el = host[melem0];
|
|
1666
|
-
}
|
|
1667
|
-
else {
|
|
1668
|
-
el = null;
|
|
1669
|
-
}
|
|
1670
|
-
retval = `${CONTEXT_PREFIX}.${cmpRef}.${melem0}`;
|
|
1671
|
-
}
|
|
1672
|
-
else if (melem.startsWith('#')) {
|
|
1673
|
-
let melem0 = melem.substr(1, melem.length - 1);
|
|
1674
|
-
el = args[melem0] = args[melem0] || context.querySelector('#' + melem0);
|
|
1675
|
-
retval = `${CONTEXT_PREFIX}.${melem0}`;
|
|
1676
|
-
}
|
|
1677
|
-
// merge dependencies
|
|
1678
|
-
if (prop && el && prop in el
|
|
1679
|
-
// && it is not a direct method call (which means that the 'prop' isn't in fact a 'func')
|
|
1680
|
-
&& typeof el[prop] !== 'function' //!isMethodCall
|
|
1681
|
-
// && does not already exist as a dependency
|
|
1682
|
-
&& dependencies.find(d => d.element === el && d.property == prop) == null) {
|
|
1683
|
-
dependencies.push({ element: el, property: prop, path: path, twowayAllowed: false });
|
|
1684
|
-
}
|
|
1685
|
-
// return value
|
|
1686
|
-
return mstart + retval;
|
|
1687
|
-
});
|
|
1688
|
-
expr += processedTrunk;
|
|
1689
|
-
if (j < strings.length) {
|
|
1690
|
-
const s = strings[j];
|
|
1691
|
-
expr += expression.substr(s.start, s.length);
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
if (independent) {
|
|
1696
|
-
// constant expression
|
|
1697
|
-
var constexpr = new Expression();
|
|
1698
|
-
constexpr._independent = true;
|
|
1699
|
-
constexpr._fnBody = `return ${expression};`;
|
|
1700
|
-
constexpr._voidBody = expression;
|
|
1701
|
-
constexpr._dependencies = [];
|
|
1702
|
-
return constexpr;
|
|
1703
|
-
}
|
|
1704
|
-
if (context == null) {
|
|
1705
|
-
return this._getPendingExpressionSingleton();
|
|
1706
|
-
}
|
|
1707
|
-
// if some dependency elements aren't available yet, then postpone...
|
|
1708
|
-
for (var elem in args) {
|
|
1709
|
-
if (args[elem] == null)
|
|
1710
|
-
return Expression._getPendingExpressionSingleton();
|
|
1820
|
+
const scope = Expression._scopeOf(element);
|
|
1821
|
+
const parsed = BindingParser.parse(expression, scope);
|
|
1822
|
+
return Expression._fromParsed(parsed);
|
|
1823
|
+
}
|
|
1824
|
+
/** The DOM surroundings of `element` the special tokens resolve against (lazily, except for the scope context). */
|
|
1825
|
+
static _scopeOf(element) {
|
|
1826
|
+
const context = CustomElementUtils.findScopeContext(element);
|
|
1827
|
+
return {
|
|
1828
|
+
ready: context != null,
|
|
1829
|
+
self: element,
|
|
1830
|
+
host: () => CustomElementUtils.findHostContext(element),
|
|
1831
|
+
item: (upLevels) => {
|
|
1832
|
+
const item = Repeater.findItemContext(element, upLevels);
|
|
1833
|
+
return item?.placeholder;
|
|
1834
|
+
},
|
|
1835
|
+
element: (id) => context.querySelector('#' + id)
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
static _fromParsed(parsed) {
|
|
1839
|
+
if (parsed.kind === 'pending') {
|
|
1840
|
+
return Expression._getPendingExpressionSingleton();
|
|
1711
1841
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1842
|
+
const retval = new Expression();
|
|
1843
|
+
retval._fnBody = parsed.functionBody;
|
|
1844
|
+
retval._voidBody = parsed.voidBody;
|
|
1845
|
+
retval._dependencies = parsed.dependencies;
|
|
1846
|
+
if (parsed.kind === 'constant') {
|
|
1847
|
+
retval._independent = true;
|
|
1848
|
+
return retval;
|
|
1717
1849
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
retexpr._fnBody = `try{ var ___$$$r = ${expr}; return ___$$$r; }catch(e){ }`;
|
|
1721
|
-
retexpr._voidBody = `try{ ${expr} }catch(e){ }`;
|
|
1722
|
-
retexpr._dependencies = dependencies;
|
|
1723
|
-
return retexpr;
|
|
1850
|
+
retval._args = parsed.args;
|
|
1851
|
+
return retval;
|
|
1724
1852
|
}
|
|
1725
1853
|
}
|
|
1726
1854
|
// }
|