UNPKG

3.69 kBPlain TextView Raw
1import {
2 createOverrideContext,
3 BindingBehavior,
4 ValueConverter,
5 sourceContext,
6 bindingMode,
7 OverrideContext
8} from 'aurelia-binding';
9
10const oneTime = bindingMode.oneTime;
11
12/**
13 * Update the override context.
14 * @param startIndex index in collection where to start updating.
15 */
16export function updateOverrideContexts(views, startIndex) {
17 let length = views.length;
18
19 if (startIndex > 0) {
20 startIndex = startIndex - 1;
21 }
22
23 for (; startIndex < length; ++startIndex) {
24 updateOverrideContext(views[startIndex].overrideContext, startIndex, length);
25 }
26}
27
28/**
29 * Creates a complete override context.
30 * @param data The item's value.
31 * @param index The item's index.
32 * @param length The collections total length.
33 * @param key The key in a key/value pair.
34 */
35export function createFullOverrideContext(repeat, data, index, length, key?: string): OverrideContext {
36 let bindingContext = {};
37 let overrideContext = createOverrideContext(bindingContext, repeat.scope.overrideContext);
38 // is key/value pair (Map)
39 if (typeof key !== 'undefined') {
40 bindingContext[repeat.key] = key;
41 bindingContext[repeat.value] = data;
42 } else {
43 bindingContext[repeat.local] = data;
44 }
45 updateOverrideContext(overrideContext, index, length);
46 return overrideContext;
47}
48
49/**
50 * Updates the override context.
51 * @param context The context to be updated.
52 * @param index The context's index.
53 * @param length The collection's length.
54 */
55export function updateOverrideContext(overrideContext, index, length) {
56 let first = (index === 0);
57 let last = (index === length - 1);
58 let even = index % 2 === 0;
59
60 overrideContext.$index = index;
61 overrideContext.$first = first;
62 overrideContext.$last = last;
63 overrideContext.$middle = !(first || last);
64 overrideContext.$odd = !even;
65 overrideContext.$even = even;
66}
67
68/**
69 * Gets a repeat instruction's source expression.
70 */
71export function getItemsSourceExpression(instruction, attrName) {
72 return instruction.behaviorInstructions
73 .filter(bi => bi.originalAttrName === attrName)[0]
74 .attributes
75 .items
76 .sourceExpression;
77}
78
79/**
80 * Unwraps an expression to expose the inner, pre-converted / behavior-free expression.
81 */
82export function unwrapExpression(expression) {
83 let unwrapped = false;
84 while (expression instanceof BindingBehavior) {
85 expression = expression.expression;
86 }
87 while (expression instanceof ValueConverter) {
88 expression = expression.expression;
89 unwrapped = true;
90 }
91 return unwrapped ? expression : null;
92}
93
94/**
95 * Returns whether an expression has the OneTimeBindingBehavior applied.
96 */
97export function isOneTime(expression) {
98 while (expression instanceof BindingBehavior) {
99 if (expression.name === 'oneTime') {
100 return true;
101 }
102 expression = expression.expression;
103 }
104 return false;
105}
106
107/**
108 * Forces a binding instance to reevaluate.
109 */
110export function updateOneTimeBinding(binding) {
111 if (binding.call && binding.mode === oneTime) {
112 binding.call(sourceContext);
113 } else if (binding.updateOneTimeBindings) {
114 binding.updateOneTimeBindings();
115 }
116}
117
118/**
119 * Returns the index of the element in an array, optionally using a matcher function.
120 */
121export function indexOf(array, item, matcher, startIndex?: number) {
122 if (!matcher) {
123 // native indexOf is more performant than a for loop
124 return array.indexOf(item);
125 }
126 const length = array.length;
127 for (let index = startIndex || 0; index < length; index++) {
128 if (matcher(array[index], item)) {
129 return index;
130 }
131 }
132 return -1;
133}