wallace 0.0.7 → 0.1.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
@@ -1,17 +1,22 @@
1
+ const ALWAYS_UPDATE = "__";
2
+
1
3
  /**
2
4
  * The base component.
3
5
  */
4
- export function Component(parent) {
5
- this.parent = parent; // The parent component. TODO: is this needed?
6
+ export function Component() {
7
+ this.ctrl = undefined; // The controller.
6
8
  this.props = undefined; // The props passed to the component. May be changed.
7
9
  this.el = null; // the element - will be set during build.
8
10
  this.ref = {}; // user set references to elements or components.
9
11
  // Internal state objects
10
12
  this._e = {}; // The dynamic elements in the DOM.
11
- this._p = {}; // The previous values for watches to compare against.
12
13
  this._s = []; // A stash for misc objects.
14
+ this._p = {}; // The previous values for watches to compare against.
15
+ this._r = {}; // The current values read during an update.
13
16
  }
14
17
 
18
+ Component.stubs = {};
19
+
15
20
  var proto = Component.prototype;
16
21
 
17
22
  Object.defineProperty(proto, "hidden", {
@@ -20,11 +25,50 @@ Object.defineProperty(proto, "hidden", {
20
25
  },
21
26
  });
22
27
 
28
+ proto._gs = function (name) {
29
+ return this.constructor.stubs[name];
30
+ };
31
+
32
+ /**
33
+ * Reads a query during update, returns an array with (oldValue, newValue, changed)
34
+ * and saves the old value. Must reset this._r before each run.
35
+ */
36
+ proto._rq = function (props, key) {
37
+ const run = this._r;
38
+ if (run[key] === undefined) {
39
+ let oldValue = this._p[key];
40
+ const newValue = this._q[key](props, this);
41
+ this._p[key] = newValue;
42
+ const rtn = [newValue, oldValue, newValue !== oldValue];
43
+ run[key] = rtn;
44
+ return rtn;
45
+ }
46
+ return run[key];
47
+ };
48
+
49
+ /**
50
+ * Applies the callbacks.
51
+ */
52
+ proto._ac = function (props, element, callbacks) {
53
+ for (let key in callbacks) {
54
+ let callback = callbacks[key];
55
+ if (key === ALWAYS_UPDATE) {
56
+ callback(element, props, this);
57
+ } else {
58
+ const result = this._rq(props, key);
59
+ if (result[2]) {
60
+ callback(result[0], result[1], element, props, this);
61
+ }
62
+ }
63
+ }
64
+ };
65
+
23
66
  /**
24
- * Sets the props and updates the component.
67
+ * The render function that gets called by parent components.
25
68
  */
26
- proto.render = function (props) {
69
+ proto.render = function (props, ctrl) {
27
70
  this.props = props;
71
+ this.ctrl = ctrl;
28
72
  this.update();
29
73
  };
30
74
 
@@ -39,10 +83,8 @@ proto.update = function () {
39
83
  parent,
40
84
  displayToggle,
41
85
  detacher,
42
- lookupReturn,
43
86
  lookupTrue,
44
87
  shouldBeVisible,
45
- visibilityChanged,
46
88
  detachedElements,
47
89
  detachedElement,
48
90
  index,
@@ -50,11 +92,10 @@ proto.update = function () {
50
92
  thisElement;
51
93
 
52
94
  const watches = this._w;
53
- const lookup = this._l;
54
95
  const props = this.props;
55
- lookup.reset();
56
96
  const il = watches.length;
57
- /*
97
+ this._r = {};
98
+ /*
58
99
  Watches is an array of objects with keys:
59
100
  e: the element reference (string)
60
101
  c: the callbacks (object)
@@ -78,10 +119,8 @@ proto.update = function () {
78
119
  i++;
79
120
  shouldBeVisible = true;
80
121
  if (displayToggle) {
81
- lookupReturn = lookup.get(this, props, displayToggle.q);
82
- lookupTrue = !!lookupReturn.n;
122
+ lookupTrue = !!this._rq(props, displayToggle.q)[0];
83
123
  shouldBeVisible = displayToggle.r ? lookupTrue : !lookupTrue;
84
- visibilityChanged = lookupTrue != !!lookupReturn.o;
85
124
  detacher = displayToggle.d;
86
125
  if (detacher) {
87
126
  index = detacher.i;
@@ -96,7 +135,7 @@ proto.update = function () {
96
135
  }).length;
97
136
  parent.insertBefore(
98
137
  detachedElement,
99
- parent.childNodes[adjustedIndex],
138
+ parent.childNodes[adjustedIndex]
100
139
  );
101
140
  detachedElements[index] = null;
102
141
  } else if (!shouldBeVisible && !detachedElement) {
@@ -112,7 +151,7 @@ proto.update = function () {
112
151
  }
113
152
  }
114
153
  if (shouldBeVisible) {
115
- lookup.applyCallbacks(this, props, element, watch.c);
154
+ this._ac(props, element, watch.c);
116
155
  }
117
156
  }
118
157
  };
package/lib/index.js CHANGED
@@ -1,34 +1,31 @@
1
- import { createComponent, createProxy, mount } from "./utils";
1
+ import { mount, watch } from "./utils";
2
2
  import { Component } from "./component";
3
- import { KeyedPool, SequentialPool } from "./pool";
3
+ import { KeyedRepeater, SequentialRepeater } from "./repeaters";
4
4
  import {
5
5
  extendComponent,
6
+ defineComponent,
6
7
  findElement,
7
- getKeyedPool,
8
- getSequentialPool,
8
+ getKeyedRepeater,
9
+ getSequentialRepeater,
9
10
  onEvent,
10
11
  nestComponent,
11
- defineComponent,
12
- extendPrototype,
13
- stashMisc,
14
12
  saveRef,
13
+ stashMisc,
15
14
  } from "./initCalls";
16
15
 
17
16
  export {
18
- extendComponent,
19
17
  Component,
20
- createComponent,
21
- createProxy,
22
18
  defineComponent,
23
- extendPrototype,
19
+ extendComponent,
24
20
  findElement,
25
- getKeyedPool,
26
- getSequentialPool,
27
- KeyedPool,
21
+ getKeyedRepeater,
22
+ getSequentialRepeater,
23
+ KeyedRepeater,
28
24
  mount,
29
25
  nestComponent,
30
26
  onEvent,
31
- stashMisc,
32
27
  saveRef,
33
- SequentialPool,
28
+ SequentialRepeater,
29
+ stashMisc,
30
+ watch,
34
31
  };
package/lib/initCalls.js CHANGED
@@ -1,106 +1,98 @@
1
1
  import { Component } from "./component";
2
- import { Lookup } from "./lookup";
3
2
  import { buildComponent, replaceNode } from "./utils";
4
- import { KeyedPool, SequentialPool } from "./pool";
3
+ import { KeyedRepeater, SequentialRepeater } from "./repeaters";
5
4
  const throwAway = document.createElement("template");
6
5
 
7
6
  /**
8
- * Create an element from html string
7
+ * Create an element from html string.
9
8
  */
10
9
  function makeEl(html) {
11
10
  throwAway.innerHTML = html;
12
11
  return throwAway.content.firstChild;
13
12
  }
14
13
 
15
- export const getProps = (component) => {
16
- return component.props;
17
- };
18
-
19
- export const findElement = (rootElement, path) => {
14
+ export function findElement(rootElement, path) {
20
15
  return path.reduce((acc, index) => acc.childNodes[index], rootElement);
21
- };
16
+ }
22
17
 
23
- export const nestComponent = (rootElement, path, cls, parent) => {
18
+ export function nestComponent(rootElement, path, cls) {
24
19
  const el = findElement(rootElement, path),
25
- child = buildComponent(cls, parent);
20
+ child = buildComponent(cls);
26
21
  replaceNode(el, child.el);
27
22
  return child;
28
- };
23
+ }
29
24
 
30
25
  /**
31
26
  * Saves a reference to element or nested component. Returns the element.
32
27
  */
33
- export const saveRef = (element, component, name) => {
28
+ export function saveRef(element, component, name) {
34
29
  component.ref[name] = element;
35
30
  return element;
36
- };
31
+ }
37
32
 
38
33
  /**
39
34
  * Stash something on the component. Returns the element.
40
35
  * The generated code is expected to keep track of the position.
41
36
  */
42
- export const stashMisc = (element, component, object) => {
37
+ export function stashMisc(element, component, object) {
43
38
  component._s.push(object);
44
39
  return element;
45
- };
40
+ }
46
41
 
47
- export const onEvent = (element, eventName, callback) => {
42
+ export function onEvent(element, eventName, callback) {
48
43
  element.addEventListener(eventName, callback);
49
44
  return element;
50
- };
45
+ }
51
46
 
52
- /**
53
- * Creates a pool.
54
- */
55
- export const getKeyedPool = (cls, keyFn) => {
56
- return new KeyedPool(cls, keyFn);
57
- };
47
+ export function getKeyedRepeater(cls, keyFn) {
48
+ return new KeyedRepeater(cls, keyFn);
49
+ }
58
50
 
59
- export const getSequentialPool = (cls) => {
60
- return new SequentialPool(cls);
61
- };
51
+ export function getSequentialRepeater(cls) {
52
+ return new SequentialRepeater(cls);
53
+ }
62
54
 
63
- export function defineComponent(
64
- html,
65
- watches,
66
- lookups,
67
- buildFunction,
68
- inheritFrom,
69
- prototypeExtras,
70
- ) {
71
- const Constructor = extendPrototype(
72
- inheritFrom || Component,
73
- prototypeExtras,
74
- );
75
- extendComponent(Constructor.prototype, html, watches, lookups, buildFunction);
76
- return Constructor;
55
+ export function extendComponent(base, componentDef) {
56
+ // This function call will have been replaced if 2nd arg is a valid component func.
57
+ // and therefor we would not receive it.
58
+ if (componentDef)
59
+ throw new Error("2nd arg to extendComponent must be a JSX arrow function");
60
+ return _createConstructor(base);
77
61
  }
78
62
 
79
- export function extendComponent(
80
- prototype,
63
+ export function defineComponent(
81
64
  html,
82
65
  watches,
83
- lookups,
66
+ queries,
84
67
  buildFunction,
68
+ inheritFrom
85
69
  ) {
70
+ const ComponentDefinition = _createConstructor(inheritFrom || Component);
71
+ const prototype = ComponentDefinition.prototype;
86
72
  //Ensure these do not clash with fields on the component itself.
87
73
  prototype._w = watches;
88
- prototype._l = new Lookup(lookups);
74
+ prototype._q = queries;
89
75
  prototype._b = buildFunction;
90
76
  prototype._n = makeEl(html);
77
+ return ComponentDefinition;
91
78
  }
92
79
 
93
- export function extendPrototype(base, prototypeExtras) {
94
- const Constructor = function (parent) {
95
- base.call(this, parent);
80
+ function _createConstructor(base) {
81
+ const ComponentDefinition = function () {
82
+ base.call(this);
83
+ };
84
+ ComponentDefinition.stubs = {};
85
+ Object.assign(ComponentDefinition.stubs, base.stubs);
86
+ // This is a helper function for the user.
87
+ ComponentDefinition.methods = function (obj) {
88
+ Object.assign(ComponentDefinition.prototype, obj);
96
89
  };
97
- Constructor.prototype = Object.create(base && base.prototype, {
90
+ ComponentDefinition.prototype = Object.create(base && base.prototype, {
98
91
  constructor: {
99
- value: Constructor,
92
+ value: ComponentDefinition,
100
93
  writable: true,
101
94
  configurable: true,
102
95
  },
103
96
  });
104
- Object.assign(Constructor.prototype, prototypeExtras);
105
- return Constructor;
97
+ return ComponentDefinition;
106
98
  }
@@ -1,19 +1,19 @@
1
- import { createComponent } from "./utils";
1
+ import { buildComponent } from "./utils";
2
2
 
3
3
  /*
4
4
  * Gets a component from the pool.
5
5
  */
6
- const getComponent = (pool, componentClass, key, item, parent) => {
6
+ function getComponent(pool, componentDefinition, ctrl, key, props) {
7
7
  let component;
8
8
  if (pool.hasOwnProperty(key)) {
9
9
  component = pool[key];
10
- component.render(item);
11
10
  } else {
12
- component = createComponent(componentClass, parent, item);
11
+ component = buildComponent(componentDefinition);
13
12
  pool[key] = component;
14
13
  }
14
+ component.render(props, ctrl);
15
15
  return component;
16
- };
16
+ }
17
17
 
18
18
  /**
19
19
  * Trims the unwanted child elements from the end.
@@ -44,29 +44,27 @@ function pull(arr, item, to) {
44
44
  }
45
45
 
46
46
  /**
47
- * Pools same type components, retrieving by key.
48
- * Must not be shared.
47
+ * Repeats nested components, reusing items based on key.
49
48
  *
50
- * @param {class} componentClass - The class of Component to create.
51
- * @param {function} keyFn - A function which obtains the key to pool by
49
+ * @param {function} componentDefinition - The ComponentDefinition to create.
50
+ * @param {function} keyFn - A function which obtains the key.
52
51
  */
53
- export function KeyedPool(componentClass, keyFn) {
54
- this._v = componentClass;
55
- this._f = keyFn;
56
- this._k = []; // keys
57
- this._p = {}; // pool of component instances
52
+ export function KeyedRepeater(componentDefinition, keyFn) {
53
+ this.def = componentDefinition;
54
+ this.keyFn = keyFn;
55
+ this.keys = []; // keys
56
+ this.pool = {}; // pool of component instances
58
57
  }
59
- const proto = KeyedPool.prototype;
58
+ const proto = KeyedRepeater.prototype;
60
59
 
61
60
  /**
62
61
  * Retrieves a single component. Though not used in wallace itself, it may
63
62
  * be used elsewhere, such as in the router.
64
63
  *
65
64
  * @param {Object} item - The item which will be passed as props.
66
- * @param {Component} parent - The parent component.
67
65
  */
68
- proto.getOne = function (item, parent) {
69
- return getComponent(this._p, this._v, this._f(item), item, parent);
66
+ proto.getOne = function (item, ctrl) {
67
+ return getComponent(this.pool, this.def, ctrl, this.keyFn(item), item);
70
68
  };
71
69
 
72
70
  /**
@@ -75,17 +73,16 @@ proto.getOne = function (item, parent) {
75
73
  *
76
74
  * @param {DOMElement} e - The DOM element to patch.
77
75
  * @param {Array} items - Array of items which will be passed as props.
78
- * @param {Component} parent - The parent component.
79
76
  */
80
- proto.patch = function (e, items, parent) {
77
+ proto.patch = function (e, items, ctrl) {
81
78
  // Attempt to speed up by reducing lookups. Does this even do anything?
82
79
  // Does webpack undo this/do it for for me? Does the engine?
83
- const pool = this._p;
84
- const componentClass = this._v;
85
- const keyFn = this._f;
80
+ const pool = this.pool;
81
+ const componentDefinition = this.def;
82
+ const keyFn = this.keyFn;
86
83
  const childNodes = e.childNodes;
87
84
  const itemsLength = items.length;
88
- const oldKeySequence = this._k;
85
+ const oldKeySequence = this.keys;
89
86
  const newKeys = [];
90
87
  let item,
91
88
  key,
@@ -94,7 +91,7 @@ proto.patch = function (e, items, parent) {
94
91
  for (let i = 0; i < itemsLength; i++) {
95
92
  item = items[i];
96
93
  key = keyFn(item);
97
- component = getComponent(pool, componentClass, key, item, parent);
94
+ component = getComponent(pool, componentDefinition, ctrl, key, item);
98
95
  newKeys.push(key);
99
96
  if (i > childElementCount) {
100
97
  e.appendChild(component.el);
@@ -103,19 +100,19 @@ proto.patch = function (e, items, parent) {
103
100
  pull(oldKeySequence, key, i);
104
101
  }
105
102
  }
106
- this._k = newKeys;
103
+ this.keys = newKeys;
107
104
  trimChildren(e, childNodes, itemsLength);
108
105
  };
109
106
 
110
107
  /**
111
- * Pools same type components, retrieving by sequence.
108
+ * Repeats nested components, yielding from its pool sequentially.
112
109
  *
113
- * @param {class} componentClass - The class of Component to create.
110
+ * @param {componentDefinition} componentDefinition - The class ComponentDefinition to create.
114
111
  */
115
- export function SequentialPool(componentClass) {
116
- this._v = componentClass;
117
- this._p = []; // pool of component instances
118
- this._c = 0; // Child element count
112
+ export function SequentialRepeater(componentDefinition) {
113
+ this.def = componentDefinition;
114
+ this.pool = []; // pool of component instances
115
+ this.count = 0; // Child element count
119
116
  }
120
117
 
121
118
  /**
@@ -124,32 +121,30 @@ export function SequentialPool(componentClass) {
124
121
  *
125
122
  * @param {DOMElement} e - The DOM element to patch.
126
123
  * @param {Array} items - Array of items which will be passed as props.
127
- * @param {Component} parent - The parent component.
124
+ * @param {any} ctrl - The parent item's controller.
128
125
  */
129
- SequentialPool.prototype.patch = function (e, items, parent) {
130
- const pool = this._p;
131
- const componentClass = this._v;
126
+ SequentialRepeater.prototype.patch = function (e, items, ctrl) {
127
+ const pool = this.pool;
128
+ const componentDefinition = this.def;
132
129
  const childNodes = e.childNodes;
133
130
  const itemsLength = items.length;
134
- let item,
135
- component,
131
+ let component,
136
132
  poolCount = pool.length,
137
- childElementCount = this._c;
133
+ childElementCount = this.count;
138
134
 
139
135
  for (let i = 0; i < itemsLength; i++) {
140
- item = items[i];
141
136
  if (i < poolCount) {
142
137
  component = pool[i];
143
- component.render(item);
144
138
  } else {
145
- component = createComponent(componentClass, parent, item);
139
+ component = buildComponent(componentDefinition);
146
140
  pool.push(component);
147
141
  poolCount++;
148
142
  }
143
+ component.render(items[i], ctrl);
149
144
  if (i >= childElementCount) {
150
145
  e.appendChild(component.el);
151
146
  }
152
147
  }
153
- this._c = itemsLength;
148
+ this.count = itemsLength;
154
149
  trimChildren(e, childNodes, itemsLength);
155
150
  };