UNPKG

twoway

Version:

Simple Zero dependency 2way databinding library

524 lines (470 loc) 16.1 kB
var twoway = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 1); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; class AbstractInput { constructor(element, store) { this.element = element; this.model = element.getAttribute("data-model"); this.propertyName = element.getAttribute("data-model"); this.value = null; this.store = store; } /** * Trigger the update method. Only triggered if there is a difference in the values * @param value New value */ update(value) { if (this.value !== value) { this.value = value; this.store.store[this.propertyName] = this.value; this.emitUpdateToElement(); } } /** * Emitting update event to the DOM element * * @memberof AbstractInput */ emitUpdateToElement() { const event = new CustomEvent("update", { detail: this.value }); this.element.dispatchEvent(event); } } /* harmony export (immutable) */ __webpack_exports__["a"] = AbstractInput; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var _Core = __webpack_require__(2); var _Core2 = _interopRequireDefault(_Core); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } (function () { if (true) { if (typeof module !== "undefined" && module.exports) { exports = module.exports = create; } exports.twoway = create; } else { root.twoway = create; } /** * create new instance * * @param {String} rootId * @param {Object} state * @returns */ function create(rootId, state) { return new _Core2.default(rootId, state).getStore(); } })(); /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Element_View_index__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Store_index__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Element_Input_Input_index__ = __webpack_require__(6); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Element_Input_Checkbox_index__ = __webpack_require__(7); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Element_Input_Radiobox_index__ = __webpack_require__(9); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Element_Input_Select_index__ = __webpack_require__(8); class TwoWay { constructor(rootElementId, store) { this.rootElementId = rootElementId; this.store = new __WEBPACK_IMPORTED_MODULE_1__Store_index__["a" /* default */](store); this.views = []; this.init(); } /** * Initialize all elements * * @memberof TwoWay */ init() { this.initViews(); //this.initCheckbox(); this.initInput(`${this.rootElementId} input[data-model]:not([type='radio']):not([type='checkbox'])`, __WEBPACK_IMPORTED_MODULE_2__Element_Input_Input_index__["a" /* default */]); this.initInput(`${this.rootElementId} textarea[data-model]`, __WEBPACK_IMPORTED_MODULE_2__Element_Input_Input_index__["a" /* default */]); this.initInput(`${this.rootElementId} select[data-model]`, __WEBPACK_IMPORTED_MODULE_5__Element_Input_Select_index__["a" /* default */]); this.initInput(`${this.rootElementId} input[type='radio'][data-model]`, __WEBPACK_IMPORTED_MODULE_4__Element_Input_Radiobox_index__["a" /* default */]); this.initInput(`${this.rootElementId} input[type='checkbox'][data-model]`, __WEBPACK_IMPORTED_MODULE_3__Element_Input_Checkbox_index__["a" /* default */]); } /** * * @return {Object} */ getStore() { return this.store.store; } /** * Initialize all views * * @memberof TwoWay */ initViews() { const elements = document.querySelectorAll(`${this.rootElementId} [data-property]`); for (let i = 0; i < elements.length; i++) { const item = elements[i]; this.views.push(new __WEBPACK_IMPORTED_MODULE_0__Element_View_index__["a" /* default */](item, this.store)); } } /** * * @param {string} selector * @param AbstractInputClass */ initInput(selector, AbstractInputClass) { const elements = document.querySelectorAll(selector); for (let i = 0; i < elements.length; i++) { const item = elements[i]; this.views.push(new AbstractInputClass(item, this.store)); } } } /* harmony export (immutable) */ __webpack_exports__["default"] = TwoWay; /***/ }), /* 3 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; class View { constructor(element, store) { this.element = element; this.value = null; this.store = store; this.model = element.getAttribute("data-property"); if (!this.model) { throw new Error("No data-property found on element!"); } this.store.registerObserver(this.model, this); } update(value) { if (this.value !== value) { this.value = value; if (typeof this.value === 'object') { this.value = JSON.stringify(value); } this.element.innerHTML = this.value; } } } /* harmony export (immutable) */ __webpack_exports__["a"] = View; /***/ }), /* 4 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__helpers__ = __webpack_require__(5); class Store { constructor(initialStore) { this.scopedSubscribers = {}; this.store = this.observe(initialStore, (property, value) => { this.notifyObservers(property); }); } /** * Observe property for changes * * @param o * @param {Function} callback * @return {object} */ observe(o, callback) { return Object(__WEBPACK_IMPORTED_MODULE_0__helpers__["a" /* default */])("", o, callback); } /** * Notify all observers of updated property * * @param {string} property * @param value */ notifyObservers(property) { let path = property.split('.'); let propPath = ""; let storeVal = this.store; for (let i = 0; i < path.length; i++) { if (propPath) { propPath += '.'; } storeVal = storeVal[path[i]]; propPath = `${propPath}${path[i]}`; this._notifyProperty(propPath, storeVal); } } /** * * @param {string} property * @param value * @private */ _notifyProperty(property, value) { if (!this.scopedSubscribers[property]) { return; } const observers = this.scopedSubscribers[property].observers; for (let i = 0; i < observers.length; i++) { const observer = observers[i]; if (observer.value !== value) { observer.update(value); } } } /** * Add new observer * * @param {string} prop * @param {View} view * @memberof Store */ registerObserver(prop, view) { if (!this.scopedSubscribers[prop]) { this.scopedSubscribers[prop] = { observers: [] }; } this.scopedSubscribers[prop].observers.push(view); this.notifyObservers(prop); } } /* harmony export (immutable) */ __webpack_exports__["a"] = Store; /***/ }), /* 5 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = buildProxy; function _populate(target, path, value) { if (path.length > 0) { let sub = path.shift(); target[sub] = _populate(target[sub], path, value); } else { return value; } return target; } function buildProxy(prefix, o, callback) { return new Proxy(o, { set(target, property, value) { // same as above, but add prefix const path = property.split('.'); target = _populate(target, path, value); callback(`${prefix}${property}`, value); return true; }, get(target, property) { // return a new proxy if possible, add to prefix const out = target[property]; if (out instanceof Object) { return buildProxy(`${prefix}${property}.`, out, callback); } return out; } }); } /***/ }), /* 6 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__AbstractInput__ = __webpack_require__(0); class Input extends __WEBPACK_IMPORTED_MODULE_0__AbstractInput__["a" /* default */] { constructor(element, store) { super(element, store); this.element.addEventListener("change", e => { this.update(e.target.value); }); this.element.addEventListener("keyup", e => { this.update(e.target.value); }); this.store.registerObserver(this.propertyName, this); } update(value) { super.update(value); if (this.element.value !== value) { this.element.value = value; } } } /* harmony export (immutable) */ __webpack_exports__["a"] = Input; /***/ }), /* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__AbstractInput__ = __webpack_require__(0); class Checkbox extends __WEBPACK_IMPORTED_MODULE_0__AbstractInput__["a" /* default */] { constructor(element, store) { super(element, store); this.propertyName = `${this.model}.${this.element.value}`; this.element.addEventListener("change", e => { this.update(e.target.checked); }); this.store.registerObserver(this.propertyName, this); } update(value) { super.update(value); this.element.checked = value; } } /* harmony export (immutable) */ __webpack_exports__["a"] = Checkbox; /***/ }), /* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; class Select { constructor(element, store) { this.isMulti = false; this.element = element; this.model = element.getAttribute("data-model"); this.propertyName = element.getAttribute("data-model"); this.value = null; this.store = store; this.isMulti = this.element.getAttribute("multiple") !== null; this.element.addEventListener("change", e => { this.onChange(e.target.value); }); this.store.registerObserver(this.propertyName, this); let selected = this.getSelectedOptions(); if (this.isMulti) { this.value = selected; } else { this.value = selected.shift(); this.onChange(this.value); } } getSelectedOptions() { let result = []; const options = this.element && this.element.options; for (var i = 0, iLen = options.length; i < iLen; i++) { let opt = options[i]; if (opt.selected) { result.push(opt.value || opt.text); } } return result; } onChange(value) { if (this.isMulti) { this.value = this.getSelectedOptions(); } else if (this.store.store[this.propertyName] !== value) { this.value = value; } this.store.store[this.propertyName] = this.value; this.emitUpdateToElement(); } /** * Trigger the update method. Only triggered if there is a difference in the values * @param value New value */ update(value) { if (this.isMulti) { const options = this.element && this.element.options; for (var i = 0, iLen = options.length; i < iLen; i++) { let opt = options[i]; opt.selected = value.indexOf(opt.value) !== -1; } } else { const options = this.element && this.element.options; for (var i = 0, iLen = options.length; i < iLen; i++) { let opt = options[i]; opt.selected = value === opt.value; } } } /** * Emitting update event to the DOM element * * @memberof AbstractInput */ emitUpdateToElement() { const event = new CustomEvent("update", { detail: this.value }); this.element.dispatchEvent(event); } } /* harmony export (immutable) */ __webpack_exports__["a"] = Select; /***/ }), /* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__AbstractInput__ = __webpack_require__(0); class Radiobox extends __WEBPACK_IMPORTED_MODULE_0__AbstractInput__["a" /* default */] { constructor(element, store) { super(element, store); this.element.addEventListener("change", e => { this.update(e.target.value); }); this.store.registerObserver(this.propertyName, this); } update(value) { super.update(value); this.element.checked = this.element.value === value; } } /* harmony export (immutable) */ __webpack_exports__["a"] = Radiobox; /***/ }) /******/ ]);