UNPKG

generator-foo

Version:

Foo project scaffold generator based on generator-jam3

368 lines (336 loc) 9.36 kB
import Vue from "vue" import signals from "signals" import store from "app/store" import throttle from "lodash/throttle" import {mainLoaderDisappear} from "app/transitions/loader" import preloader from 'preloader' import Analytics from "foo/utils/Analytics" import Requester from "foo/net/Requester" import Facebook from "foo/net/api/Facebook" import Google from "foo/net/api/Google" import Xeerpa from "foo/net/api/Xeerpa" import {LOADING, PROGRESS} from "app/store/modules/loader" import {LOCALE_CHANGED, LOCALE_LOADING, STARTED} from "app/store/modules/app" export default class AbstractApp { /** * @module foo * @namespace core * @class AbstractApp * @author Mendieta * @constructor * @param {object} config App config object * @param {object} environment App environment object * @param {object} [data={}] App initial load data */ constructor(config, environment, data = {}) { /** * Signal dispatching on app animationFrame * @property rendered * @type {Signal} */ this.rendered = new signals.Signal(); /** * Signal dispatching on ap resize * @property resized * @type {Signal} */ this.resized = new signals.Signal(); /** * The app debug flasg * @property DEBUG * @type {boolean} */ this.DEBUG = environment.vars.debug; /** * The app config object * @property config * @type {Object} */ this.config = config; /** * The app analytics util * @property analytics * @type {Analytics} */ this.analytics = null; /** * App environment object * @property environment * @type {Object} */ this.environment = environment; /** * App initial load data * @default {} * @property data * @type {Object} */ this.data = data; /** * Defines if the App has started * @property started * @default false * @type {boolean} */ this.started = false; /** * The app window width * @property width * @type {Number} */ this.width = window.innerWidth; /** * The app window height * @property height * @type {Number} */ this.height = window.innerHeight; /** * The current locale * @default "es-MX" * @property locale * @type {string} */ this.locale = config.locale; /** * Loader * @property loader * @type {preloader} */ this.loader = preloader({ xhrImages: false, loadFullAudio: true, loadFullVideo: true }); this.setLocale = this.setLocale.bind(this); window.App = this; this._setupAnalytics(); } /** * Method called when the App will initialize, setup initial data at override * @method init * @override */ init() { if (this.DEBUG) this.startDebug(); this._addListeners(); this._initSDKs().then(() => { if (this.config.asset_loading) { Requester.getJSON("static/data/preload.json").then((response) => { this.loadAssets(response.body); }).then(undefined, (error) => { throw new Error("Unable to load preload.json file!"); }); } else { this.start(); } }); } /** * Method that init the Analytics helper * @protected * @override * @method _setupAnalytics * @returns {void} */ _setupAnalytics() { this.analytics = new Analytics("static/data/tracking.json", this.config.analytics, this._setupPolyglot()) } /** * Method that setups Polyglot, loads default locale * @private * @override * @method _setupPolyglot * @returns {void} */ _setupPolyglot() { /** * the current locale * @default "es-MX" * @type {Array} */ this.locales = []; window.locale = Vue.t; this.setLocale(this.locale); } /** * Method that loads the current locale and (re)renders the App * @private * @override * @method _loadLocale * @returns {void} */ _loadLocale() { Requester.getJSON(`static/data/locale/${this.locale}.json`) .then((response) => { this.locales.push(this.locale); Vue.locale(this.locale, response.body); Vue.config.lang = this.locale; store.commit(LOCALE_CHANGED, this.locale); if (!this.started) { this.init(); } }) .then(undefined, (error) => { console.error("Error: The provided locale was not found in the locales directory.", error); }) } /** * Method that set the current locale * @method setLocale * @param {string} locale The locale to set as current * @returns {void} */ setLocale(locale) { this.locale = locale; if (this.locales.includes(this.locale)) { Vue.config.lang = this.locale; store.commit(LOCALE_CHANGED, this.locale); } else { store.commit(LOCALE_LOADING); this._loadLocale(); } } /** * Method that init listeners depending on the App config * @private * @method _addListeners * @returns {void} */ _addListeners() { if (this.config.vars.resize) window.addEventListener("resize", throttle(this._onResizeHandler, 16)); if (this.config.vars.animate) this._animate(); } /** * Method that initialize SDKs and APIs depending on the App config * @private * @method _initSDKs * @returns {Promise} */ _initSDKs() { return new Promise((resolve, reject) => { const {apis} = this.config; let count = 0; let loaded = 0; if (apis.facebook) { count++; Facebook.setup().then(() => { defer(); }) } if (apis.google) { count++; Google.setup().then(() => { defer(); }) } if (apis.twitter) { //TODO: Setup twitter api } if (apis.xeerpa) { count++; Xeerpa.setup().then(() => { defer(); }) } let defer = () => { loaded++; if (loaded == count) { resolve(); } }; if (count == 0) resolve(); }); } /** * Window resize event handler * @param {Event} e The event object * @protected * @method _onResizeHandler * @returns {void} */ _onResizeHandler(e) { this.width = window.innerWidth; this.height = window.innerHeight; App.resized.dispatch({width: this.width, height: this.height}); } /** * Method that loops animation frameworks * @private * @method _animate * @returns {void} */ _animate() { requestAnimationFrame(() => { App.rendered.dispatch(); this._animate(); }); } /** * Method that starts debug mode, depending on App config and environment * @protected * @override * @method startDebug * @returns {void} */ startDebug() { } /** * Method to load all assets * @private * @param assets * @method loadAssets * @return {void} */ loadAssets(assets) { store.commit(LOADING, true); assets.map((item, i) => { this.loader.add(item); }); this.loader.on("progress", this.loaderProgress.bind(this)); this.loader.on("complete", this.loaderComplete.bind(this)); this.loader.load(); } /** * Starts App, override if needed custom initialization. * @override * @method start * @returns {void} */ start() { this.started = true; this.renderApp(); mainLoaderDisappear().then(() => { //TODO: Defer app rendering to loader out transition complete? ¿Maybe? Or defer first view animation? }); store.commit(STARTED); } /** * Loader Progress * @override * @method loaderProgress * @returns {void} */ loaderProgress(prog) { store.commit(PROGRESS, prog); } /** * Loader Complete * @override * @method loaderComplete * @returns {void} */ loaderComplete() { store.commit(LOADING, false); this.start(); } /** * Method to be overridden, render logic * @abstract * @override * @method renderApp * @returns {void} */ renderApp() { } }