mirror of
https://github.com/JeremyLikness/vanillajs-deck
synced 2024-12-04 19:27:37 +00:00
Refactor data-binding to own class
This commit is contained in:
parent
0cab33efe5
commit
47a3dc8ba5
50
js/dataBinding.js
Normal file
50
js/dataBinding.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
export class DataBinding {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple evaluation
|
||||||
|
* @param {string} js The JavaScript to evaluate
|
||||||
|
*/
|
||||||
|
execute(js) {
|
||||||
|
return eval(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates JavaScript with a constrained context (scope)
|
||||||
|
* @param {string} src The JavaScript to evaluate
|
||||||
|
* @param {object} context The context (data) to evaluate with
|
||||||
|
* @returns {object} The result of the evaluation
|
||||||
|
*/
|
||||||
|
executeInContext(src, context) {
|
||||||
|
return this.execute.call(context, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for "repeat" attribute to data-bind lists
|
||||||
|
* @param {HTMLElement} elem The parent element to search
|
||||||
|
* @param {object} context The context to use for binding
|
||||||
|
*/
|
||||||
|
bindLists(elem, context) {
|
||||||
|
const listBinding = elem.querySelectorAll("[repeat]");
|
||||||
|
listBinding.forEach(elem => {
|
||||||
|
const parent = elem.parentElement;
|
||||||
|
const expression = elem.getAttribute("repeat");
|
||||||
|
elem.removeAttribute("repeat");
|
||||||
|
const template = elem.outerHTML;
|
||||||
|
parent.removeChild(elem);
|
||||||
|
context[expression].forEach(item => {
|
||||||
|
let newTemplate = `${template}`;
|
||||||
|
const matches = newTemplate.match(/\{\{([^\}]*?)\}\}/g);
|
||||||
|
if (matches) {
|
||||||
|
matches.forEach(match => {
|
||||||
|
match = match.replace("{{", "").replace("}}", "");
|
||||||
|
const value = this.executeInContext(`this.${match}`, {item});
|
||||||
|
newTemplate = newTemplate.replace(`{{${match}}}`, value);
|
||||||
|
});
|
||||||
|
parent.innerHTML += newTemplate;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
42
js/slide.js
42
js/slide.js
@ -1,4 +1,7 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
import {DataBinding} from "./dataBinding.js"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a slide
|
* Represents a slide
|
||||||
* */
|
* */
|
||||||
@ -19,6 +22,11 @@ export class Slide {
|
|||||||
* @type {object}
|
* @type {object}
|
||||||
*/
|
*/
|
||||||
this._context = {};
|
this._context = {};
|
||||||
|
/**
|
||||||
|
* Data binding helper
|
||||||
|
* @type {DataBinding}
|
||||||
|
*/
|
||||||
|
this._dataBinding = new DataBinding();
|
||||||
/**
|
/**
|
||||||
* The HTML DOM hosting the slide contents
|
* The HTML DOM hosting the slide contents
|
||||||
* @type {HTMLDivElement}
|
* @type {HTMLDivElement}
|
||||||
@ -57,41 +65,11 @@ export class Slide {
|
|||||||
// execute any scripts
|
// execute any scripts
|
||||||
const script = this._html.querySelector("script");
|
const script = this._html.querySelector("script");
|
||||||
if (script) {
|
if (script) {
|
||||||
(function (/** @type {string} */src) {
|
this._dataBinding.executeInContext(script.innerText, this._context);
|
||||||
return eval(src)
|
this._dataBinding.bindLists(this._html, this._context);
|
||||||
}).call(this._context, script.innerText);
|
|
||||||
this.dataBind();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Scans for data-binding and applies the bindings
|
|
||||||
*/
|
|
||||||
dataBind() {
|
|
||||||
const listBinding = this._html.querySelectorAll("[repeat]");
|
|
||||||
listBinding.forEach(elem => {
|
|
||||||
const parent = elem.parentElement;
|
|
||||||
const expression = elem.getAttribute("repeat");
|
|
||||||
elem.removeAttribute("repeat");
|
|
||||||
const template = elem.outerHTML;
|
|
||||||
parent.removeChild(elem);
|
|
||||||
this._context[expression].forEach(item => {
|
|
||||||
let newTemplate = `${template}`;
|
|
||||||
const matches = newTemplate.match(/\{\{([^\}]*?)\}\}/g);
|
|
||||||
if (matches) {
|
|
||||||
matches.forEach(match => {
|
|
||||||
match = match.replace("{{", "").replace("}}", "");
|
|
||||||
const value = (function (/** @type {string} */src) {
|
|
||||||
return eval(src)
|
|
||||||
}).call({ item }, match);
|
|
||||||
newTemplate = newTemplate.replace(`{{${match}}}`, value);
|
|
||||||
});
|
|
||||||
parent.innerHTML += newTemplate;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The slide transition
|
* The slide transition
|
||||||
* @returns {string} The transition name
|
* @returns {string} The transition name
|
||||||
|
Loading…
Reference in New Issue
Block a user