Skip to content

Commit b8ca80e

Browse files
committed
Change logic for data flow.
1 parent dbaa79d commit b8ca80e

6 files changed

Lines changed: 202 additions & 86 deletions

File tree

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
11
# DataFlowJS
22
DataFlow JS data binding JS library
3+
4+
# Usage
5+
6+
```html
7+
8+
<span class="my-element"></span>
9+
<span class="my-element"></span>
10+
<span id="nested"></span>
11+
12+
<script src="data-flow.js"></script>
13+
<script>
14+
var flow = new DataFlow({
15+
myBoundData: 'my data',
16+
nested: {
17+
data: {
18+
works: 'too'
19+
}
20+
}
21+
});
22+
23+
// Bind all changes to myBoundData to all elements of class my-element
24+
flow.bind({to: '.my-element', path: 'myBoundData'});
25+
flow.bind({to: '#nested', as: 'html', path: 'nested.data.works'});
26+
27+
// All elements of .my-element are not showing my another data
28+
flow.set("myBoundData", "my another data");
29+
30+
// span with id nested now has bold text also works as contents.
31+
flow.set('nested.data.works', "<strong>also works</strong>");
32+
</script>
33+
```
34+
35+
# Building
36+
37+
Run `npm install` then run `npm run build`.

src/bound-element.js

Lines changed: 77 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,87 +2,89 @@ import inspect from './inspect';
22

33
var noop = function() {};
44

5-
function BoundElement(config) {
6-
this.element = inspect.isString(config.element) ? document.querySelector(config.element) : config.element;
7-
this.dataSource = config.dataSource;
8-
this.path = config.path;
9-
this.to = config.to || 'html';
10-
this._callback = config.callback || noop;
11-
this._bound = true;
12-
this._boundHandler = this.update.bind(this);
13-
this.dataSource.bindHandler(this._boundHandler);
14-
15-
this.onBind = config.onBind || noop;
16-
this.onUpdate = config.onUpdate || noop;
17-
this.onUnbind = config.onUnbind || noop;
18-
19-
this.onBind.call(this.element);
20-
21-
if (!config.disableUpdate) {
22-
this.update();
5+
export default function initModule(renderer, dataSource) {
6+
function BoundElement(config) {
7+
this.element = inspect.isString(config.to) ? document.querySelectorAll(config.to) : config.to;
8+
this.multiple = config.multiple || (this.element instanceof NodeList && this.element.length > 1);
9+
10+
if (!this.multiple) {
11+
this.element = this.element[0];
12+
}
13+
14+
this.dataSource = config.dataSource;
15+
this.path = config.path;
16+
this.as = config.as || 'text';
17+
this._bound = true;
18+
this._boundHandler = this.update.bind(this);
19+
this.dataSource.bindHandler(this._boundHandler);
20+
21+
this.onBind = config.onBind || noop;
22+
this.onUpdate = config.onUpdate || noop;
23+
this.onUnbind = config.onUnbind || noop;
24+
this.onAfterRender = config.onAfterRender || noop;
25+
26+
this.onBind.call(this.element);
27+
28+
if (!config.disableUpdate) {
29+
this.update();
30+
}
31+
}
32+
33+
BoundElement.prototype.getValue = getValue;
34+
BoundElement.prototype.setValue = setValue;
35+
BoundElement.prototype.run = run;
36+
BoundElement.prototype.update = update;
37+
BoundElement.prototype.unbind = unbind;
38+
39+
return function bind(config) {
40+
if (Array.isArray(config)) {
41+
return bindArray(config);
42+
}
43+
44+
return bindSingle(config);
45+
};
46+
47+
function bindArray(items) {
48+
var results = [];
49+
for(var i = 0; i < config.length; i++) {
50+
results.push(bindSingle(config[i]));
2351
}
24-
}
2552

26-
BoundElement.prototype.get = getValue;
27-
BoundElement.prototype.set = setValue;
28-
BoundElement.prototype.run = run;
29-
BoundElement.prototype.update = update;
30-
BoundElement.prototype.unbind = unbind;
31-
32-
export default function bind(config, dataSource) {
33-
if (Array.isArray(config)) {
34-
var results = [];
35-
for(var i = 0; i < config.length; i++) {
36-
var item = config[i];
37-
if (!item.dataSource) {
38-
item.dataSource = dataSource;
39-
}
40-
41-
results.push(new BoundElement(item));
42-
}
43-
44-
return results;
45-
}
53+
return results;
54+
}
4655

56+
function bindSingle(config) {
4757
if (!config.dataSource) {
4858
config.dataSource = dataSource;
4959
}
5060

5161
return new BoundElement(config);
52-
};
53-
54-
function getValue(defaultValue) {
55-
return this.dataSource.get(this.path, defaultValue);
56-
}
57-
58-
function setValue(value) {
59-
if (!this._bound) {
60-
throw new Error('Cannot call setValue of unbound instance.');
61-
}
62-
this.dataSource.set(this.path, value);
63-
}
64-
65-
function update() {
66-
var value = this.get();
67-
68-
if (this.to === 'html') {
69-
this.element.innerHTML = String(value);
70-
} else if (this.to === 'text') {
71-
this.element.innerText = String(value);
72-
} else if (this.to === 'callback') {
73-
this._callback.call(this.element, value);
74-
}
75-
76-
this.onUpdate.call(this.element, value);
77-
}
78-
79-
function unbind() {
80-
this._bound = false;
81-
this.dataSource.unbindHandler(this._boundHandler);
82-
this.onUnbind.call(this.element, value);
83-
}
84-
85-
function run(callback) {
86-
callback.call(this, this.getValue());
87-
this.update();
62+
}
63+
64+
function getValue(defaultValue) {
65+
return this.dataSource.get(this.path, defaultValue);
66+
}
67+
68+
function setValue(value) {
69+
if (!this._bound) {
70+
throw new Error('Cannot call setValue of unbound instance.');
71+
}
72+
this.dataSource.set(this.path, value);
73+
}
74+
75+
function update() {
76+
this.onUpdate.call(this.element, this.getValue());
77+
return renderer.render(this);
78+
}
79+
80+
function unbind() {
81+
this._bound = false;
82+
this.dataSource.unbindHandler(this._boundHandler);
83+
this.onUnbind.call(this.element, value);
84+
}
85+
86+
function run(callback) {
87+
callback.call(this, this.getValue());
88+
this.update();
89+
}
8890
}

src/data-source.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import inspect from './inspect';
2-
import findByPath from './path';
2+
import findByPath from './find-by-path';
33

4-
export default function toDataSource(data) {
5-
return new DataSource(data);
6-
}
4+
export default DataSource;
75

86
function DataSource(data) {
97
this._data = data;

src/path.js renamed to src/find-by-path.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import inspect from './inspect';
2-
export default findByPath;
32

4-
function findByPath(object, path, createPathIfEmpty) {
3+
export default function findByPath(object, path, createPathIfEmpty) {
54
if (!path) {
65
return {
76
result: object,

src/index.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
import bind from './bound-element';
2-
import toDataSource from './data-source';
1+
import initBoundElementModule from './bound-element';
2+
import DataSource from './data-source';
3+
import Renderer from './renderer';
34

4-
window.DataFlow = {
5-
bind: bind,
6-
toDataSource: toDataSource
5+
window.DataFlow = function DataFlow(dataSource) {
6+
var renderer = new Renderer();
7+
var dataSource = dataSource instanceof DataSource ? dataSource : new DataSource(dataSource);
8+
9+
dataSource.bind = initBoundElementModule(renderer, dataSource);
10+
dataSource.renderer = renderer;
11+
12+
return dataSource;
713
};
14+
15+
window.DataFlow.initBoundElementModule = initBoundElementModule;
16+
window.DataFlow.DataSource = DataSource;
17+
window.DataFlow.Renderer = Renderer;

src/renderer.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
var staticRenderers = {};
2+
3+
export default function Renderer() {
4+
this.renderers = getInitialRenderers();
5+
}
6+
7+
Renderer.prototype.render = render;
8+
Renderer.prototype.set = setRenderer;
9+
Renderer.prototype.runOnBoundElement = runOnBoundElement;
10+
11+
Renderer.setStaticRenderer = function(name, callback) {
12+
staticRenderers[name] = callback;
13+
};
14+
15+
function render(boundElement) {
16+
var rendererName = boundElement.as;
17+
18+
if (typeof rendererName === "function") {
19+
rendererName(boundElement);
20+
boundElement.onAfterRender();
21+
return;
22+
}
23+
24+
if (!(rendererName in this.renderers)) {
25+
throw new Error('Unknown renderer: ' + rendererName);
26+
}
27+
28+
this.renderers[rendererName](boundElement);
29+
boundElement.onAfterRender();
30+
}
31+
32+
function setRenderer(name, callback) {
33+
tihs.renderers[name] = callback;
34+
}
35+
36+
function getDefaultRenderers() {
37+
return {
38+
html: function(boundElement, forElement) {
39+
console.log(boundElement, forElement);
40+
forElement.innerHTML = String(boundElement.getValue());
41+
},
42+
text: function(boundElement, forElement) {
43+
forElement.innerText = String(boundElement.getValue());
44+
}
45+
};
46+
}
47+
48+
function runOnBoundElement(callback, boundElement) {
49+
if (boundElement.multiple) {
50+
for(var i = 0; i < boundElement.element.length; i++) {
51+
callback(boundElement, boundElement.element[i]);
52+
}
53+
} else {
54+
callback(boundElement, boundElement.element);
55+
}
56+
}
57+
58+
function getInitialRenderers() {
59+
var renderers = getDefaultRenderers();
60+
61+
for(var name in staticRenderers) {
62+
if (staticRenderers.hasOwnProperty(name)) {
63+
renderers[name] = staticRenderers[name];
64+
}
65+
}
66+
67+
for(var name in renderers) {
68+
renderers[name] = runOnBoundElement.bind(this, renderers[name]);
69+
}
70+
71+
return renderers;
72+
}

0 commit comments

Comments
 (0)