wallace 0.14.1 → 0.15.0

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/lib/component.js CHANGED
@@ -2,21 +2,15 @@ const throwAway = document.createElement("template");
2
2
  const NO_LOOKUP = "__";
3
3
 
4
4
  const ComponentPrototype = {
5
- /*
6
- COMPILER_MODS:
7
- if useController is false:
8
- - param `ctrl` is removed.
9
- - `this.ctrl = ctrl` is removed.
10
- */
11
- render: function (props, ctrl) {
5
+ render: function (props, /* #INCLUDE-IF: allowCtrl */ ctrl) {
12
6
  this.props = props;
13
- this.ctrl = ctrl;
7
+ /* #INCLUDE-IF: allowCtrl */ this.ctrl = ctrl;
14
8
  this.update();
15
9
  },
16
10
 
17
11
  /*
18
12
  COMPILER_MODS:
19
- if useFlags is false this is deleted, so `_u` can be renamed to `update`.
13
+ if allowParts is false this is deleted, so `_u` can be renamed to `update`.
20
14
  */
21
15
  update: function () {
22
16
  this._u(0, this._l);
@@ -24,18 +18,19 @@ const ComponentPrototype = {
24
18
 
25
19
  /*
26
20
  COMPILER_MODS:
27
- if useFlags is false:
21
+ if allowParts is false:
28
22
  - gets renamed to `update`
29
23
  - parameters are removed
30
24
  - add `i = 0, il = this._l` to variable declarator.
31
25
  */
32
26
  _u: function (i, il) {
33
- let watch, element, displayToggle, detacher, lookupTrue, shouldBeVisible;
27
+ let watch, element, displayToggle, detacher, query, lookupTrue, shouldBeVisible;
34
28
 
35
29
  const watches = this._w,
36
30
  props = this.props,
37
31
  previous = this._p,
38
32
  elements = this._e,
33
+ lookups = this._q,
39
34
  stash = this._s;
40
35
  /*
41
36
  Watches is an array of objects with keys:
@@ -58,9 +53,12 @@ const ComponentPrototype = {
58
53
  displayToggle = watch.v;
59
54
  shouldBeVisible = true;
60
55
  if (displayToggle) {
61
- lookupTrue = !!this._q[displayToggle.q](props, this);
62
- shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
56
+ query = displayToggle.q;
63
57
  detacher = displayToggle.d;
58
+ if (query !== undefined) {
59
+ lookupTrue = !!lookups[query](props, this);
60
+ shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
61
+ }
64
62
  if (detacher) {
65
63
  detacher.apply(element, shouldBeVisible, elements, stash);
66
64
  } else {
@@ -78,7 +76,7 @@ const ComponentPrototype = {
78
76
  callbacks[key](element, props, this, stash);
79
77
  } else {
80
78
  const oldValue = prev[key],
81
- newValue = this._q[key](props, this);
79
+ newValue = lookups[key](props, this);
82
80
  if (oldValue !== newValue) {
83
81
  callbacks[key](element, props, this, newValue);
84
82
  prev[key] = newValue;
@@ -88,23 +86,23 @@ const ComponentPrototype = {
88
86
  }
89
87
  i++;
90
88
  }
89
+ },
90
+ /* #INCLUDE-IF: allowDismount */ dismount: function () {
91
+ let i = 0,
92
+ stash = this._s,
93
+ dismountKeys = this._d;
94
+ while (i < dismountKeys.length) {
95
+ stash[dismountKeys[i]].dismount();
96
+ i++;
97
+ }
91
98
  }
92
99
  };
93
100
 
94
- Object.defineProperty(ComponentPrototype, "hidden", {
95
- set: function (value) {
96
- this.el.hidden = value;
97
- }
98
- });
99
-
100
101
  const ComponentBase = {
101
- prototype: ComponentPrototype
102
+ prototype: ComponentPrototype,
103
+ /* #INCLUDE-IF: allowStubs */ stubs: {}
102
104
  };
103
105
 
104
- if (wallaceConfig.flags.allowStubs) {
105
- ComponentBase.stubs = {};
106
- }
107
-
108
106
  /**
109
107
  *
110
108
  * @param {function} ComponentFunction - The Component definition function to add bits to.
@@ -128,7 +126,7 @@ export const initConstructor = (ComponentFunction, BaseComponentFunction) => {
128
126
  });
129
127
  } else {
130
128
  if (process.env.NODE_ENV !== "production") {
131
- Object.defineProperty(ComponentFunction, "name", {
129
+ Object.defineProperty(ComponentFunction, "methods", {
132
130
  set: function (value) {
133
131
  throw new Error(
134
132
  'Flag "allowMethods" must be set to true in the config for this feature.'
@@ -143,20 +141,30 @@ export const initConstructor = (ComponentFunction, BaseComponentFunction) => {
143
141
  }
144
142
  }
145
143
 
146
- if (wallaceConfig.flags.allowStubs) {
147
- ComponentFunction.stubs = Object.assign({}, BaseComponentFunction.stubs);
148
- }
144
+ /* #INCLUDE-IF: allowStubs */
145
+ ComponentFunction.stubs = Object.assign({}, BaseComponentFunction.stubs);
149
146
 
150
147
  return ComponentFunction;
151
148
  };
152
149
 
153
- export const defineComponent = (html, watches, queries, contructor, inheritFrom) => {
150
+ export const defineComponent = (
151
+ html,
152
+ watches,
153
+ queries,
154
+ contructor,
155
+ /* #INCLUDE-IF: allowDismount */ dismountKeys,
156
+ inheritFrom
157
+ ) => {
154
158
  const ComponentDefinition = initConstructor(contructor, inheritFrom || ComponentBase);
155
159
  const proto = ComponentDefinition.prototype;
156
160
  throwAway.innerHTML = html;
157
161
  proto._w = watches;
158
162
  proto._q = queries;
159
163
  proto._t = throwAway.content.firstChild;
164
+ if (wallaceConfig.flags.allowDismount) {
165
+ ComponentDefinition.pool = proto._c = []; // The shared component pool.
166
+ proto._d = dismountKeys; // Keys of stashed elements to dismount.
167
+ }
160
168
  if (wallaceConfig.flags.allowBase) {
161
169
  proto.base = ComponentPrototype;
162
170
  } else {
@@ -1,5 +1,9 @@
1
- export const createComponent = (ComponentFunction, props, ctrl) => {
1
+ export const createComponent = (
2
+ ComponentFunction,
3
+ props,
4
+ /* #INCLUDE-IF: allowCtrl */ ctrl
5
+ ) => {
2
6
  const component = new ComponentFunction();
3
- component.render(props, ctrl);
7
+ component.render(props, /* #INCLUDE-IF: allowCtrl */ ctrl);
4
8
  return component;
5
9
  };
package/lib/detacher.js CHANGED
@@ -1,25 +1,71 @@
1
1
  import { countOffset } from "./offsetter";
2
2
  /**
3
- * Deals with conditionally detaching elements with the if directive.
3
+ * Deals with conditionally detaching single elements or components.
4
+ * A Detacher is assigned to a watch, not a component.
4
5
  */
5
- export function Detacher(i, e, s) {
6
- this.i = i; // the initial element index.
7
- this.e = e; // the parent element key.
8
- this.s = s; // the stash key of the map of detached nodes.
6
+ export function Detacher(initialIndex, parentElementKey, offsetTrackerStashKey) {
7
+ this.i = initialIndex;
8
+ this.e = parentElementKey;
9
+ this.s = offsetTrackerStashKey;
9
10
  }
10
11
 
11
- Detacher.prototype.apply = function (element, shouldBeVisible, elements, stash) {
12
+ /*
13
+ This is very tricky bit of code.
14
+
15
+ It is affected by:
16
+ - initialIndex as passed into Detacher constructor.
17
+ - offsetTracker's initial value.
18
+
19
+ It take either:
20
+ - an element, which starts attached.
21
+ - a nester, whose element isn't attached to begin with.
22
+
23
+ Which affects how the insertion position is calculated.
24
+
25
+ About the offsetTracker:
26
+
27
+ The offset tracker is a map which stores a number against the initialIndex of each
28
+ conditionally displayed element, nester or repeater.
29
+
30
+ That number serves two purposes:
31
+ 1. For elements & nesters it indicates whether the element needs inserted or removed,
32
+ if any.
33
+ 2. For all cases, it is used to calculate the position at which new itsems should be
34
+ inserted.
35
+
36
+ Where it gets tricky is that the initial DOM will include elements, but not nester or
37
+ repeater elements.
38
+
39
+ For elements an offset of 0 means it is attached (and is the default if not set) and -1
40
+ indicates it is detached, and tells elements after it that they need to adjust their
41
+ insertion index by that much.
42
+
43
+ For nesters it is also 0 or -1, but the default is -1, which is set in the constructor.
44
+
45
+ For repeaters the offset is the number of items last rendered -1, because 0 items means
46
+ no elements inserted. However the repeaters never go through this function, so we can
47
+ assume the value here is always 0 or -1.
48
+
49
+ */
50
+ Detacher.prototype.apply = function (elementOrNester, shouldBeVisible, elements, stash) {
12
51
  const index = this.i,
13
- parent = elements[this.e],
14
52
  offsetTracker = stash[this.s];
15
53
  let ownOffset = offsetTracker.get(index) || 0;
16
- if (shouldBeVisible && ownOffset === -1) {
17
- const adjustedIndex = countOffset(offsetTracker, index);
18
- parent.insertBefore(element, parent.childNodes[adjustedIndex]);
19
- ownOffset = 0;
20
- } else if (!shouldBeVisible && ownOffset === 0) {
21
- parent.removeChild(element);
22
- ownOffset = -1;
54
+
55
+ if ((shouldBeVisible && ownOffset < 0) || (!shouldBeVisible && ownOffset === 0)) {
56
+ var parent = elements[this.e],
57
+ element =
58
+ elementOrNester instanceof HTMLElement
59
+ ? elementOrNester
60
+ : elementOrNester.get().el;
61
+ if (shouldBeVisible) {
62
+ var adjustedIndex = countOffset(offsetTracker, index);
63
+ parent.insertBefore(element, parent.childNodes[adjustedIndex]);
64
+ ownOffset = 0;
65
+ } else {
66
+ parent.removeChild(element);
67
+ ownOffset = -1;
68
+ }
69
+ offsetTracker.set(index, ownOffset);
23
70
  }
24
- offsetTracker.set(index, ownOffset);
25
71
  };
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@ export { Detacher } from "./detacher";
3
3
  export { extendComponent } from "./extend";
4
4
  export { mount } from "./mount";
5
5
  export { createComponent } from "./createComponent";
6
- export { nestComponent } from "./nestComponent";
6
+ export { Nester } from "./repeaters/nester";
7
7
  export { saveRef } from "./refs";
8
8
  export { savePart } from "./part";
9
9
  export { KeyedRepeater } from "./repeaters/keyed";
package/lib/mount.js CHANGED
@@ -1,17 +1,21 @@
1
- import { replaceNode } from "./utils";
2
-
3
1
  /**
4
2
  * Creates and mounts a component onto an element.
5
3
  *
6
4
  * @param {any} elementOrId Either a string representing an id, or an element.
7
5
  * @param {callable} componentDefinition The class of Component to create
8
6
  * @param {object} props The props to pass to the component (optional)
7
+ * @param {ctrl} props The ctrl to pass to the component (optional)
9
8
  */
10
- export const mount = (elementOrId, componentDefinition, props, ctrl) => {
9
+ export const mount = (
10
+ elementOrId,
11
+ componentDefinition,
12
+ props,
13
+ /* #INCLUDE-IF: allowCtrl */ ctrl
14
+ ) => {
11
15
  const component = new componentDefinition();
12
- component.render(props, ctrl);
16
+ component.render(props, /* #INCLUDE-IF: allowCtrl */ ctrl);
13
17
  const element =
14
18
  typeof elementOrId === "string" ? document.getElementById(elementOrId) : elementOrId;
15
- replaceNode(element, component.el);
19
+ element.parentNode.replaceChild(component.el, element);
16
20
  return component;
17
21
  };
package/lib/offsetter.js CHANGED
@@ -1,8 +1,7 @@
1
- export function countOffset(offsetTracker, index) {
1
+ export const countOffset = (offsetTracker, index) => {
2
2
  let offset = 0;
3
3
  for (let [key, value] of offsetTracker.entries()) {
4
- if (key >= index) break;
5
- offset += value;
4
+ if (key < index) offset += value;
6
5
  }
7
6
  return index + offset;
8
- }
7
+ };
package/lib/part.js CHANGED
@@ -1,11 +1,11 @@
1
1
  function Part(component, start, end) {
2
- this._c = component;
3
- this._s = start;
4
- this._e = end;
2
+ this.c = component;
3
+ this.s = start;
4
+ this.e = end;
5
5
  }
6
6
 
7
7
  Part.prototype.update = function () {
8
- this._c._u(this._s, this._e);
8
+ this.c._u(this.s, this.e);
9
9
  };
10
10
 
11
11
  /**
@@ -2,114 +2,135 @@ import { countOffset } from "../offsetter";
2
2
 
3
3
  /**
4
4
  * Repeats nested components, reusing items based on key.
5
- *
6
- * COMPILER_MODS:
7
- * if allowRepeaterSiblings is false the last two parameters are removed.
8
5
  */
9
- export function KeyedRepeater(componentDefinition, key, adjustmentTracker, initialIndex) {
6
+ export function KeyedRepeater(
7
+ componentDefinition,
8
+ key,
9
+ /* #INCLUDE-IF: allowRepeaterSiblings */ adjustmentTracker,
10
+ /* #INCLUDE-IF: allowRepeaterSiblings */ initialIndex
11
+ ) {
10
12
  this.d = componentDefinition;
13
+ /* #INCLUDE-IF: allowDismount */ this.s = componentDefinition.pool;
14
+ this.p = new Map();
11
15
  this.k = []; // array of keys as last set.
12
16
  if (typeof key === "function") {
13
17
  this.f = key;
14
18
  } else {
15
19
  this.n = key;
16
20
  }
17
- if (wallaceConfig.flags.allowRepeaterSiblings) {
18
- this.a = adjustmentTracker;
19
- this.i = initialIndex;
20
- }
21
+ /* #INCLUDE-IF: allowRepeaterSiblings */ this.a = adjustmentTracker;
22
+ /* #INCLUDE-IF: allowRepeaterSiblings */ this.i = initialIndex;
21
23
  }
22
24
 
23
25
  /**
24
26
  * Updates the element's childNodes to match the items.
25
27
  * Performance is important.
26
- *
27
- * @param {DOMElement} parent - The DOM element to patch.
28
- * @param {Array} items - Array of items which will be passed as props.
29
- * @param {Map} pool - pool of component instances.
30
- * @param {any} ctrl - The parent item's controller.
31
28
  */
32
- KeyedRepeater.prototype.patch = function (parent, items, pool, ctrl) {
33
- const componentDefinition = this.d,
34
- keyName = this.n,
35
- keyFn = this.f,
36
- useKeyName = keyName !== undefined,
37
- childNodes = parent.childNodes,
38
- itemsLength = items.length,
39
- previousKeys = this.k,
40
- previousKeysLength = previousKeys.length,
41
- newKeys = [],
42
- previousKeysSet = new Set(previousKeys),
43
- frag = document.createDocumentFragment();
29
+ KeyedRepeater.prototype = {
30
+ patch: function (parent, items, /* #INCLUDE-IF: allowCtrl */ ctrl) {
31
+ const componentDefinition = this.d,
32
+ /* #INCLUDE-IF: allowDismount */ sharedPool = this.s,
33
+ ownPool = this.p,
34
+ keyName = this.n,
35
+ keyFn = this.f,
36
+ useKeyName = keyName !== undefined,
37
+ childNodes = parent.childNodes,
38
+ itemsLength = items.length,
39
+ previousKeys = this.k,
40
+ previousKeysLength = previousKeys.length,
41
+ newKeys = [],
42
+ previousKeysSet = new Set(previousKeys),
43
+ frag = document.createDocumentFragment();
44
44
 
45
- let item,
46
- el,
47
- itemKey,
48
- component,
49
- initialIndex,
50
- offsetTracker,
51
- endAnchor = null,
52
- adjustment = 0,
53
- anchor = null,
54
- fragAnchor = null,
55
- untouched = true,
56
- append = false,
57
- offset = previousKeysLength - itemsLength,
58
- i = itemsLength - 1;
45
+ let item,
46
+ el,
47
+ itemKey,
48
+ component,
49
+ initialIndex,
50
+ offsetTracker,
51
+ endAnchor = null,
52
+ adjustment = 0,
53
+ anchor = null,
54
+ fragAnchor = null,
55
+ untouched = true,
56
+ append = false,
57
+ offset = previousKeysLength - itemsLength,
58
+ i = itemsLength - 1;
59
59
 
60
- if (wallaceConfig.flags.allowRepeaterSiblings) {
61
- offsetTracker = this.a;
62
- initialIndex = this.i;
63
- if (offsetTracker) {
64
- adjustment = countOffset(offsetTracker, initialIndex);
65
- endAnchor = childNodes[previousKeysLength + adjustment] || null;
66
- anchor = endAnchor;
67
- untouched = false;
60
+ if (wallaceConfig.flags.allowRepeaterSiblings) {
61
+ offsetTracker = this.a;
62
+ initialIndex = this.i;
63
+ if (offsetTracker) {
64
+ adjustment = countOffset(offsetTracker, initialIndex);
65
+ endAnchor = childNodes[previousKeysLength + adjustment] || null;
66
+ anchor = endAnchor;
67
+ untouched = false;
68
+ }
68
69
  }
69
- }
70
70
 
71
- // Working backwards saves us having to track moves.
72
- while (i >= 0) {
73
- item = items[i];
74
- itemKey = useKeyName ? item[keyName] : keyFn(item);
75
- if (!(component = pool.get(itemKey))) {
76
- component = new componentDefinition();
77
- pool.set(itemKey, component);
78
- }
79
- component.render(item, ctrl);
80
- el = component.el;
81
- if (untouched && !previousKeysSet.has(itemKey)) {
82
- frag.insertBefore(el, fragAnchor);
83
- fragAnchor = el;
84
- append = true;
85
- offset++;
86
- } else {
87
- if (itemKey !== previousKeys[i + offset]) {
88
- parent.insertBefore(el, anchor);
89
- untouched = false;
71
+ // Working backwards saves us having to track moves.
72
+ while (i >= 0) {
73
+ item = items[i];
74
+ itemKey = useKeyName ? item[keyName] : keyFn(item);
75
+ if (!(component = ownPool.get(itemKey))) {
76
+ if (wallaceConfig.flags.allowDismount) {
77
+ component = sharedPool.pop() || new componentDefinition();
78
+ } else {
79
+ component = new componentDefinition();
80
+ }
81
+ ownPool.set(itemKey, component);
82
+ }
83
+ component.render(item, /* #INCLUDE-IF: allowCtrl */ ctrl);
84
+ el = component.el;
85
+ if (untouched && !previousKeysSet.has(itemKey)) {
86
+ frag.insertBefore(el, fragAnchor);
87
+ fragAnchor = el;
88
+ append = true;
89
+ offset++;
90
+ } else {
91
+ if (itemKey !== previousKeys[i + offset]) {
92
+ parent.insertBefore(el, anchor);
93
+ untouched = false;
94
+ }
95
+ anchor = el;
90
96
  }
91
- anchor = el;
97
+ newKeys.push(itemKey);
98
+ previousKeysSet.delete(itemKey);
99
+ i--;
92
100
  }
93
- newKeys.push(itemKey);
94
- previousKeysSet.delete(itemKey);
95
- i--;
96
- }
97
101
 
98
- if (append) {
99
- parent.insertBefore(frag, endAnchor);
100
- }
102
+ if (append) {
103
+ parent.insertBefore(frag, endAnchor);
104
+ }
101
105
 
102
- let toStrip = previousKeysSet.size;
103
- while (toStrip > 0) {
104
- parent.removeChild(childNodes[adjustment]);
105
- toStrip--;
106
- }
106
+ let toStrip = previousKeysSet.size;
107
+ while (toStrip > 0) {
108
+ parent.removeChild(childNodes[adjustment]);
109
+ toStrip--;
110
+ }
107
111
 
108
- this.k = newKeys.reverse();
112
+ this.k = newKeys.reverse();
109
113
 
110
- if (wallaceConfig.flags.allowRepeaterSiblings) {
114
+ /* #INCLUDE-IF: allowRepeaterSiblings */
111
115
  if (offsetTracker) {
112
116
  offsetTracker.set(initialIndex, itemsLength - 1);
113
117
  }
118
+
119
+ /* #INCLUDE-IF: allowDismount */
120
+ for (const keyToRemove of previousKeysSet) {
121
+ component = ownPool.get(keyToRemove);
122
+ sharedPool.push(component);
123
+ component.dismount();
124
+ ownPool.delete(keyToRemove);
125
+ }
126
+ },
127
+ /* #INCLUDE-IF: allowDismount */ dismount: function () {
128
+ const pool = this.p,
129
+ sharedPool = this.s;
130
+ for (const [key, value] of pool.entries()) {
131
+ sharedPool.push(value);
132
+ value.dismount();
133
+ }
134
+ pool.clear();
114
135
  }
115
136
  };
@@ -0,0 +1,29 @@
1
+ export function Nester(componentDefinition) {
2
+ this.d = componentDefinition;
3
+ this.i = null;
4
+ /* #INCLUDE-IF: allowDismount */ this.s = componentDefinition.pool;
5
+ }
6
+
7
+ Nester.prototype = {
8
+ send: function (props, ctrl) {
9
+ this.get().render(props, ctrl);
10
+ },
11
+ get: function () {
12
+ if (!this.i) {
13
+ if (wallaceConfig.flags.allowDismount) {
14
+ this.i = this.s.pop() || new this.d();
15
+ } else {
16
+ this.i = new this.d();
17
+ }
18
+ }
19
+ return this.i;
20
+ },
21
+ /* #INCLUDE-IF: allowDismount */ dismount: function () {
22
+ const i = this.i;
23
+ if (i) {
24
+ i.dismount();
25
+ this.s.push(i);
26
+ this.i = null;
27
+ }
28
+ }
29
+ };
@@ -2,77 +2,103 @@ import { countOffset } from "../offsetter";
2
2
 
3
3
  /**
4
4
  * Repeats nested components, yielding from the pool sequentially.
5
- *
6
- * COMPILER_MODS:
7
- * if allowRepeaterSiblings is false the last two parameters are removed.
8
5
  */
9
- export function SequentialRepeater(componentDefinition, adjustmentTracker, initialIndex) {
6
+ export function SequentialRepeater(
7
+ componentDefinition,
8
+ /* #INCLUDE-IF: allowRepeaterSiblings */ adjustmentTracker,
9
+ /* #INCLUDE-IF: allowRepeaterSiblings */ initialIndex
10
+ ) {
10
11
  this.d = componentDefinition;
12
+ /* #INCLUDE-IF: allowDismount */ this.s = componentDefinition.pool;
13
+ this.p = [];
11
14
  this.c = 0; // Child count
12
- if (wallaceConfig.flags.allowRepeaterSiblings) {
13
- this.a = adjustmentTracker;
14
- this.i = initialIndex;
15
- }
15
+ /* #INCLUDE-IF: allowRepeaterSiblings */ this.a = adjustmentTracker;
16
+ /* #INCLUDE-IF: allowRepeaterSiblings */ this.i = initialIndex;
16
17
  }
17
18
 
18
19
  /**
19
20
  * Updates the element's childNodes to match the items.
20
21
  * Performance is important.
21
- *
22
- * @param {DOMElement} parent - The DOM element to patch.
23
- * @param {Array} items - Array of items which will be passed as props.
24
- * @param {Array} pool - pool of component instances.
25
- * @param {any} ctrl - The parent item's controller.
26
22
  */
27
- SequentialRepeater.prototype.patch = function (parent, items, pool, ctrl) {
28
- const componentDefinition = this.d,
29
- previousChildCount = this.c,
30
- itemsLength = items.length,
31
- childNodes = parent.childNodes;
23
+ SequentialRepeater.prototype = {
24
+ patch: function (parent, items, /* #INCLUDE-IF: allowCtrl */ ctrl) {
25
+ const componentDefinition = this.d,
26
+ /* #INCLUDE-IF: allowDismount */ sharedPool = this.s,
27
+ previousChildCount = this.c,
28
+ pool = this.p,
29
+ itemsLength = items.length,
30
+ childNodes = parent.childNodes;
32
31
 
33
- let i = 0,
34
- offset = 0,
35
- component,
36
- nextElement,
37
- initialIndex,
38
- offsetTracker,
39
- endOfRange = previousChildCount,
40
- poolCount = pool.length;
32
+ let i = 0,
33
+ offset = 0,
34
+ component,
35
+ nextElement,
36
+ initialIndex,
37
+ offsetTracker,
38
+ endOfRange = previousChildCount,
39
+ poolCount = pool.length,
40
+ originalPoolCount = poolCount;
41
41
 
42
- if (wallaceConfig.flags.allowRepeaterSiblings) {
43
- initialIndex = this.i;
44
- offsetTracker = this.a;
45
- if (offsetTracker) {
46
- // The repeat element has siblings
47
- offset = countOffset(offsetTracker, initialIndex);
48
- endOfRange += offset;
49
- nextElement = childNodes[endOfRange] || null;
42
+ if (wallaceConfig.flags.allowRepeaterSiblings) {
43
+ initialIndex = this.i;
44
+ offsetTracker = this.a;
45
+ if (offsetTracker) {
46
+ // The repeat element has siblings
47
+ offset = countOffset(offsetTracker, initialIndex);
48
+ endOfRange += offset;
49
+ nextElement = childNodes[endOfRange] || null;
50
+ }
50
51
  }
51
- }
52
- while (i < itemsLength) {
53
- if (i < poolCount) {
54
- component = pool[i];
55
- } else {
56
- component = new componentDefinition();
57
- pool.push(component);
58
- poolCount++;
52
+ while (i < itemsLength) {
53
+ if (i < poolCount) {
54
+ component = pool[i];
55
+ } else {
56
+ if (wallaceConfig.flags.allowDismount) {
57
+ component = sharedPool.pop() || new componentDefinition();
58
+ } else {
59
+ component = new componentDefinition();
60
+ }
61
+ pool.push(component);
62
+ poolCount++;
63
+ }
64
+ component.render(items[i], /* #INCLUDE-IF: allowCtrl */ ctrl);
65
+ if (i >= previousChildCount) {
66
+ parent.insertBefore(component.el, nextElement);
67
+ }
68
+ i++;
59
69
  }
60
- component.render(items[i], ctrl);
61
- if (i >= previousChildCount) {
62
- parent.insertBefore(component.el, nextElement);
70
+ this.c = itemsLength;
71
+
72
+ let removeAtIndex = offset + previousChildCount - 1;
73
+ const stopAtIndex = offset + itemsLength - 1;
74
+ for (let i = removeAtIndex; i > stopAtIndex; i--) {
75
+ parent.removeChild(childNodes[i]);
63
76
  }
64
- i++;
65
- }
66
- this.c = itemsLength;
67
77
 
68
- let removeAtIndex = offset + previousChildCount - 1;
69
- const stopatIndex = offset + itemsLength - 1;
70
- for (let i = removeAtIndex; i > stopatIndex; i--) {
71
- parent.removeChild(childNodes[i]);
72
- }
73
- if (wallaceConfig.flags.allowRepeaterSiblings) {
78
+ /* #INCLUDE-IF: allowRepeaterSiblings */
74
79
  if (offsetTracker) {
75
80
  offsetTracker.set(initialIndex, itemsLength - 1);
76
81
  }
82
+
83
+ /* #INCLUDE-IF: allowDismount */
84
+ while (originalPoolCount > itemsLength) {
85
+ component = pool.pop();
86
+ sharedPool.push(component);
87
+ component.dismount();
88
+ originalPoolCount--;
89
+ }
90
+ },
91
+ /* #INCLUDE-IF: allowDismount */ dismount: function () {
92
+ let component,
93
+ pool = this.p,
94
+ poolCount = pool.length,
95
+ sharedPool = this.s;
96
+ while (poolCount > 0) {
97
+ component = pool.pop();
98
+ sharedPool.push(component);
99
+ component.dismount();
100
+ poolCount--;
101
+ }
102
+ pool.length = 0;
77
103
  }
78
104
  };
package/lib/router.js CHANGED
@@ -22,8 +22,8 @@ export const route = (path, componentDef, converter, cleanup) =>
22
22
 
23
23
  export const Router = () => <div></div>;
24
24
 
25
- Router.methods = {
26
- render(props, ctrl) {
25
+ Object.assign(Router.prototype, {
26
+ render(props, /* #INCLUDE-IF: allowCtrl */ ctrl) {
27
27
  const defaultError = (error, router) => (router.el.innerHTML = error.message);
28
28
  this.error = props.error || defaultError;
29
29
  this.current = null;
@@ -33,7 +33,7 @@ Router.methods = {
33
33
  this.el.setAttribute(k, props.atts[k]);
34
34
  });
35
35
  }
36
- this.base.render.call(this, props, ctrl);
36
+ this.base.render.call(this, props, /* #INCLUDE-IF: allowCtrl */ ctrl);
37
37
  },
38
38
  async onHashChange() {
39
39
  const path = location.hash.slice(1) || "",
@@ -45,7 +45,10 @@ Router.methods = {
45
45
  while (i < len) {
46
46
  let route = routes[i];
47
47
  if ((routeData = route.match(path))) {
48
- const component = await route.getComponent(routeData, this.ctrl);
48
+ const component = await route.getComponent(
49
+ routeData,
50
+ /* #INCLUDE-IF: allowCtrl */ this.ctrl
51
+ );
49
52
  this.current && this.current.cleanup();
50
53
  this.mount(component);
51
54
  this.current = route;
@@ -62,7 +65,7 @@ Router.methods = {
62
65
  this.el.textContent = "";
63
66
  this.el.appendChild(component.el);
64
67
  }
65
- };
68
+ });
66
69
 
67
70
  export function Route(path, def, convert, cleanup) {
68
71
  this.chunks = path
@@ -96,12 +99,12 @@ Route.prototype = {
96
99
  }
97
100
  return { args, params: new URLSearchParams(query), url };
98
101
  },
99
- async getComponent(routeData, ctrl) {
102
+ async getComponent(routeData, /* #INCLUDE-IF: allowCtrl */ ctrl) {
100
103
  if (!this.component) {
101
104
  this.component = new this.def();
102
105
  }
103
106
  const props = await this._convert(routeData);
104
- this.component.render(props, ctrl);
107
+ this.component.render(props, /* #INCLUDE-IF: allowCtrl */ ctrl);
105
108
  return this.component;
106
109
  },
107
110
  /**
package/lib/types.d.ts CHANGED
@@ -525,12 +525,13 @@ watchedObj[0] = 'foo'; // throws error.
525
525
  You can toggle flags in your babel config to disable certain features for cutting edge
526
526
  performance and bundle size:
527
527
 
528
- 1. allowBase - enables use of `base` in components.
529
- 2. allowCtrl - enables use of `ctrl` in components.
530
- 3. allowMethods - adds the `methods` helper to components.
531
- 4. allowParts - enables use of parts.
532
- 5. allowRepeaterSiblings - allows repeaters to have siblings.
533
- 6. allowStubs - enables the use of stubs.
528
+ 1. `allowBase` - allows use of `base` in components.
529
+ 2. `allowCtrl` - allows use of `ctrl` in components.
530
+ 3. `allowDismount` - allows components to handle dismounting.
531
+ 4. `allowMethods` - allows use of `methods` helper to components.
532
+ 5. `allowParts` - allows use of parts.
533
+ 6. `allowRepeaterSiblings` - allows repeaters to have siblings.
534
+ 7. `allowStubs` - allows use of stubs.
534
535
 
535
536
  These flags default to true, unless you specify `flags` in the plugin config, in which
536
537
  case they default to false and you need to explicitly enable those you want:
package/lib/utils.js CHANGED
@@ -1,16 +1,12 @@
1
- export function findElement(rootElement, path) {
1
+ export const findElement = (rootElement, path) => {
2
2
  let node = rootElement;
3
3
  for (let i = 0; i < path.length; i++) {
4
4
  node = node.childNodes[path[i]];
5
5
  }
6
6
  return node;
7
- }
7
+ };
8
8
 
9
- export function replaceNode(nodeToReplace, newNode) {
10
- nodeToReplace.parentNode.replaceChild(newNode, nodeToReplace);
11
- }
12
-
13
- export function onEvent(element, eventName, callback) {
9
+ export const onEvent = (element, eventName, callback) => {
14
10
  element.addEventListener(eventName, callback);
15
11
  return element;
16
- }
12
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wallace",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "author": "Andrew Buchan",
5
5
  "description": "An insanely small, fast, intuitive and extendable front-end framework",
6
6
  "homepage": "https://wallace.js.org",
@@ -15,8 +15,8 @@
15
15
  "test": "jest --clearCache && jest"
16
16
  },
17
17
  "dependencies": {
18
- "babel-plugin-wallace": "^0.14.1",
18
+ "babel-plugin-wallace": "^0.15.0",
19
19
  "browserify": "^17.0.1"
20
20
  },
21
- "gitHead": "c60384d682e38095780dd260004299e9c4038583"
21
+ "gitHead": "87a69fe8a8f3b8dd20e66eb0d125998658272931"
22
22
  }
@@ -1,8 +0,0 @@
1
- import { findElement, replaceNode } from "./utils";
2
-
3
- export const nestComponent = (rootElement, path, componentDefinition) => {
4
- const el = findElement(rootElement, path),
5
- child = new componentDefinition();
6
- replaceNode(el, child.el);
7
- return child;
8
- };