UNPKG

appblocks

Version:

A lightweight javascript library for building micro apps for the front-end.

190 lines (148 loc) 5.77 kB
'use strict'; import {Idiomorph} from 'idiomorph/dist/idiomorph.esm'; import {updateTextNodePlaceholders} from './placeholders'; import {directives} from './directives'; import {filters} from './filters'; import {processNode} from './processing'; import {helpers} from './utils'; import {fetchRequest, axiosRequest} from './requests'; import { logError } from './logger'; const defaultRequestHeaders = { } export function AppBlock(config) { // Sets or Updates the data and then calls render() this.setData = function(newData, replaceData = false) { if (replaceData) { this.data = newData; } else { Object.assign(this.data, newData); } this.render(); } // Resets to the default state. Handy before making a request. this.resetState = function() { this.state.loading = false; this.state.error = false; this.state.success = false; } // Requests this.axiosRequest = (options, callbacks, delay) => axiosRequest(this, options, callbacks, delay); this.fetchRequest = (url, options, callbacks, delay) => fetchRequest(this, url, options, callbacks, delay); // Render ============================================================================================================ // This is the heart of an AppBlock. This is where all placeholders and directives get evaluated based on our // data, and content gets updated. this.prepareTmpDom = function() { const comp = this; let tmpDOM = comp.template.cloneNode(true); processNode(comp, tmpDOM); updateTextNodePlaceholders(comp, tmpDOM); return tmpDOM; } this.render = function(callback) { const comp = this; if (comp.methods.beforeRender instanceof Function) comp.methods.beforeRender(comp); let tmpDOM = this.prepareTmpDom(); if (comp.renderEngine === 'Idiomorph') { comp.idiomorphRender(tmpDOM); } else if (comp.renderEngine === 'plain') { comp.plainRender(tmpDOM); } else { logError(comp, `${comp.renderEngine} renderEngine does not exist.`); } if (comp.methods.afterRender instanceof Function) comp.methods.afterRender(comp); if (callback instanceof Function) callback(); } // Render engines this.plainRender = function(tmpDOM) { this.el.innerHTML = ''; this.el.appendChild(tmpDOM); } this.idiomorphRender = function(tmpDOM) { Idiomorph.morph(this.el, tmpDOM, {morphStyle:'innerHTML'}); } // Initialization ==================================================================================================== this.Init = function() { const comp = this; if (config.name) { comp.name = config.name; } else { comp.name = "AppBlock"; } // Initialize all the properties and update them from the config if they are included, or exit if no // config is provided. if (config !== undefined) { if (config.el === undefined) { logError(comp, "el is empty. Please assign a DOM element to el."); return; } if (config.el === null) { logError(comp, "The element you assigned to el is not present."); return; } comp.el = config.el; comp.renderEngine = config.renderEngine ? config.renderEngine : "Idiomorph"; // Get or create a document fragment with all the app's contents and pass it to the template. if (config.template) { comp.template = config.template.content; } else { comp.template = document.createDocumentFragment(); while (comp.el.firstChild) { comp.template.appendChild(comp.el.firstChild); } } comp.state = { loading: false, error: false, success: false }; comp.data = {}; if (config.data instanceof Object) comp.data = config.data; // A set of helper functions. comp.utils = helpers; comp.utils['comp'] = comp; comp.methods = { Parent: comp, isLoading(thisApp) { return thisApp.state.loading; }, isSuccessful(thisApp) { return thisApp.state.success; }, hasError(thisApp) { return thisApp.state.error; }, beforeRender(thisApp) {}, afterRender(thisApp) {} }; if (config.methods instanceof Object) Object.assign(comp.methods, config.methods); comp.directives = directives; if (config.directives instanceof Object) Object.assign(comp.directives, config.directives); comp.filters = filters; if (config.filters instanceof Object) Object.assign(comp.filters, config.filters); // Event handling ------------------------------------------------------------------------------------------------ comp.events = {}; if (config.events instanceof Object) { Object.assign(comp.events, config.events) // Add event listeners to :el for each event for (const ev in comp.events) { // Events are in this form (event element) so split at space to get the eventName and the element to attach // the event on. const eParts = ev.split(' '); const eventName = eParts[0]; const eventElement = eParts[1]; comp.el.addEventListener(eventName, function(e) { comp.el.querySelectorAll(eventElement).forEach(el => { if (e.srcElement === el) comp.events[ev](e); }); }); } } comp.events['Parent'] = comp; } else { return false; } comp.render(); return comp; } return this.Init(); }