UNPKG

blinx

Version:

The Scalable JavaScript Application Framework

1,518 lines (1,306 loc) 156 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Truss"] = factory(); else root["Truss"] = factory(); })(this, function() { return /******/ (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, exports, __webpack_require__) { var _ = __webpack_require__(2).runInContext(); module.exports = __webpack_require__(5)(_, _); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); // CONCATENATED MODULE: ./src/helpers/utils.js var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var uniqueIdsTill = -1; function charsLeftIndex(string, chars) { var index = -1, length = string.length; while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} return index; } function charsRightIndex(string, chars) { var index = string.length; while (index-- && chars.indexOf(string.charAt(index)) > -1) {} return index; } /* harmony default export */ var utils_defaultExport = ({ getNextUniqueId: function getNextUniqueId() { return 'blinx-wrapper-' + ++uniqueIdsTill; }, pick: function pick(obj, arr) { var o = {}; arr.forEach(function (key) { o[key] = obj[key]; }); return o; }, length: function length(obj) { if (Array.isArray(obj)) { return obj.length; } else if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object') { return Object.keys(obj).length; } else if (typeof obj === 'string') { return obj.length; } return 0; }, trim: function trim(string, chars) { return string.slice(charsLeftIndex(string, chars), charsRightIndex(string, chars) + 1); }, clearSlashes: function clearSlashes(string) { return this.trim(string, '/'); }, partial: function partial(fn /* , args... */) { // A reference to the Array#slice method. var slice = Array.prototype.slice; // Convert arguments object to an array, removing the first argument. var args = slice.call(arguments, 1); return function () { // Invoke the originally-specified function, passing in all originally- // specified arguments, followed by any just-specified arguments. return fn.apply(this, args.concat(slice.call(arguments, 0))); }; }, getCSSSelector: function getCSSSelector(instanceConfig, moduleStore) { try { var cssSelector = '' + instanceConfig.instanceConfig.container; var tempParent = instanceConfig.meta.parent && instanceConfig.meta.parent.pointer ? instanceConfig.meta.parent.pointer : undefined; while (tempParent) { cssSelector = tempParent.instanceConfig.container + ' ' + cssSelector; tempParent = tempParent.meta.parent && tempParent.meta.parent.pointer ? tempParent.meta.parent.pointer : undefined; } return cssSelector; } catch (err) { return ''; } }, configValidator: function configValidator(config) { var isValid = true; if (!config) { console.error('Config is mandatory to create instance of any module.'); isValid = false; } if (!config.moduleName) { console.error('moduleName property on config is require field to create instance of any module.'); isValid = false; } if (typeof config.moduleName !== 'string') { console.error('moduleName property on config should be string.'); isValid = false; } if (!config.module || _typeof(config.module) !== 'object') { console.error('module property on config is mandatory and should be object'); isValid = false; } if (!config.instanceConfig || config.instanceConfig && !config.instanceConfig.container) { console.error('instanceConfig property and instanceConfig.container is mandatory'); isValid = false; } if (!isValid) { console.dirxml(config); } return isValid; } }); // CONCATENATED MODULE: ./src/interfaces/store.js var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * The module store stores all the instances of the modules which are loaded. It deletes the instances in case they are unloaded from screen * @module */ var moduleS = _extends([], { /** * inserts the instance into the module store * @method * @param instance of {@link Module} */ insertInstance: function insertInstance(instance) { this.push(instance); }, /** * deletes the instance of the module. Removes the entry from the module store * @method * instance of {@link Module} * @param id */ deleteInstance: function deleteInstance(id) { for (var i = this.length - 1; i >= 0; i--) { if (this[i].meta.id === id) { this.splice(i, 1); break; } } }, /** * Finds all the instances of the module from the module store * @method * @param name of the module to be searched * @returns {Array} of all the instances of the module */ findInstance: function findInstance(id, name) { if (id) { return this.filter(function (module) { if (module.meta.id === id) { return module; } }); } else if (name) { return this.filter(function (module) { if (module.name === name) { return module; } }); } return []; } }); /** * {@todo reserved for future use} * @type {boolean} */ var isBrowser = typeof window !== 'undefined'; /** * {@todo reserved for future use} * @type {boolean} */ var isServer = !isBrowser; /** * To be used by {@link pubsub} * {Object} List of all the subscriptions of all the events. Present in the format {"eventName": {subscription object}} */ var subscriptions = {}; /** * * @type {{store: Array}} */ var eventQ = { store: [] }; var middleWareFns = []; // CONCATENATED MODULE: ./src/interfaces/pubsub.js var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var subscribeLogger = function subscribeLogger(eventName, subscription) { console.group('Event Subscribed'); console.info(eventName); console.dirxml(subscription); console.groupEnd(); }; var publishLogger = function publishLogger(eventName, publishData) { console.group('Event Published'); console.info(eventName); console.dirxml(publishData); console.groupEnd(); }; var unsubscribeLogger = function unsubscribeLogger(eventName, subscription) { console.group('Event UnSubscribed'); console.info(eventName); console.dirxml(subscription); console.groupEnd(); }; /** * Check if the module is rendered * @param moduleContext {Object} the moduleContext object */ var isModuleRendered = function isModuleRendered(moduleContext) { return moduleContext && moduleContext.lifeCycleFlags && moduleContext.lifeCycleFlags.rendered == true; }; /** * Check if the module has initOn * @param moduleContext {Object} the moduleContext object * @param EventName {String} */ var checkIfModuleHasInitOn = function checkIfModuleHasInitOn(moduleContext, eventName) { // Should also remove from the eventQ maintained return moduleContext && moduleContext.instanceConfig && moduleContext.instanceConfig.initOn && moduleContext.instanceConfig.initOn.eventName == eventName; }; /** * Check if the event is subscribed or published using global pubsub * @param instance {Object} the instance object using which the pub sub is handled */ var isGlobalPubsub = function isGlobalPubsub(instance) { return instance && instance.getInstanceName() == 'PUBSUB'; }; /** * @class * PubSub * The publisher subscriber module for Blinx. * It is responsible for the communication between the modules through events */ var pubsub_PubSub = function () { function PubSub() { _classCallCheck(this, PubSub); } _createClass(PubSub, [{ key: 'subscribe', /** * Subscribes to the blinx event * @method * @public * @param subscription {Object} the subscription object * @param [eventName = subscription.eventName] */ value: function subscribe(subscription) { var eventName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : subscription.eventName; if (!subscriptions[eventName]) subscriptions[eventName] = []; var subscriptionData = utils_defaultExport.pick(subscription, ['callback', 'context', 'eventSubscriber', 'eventPublisher', 'once', 'type']); subscriptionData.moduleContext = this; subscriptions[eventName].push(subscriptionData); subscribeLogger(eventName, subscription); } /** * Publishes a blinx event * @method * @public * @param eventName {string} * @param message {string} */ }, { key: 'publish', value: function publish(eventName, message) { var publisher = ''; if (arguments.length === 3) { publisher = arguments[0] || ''; eventName = arguments[1]; message = arguments[2]; } else { publisher = utils_defaultExport.getCSSSelector(this); } var subscriptionsForEvent = subscriptions[eventName], remainingSubscriptions = []; publishLogger(eventName, { eventName: eventName, message: message, publisher: publisher, subscription: subscriptionsForEvent }); if (!subscriptionsForEvent) { return; } // If any of the subscription is of type Replay // Push the message to eventQ var replaySubscriptions = subscriptionsForEvent.filter(function (subs) { if (subs.type === 'RE_PLAY') return subs; }); if (replaySubscriptions.length) { eventQ.store.push({ eventName: eventName, message: message, publisher: publisher }); } subscriptionsForEvent && subscriptionsForEvent.length && subscriptionsForEvent.forEach(function (subscription) { var callback = subscription.callback, context = subscription.context, subscribeOnce = subscription.once, moduleContext = subscription.moduleContext, subscriptionMatched = false; if (!callback || typeof callback !== 'function') { console.error('The callback for the event is invalid'); return; } if (subscription.eventPublisher) { var regex = new RegExp(subscription.eventPublisher + '$'); if (regex.test(publisher)) { subscriptionMatched = true; } else { var actualPublisherHierarchy = publisher.split(' '), subscriptionPublisherHierarhcy = subscription.eventPublisher.split(' '), actualPublisherHierarchyLength = actualPublisherHierarchy.length, subscriptionPublisherHierarhcyLength = subscriptionPublisherHierarhcy.length; while (actualPublisherHierarchy.length && subscriptionPublisherHierarhcy.length) { actualPublisherHierarchyLength = actualPublisherHierarchy.length; subscriptionPublisherHierarhcyLength = subscriptionPublisherHierarhcy.length; if (actualPublisherHierarchy[actualPublisherHierarchyLength - 1] === subscriptionPublisherHierarhcy[subscriptionPublisherHierarhcyLength - 1]) { actualPublisherHierarchy.pop(); subscriptionPublisherHierarhcy.pop(); } else { actualPublisherHierarchy.pop(); } } if (!subscriptionPublisherHierarhcy.length) { subscriptionMatched = true; } } } if (!subscription.eventPublisher || subscriptionMatched) { // If replay event: publish only after render is complete // If replay event: publish all the data matched from event queue var publishData = message; if (isModuleRendered(moduleContext) || checkIfModuleHasInitOn(moduleContext, eventName) || isGlobalPubsub(moduleContext) || subscription.type == 'KEEP_ON') { callback.call(context || null, publishData); } if (subscribeOnce) { subscriptions[eventName] = subscriptions[eventName].filter(function (sub) { return sub.eventSubscriber !== subscription.eventSubscriber && sub.eventName !== subscription.eventName; }); } } }); } /** * unsubscribes a blinx event * @public * @param subscriber {Object} the reference of the module which had subscribed the event earlier * @param eventName {string} * @param callback {function} the callback method to be unsubscribed */ }, { key: 'unsubscribe', value: function unsubscribe(subscriber, eventName, callback) { var subscriptionsForEvent = subscriptions[eventName]; if (!subscriptionsForEvent) { return; } // Check if any RE_PLAY event is there and all the event context is of is same as // destroy its data from eventQ var replaySubscriptions = subscriptionsForEvent.filter(function (subscription) { if (subscription.type === 'RE_PLAY') return subscription; }); subscriptions[eventName] = subscriptionsForEvent.filter(function (subscription) { return !(subscription.callback === callback && subscription.eventSubscriber === subscriber); }); unsubscribeLogger(eventName, subscriptionsForEvent); if (replaySubscriptions.length) { if (!subscriptions[eventName].length) { // Remove all the items from eventQ with eventName eventQ.store = eventQ.store.filter(function (evt) { if (evt.eventName !== eventName) return evt; }); } } } /** * For internal use * This method is currently used to check is the event occured via Pub sub or a module * @returns {string} */ }, { key: 'getInstanceName', value: function getInstanceName() { return 'PUBSUB'; } }]); return PubSub; }(); /* harmony default export */ var pubsub_defaultExport = (pubsub_PubSub); // CONCATENATED MODULE: ./src/interfaces/module.js /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash_fp__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash_fp___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash_fp__); var module__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var module__typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var module__createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function module__classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * @module Module */ var module_Module = function () { var modulePrivateData = new WeakMap(); /** * @class * All the modules created by this framework will be extended by this Module. * @extends {@link PubSub} */ var Module = function (_PubSub) { _inherits(Module, _PubSub); module__createClass(Module, [{ key: '$proxyHandler', // *** // Observer value: function $proxyHandler() { var ctx = this; var _callObservingMethods = function _callObservingMethods() { setTimeout(function () { ctx.$_observerFns.forEach(function (fnObj) { if (Array.isArray(fnObj.deps)) { // Dont trigger if adjacent node/sibling node has changed var pathArray = path.split('='); var depsMatched = fnObj.deps.find(function (deps) { var depsArr = deps.split('.'); if (__WEBPACK_IMPORTED_MODULE_0_lodash_fp__["isEqual"](depsArr, pathArray)) return true; if (pathArray.length < depsArr.length) { var pathLastIndex = pathArray.length - 1; if (__WEBPACK_IMPORTED_MODULE_0_lodash_fp__["isEqual"](pathArray[pathLastIndex], depsArr[pathLastIndex])) return true; } if (pathArray.length <= depsArr.length) { return pathArray.find(function (keyItem, index) { return depsArr[index] !== keyItem; }); } }); depsMatched ? fnObj.fn.call(ctx) : undefined; } else { fnObj.fn.call(ctx); } }); }); }; return { get: function get(target, prop, receiver) { try { return Module.isObject(target[prop]) && '__value' in target[prop] ? target[prop].__value : target[prop]; } catch (err) { return undefined; } }, set: function set(target, name, value) { if (Array.isArray(target) && name === 'length') { target.length = value; return target; } var path = void 0; // Dont set meta data for meta fields if (name === '__path' || name === '__value') { target[name] = value; return target; } path = target.__path ? target.__path + '=' + name : name; // Set values if (Module.isObject(value)) { target[name] = new Proxy(value, ctx.$proxyHandler()); } else { target[name] = { __value: value }; } Object.defineProperty(target[name], '__path', { enumerable: false, value: path }); // Call _callObservingMethods(); return target; }, deleteProperty: function deleteProperty(target, property) { var x = void 0; if (Module.isObject(target) || Array.isArray(target)) { x = delete target[property]; } _callObservingMethods(); return x; }, has: function has(target, prop) { try { return (Module.isObject(target) || Array.isArray(target)) && target[prop]; } catch (err) { return false; } } }; } /** * @constructor * @param name * @param moduleName {string} the name of the module * @param lifeCycleFlags {lifeCycleFlags} the initial value of the lifecycle flags * @param instanceConfig the configuration of the module passed * @param instanceData It is the reference of module * @param meta */ }], [{ key: 'isObject', value: function isObject(x) { return x != null && (typeof x === 'undefined' ? 'undefined' : module__typeof(x)) === 'object'; } }, { key: 'getDependencies', value: function getDependencies(fnStr) { // Return if ._ is used directly if (fnStr.match(/\._[^.]/g)) { return '*'; } var matched = fnStr.match(/\._\.((\S)*[a-zA-Z0-9_$])/g), matchAll = '*'; // If any dependency is not found, trigger all the time. if (!matched || matched.length === 0) { return matchAll; } matched = matched.map(function (match) { var splitted = match.split('._.'); return splitted[1] || splitted[0]; }); // If any evaluated dependency is present at root level var evaluatedDependencyAtRoot = matched.find(function (match) { return match.startsWith('._['); }); if (evaluatedDependencyAtRoot) { return matchAll; } matched = matched.map(function (match) { return match.split('[')[0]; }); return matched; } }]); function Module(name, moduleName, lifeCycleFlags, instanceConfig, instanceData, meta) { module__classCallCheck(this, Module); var _this = _possibleConstructorReturn(this, (Module.__proto__ || Object.getPrototypeOf(Module)).call(this)); _this.moduleName = moduleName; _this.name = name; _this.lifeCycleFlags = module__extends({}, lifeCycleFlags); _this.instanceConfig = instanceConfig; _this.modulePlaceholders = _this.instanceConfig.placeholders; _this.createChildInstance = createInstance.bind(_this); _this.meta = meta; for (var key in instanceData) { _this[key] = instanceData[key]; } modulePrivateData.set(_this, { moduleSubscriptions: [], uniqueId: meta.id }); // Apply middleware, PRE:_Create middleWareFns.forEach(function (middlewareFn) { module__extends(_this, middlewareFn(_this)); }); // Observable proxy setup _this.$_observerFns = []; _this.observe_For && _this.observe_For.forEach(function (fnName) { if (!_this[fnName] || typeof _this[fnName] !== 'function') { console.error('{fnName} is not available over module. Can be observed.'); return; } var fnObj = { fn: _this[fnName], deps: Module.getDependencies(String(_this[fnName])) }; _this.$_observerFns.push(fnObj); }); _this._ = new Proxy({}, _this.$proxyHandler()); return _this; } /** * @method * renders the template using placeholder * @param placeholderData : The placeholder data for creation of template */ module__createClass(Module, [{ key: 'render', value: function render(placeholderData) { var containerSelector = this.getUniqueId(); var placeholders = placeholderData || this.instanceConfig.placeholders; if (!this.template) return; document.querySelector('#' + containerSelector).innerHTML = this.template(placeholders); } /** * @method * gets all the events of all types subscribed by the module * @returns {array} array of subscriptions */ }, { key: 'getAllSubscriptions', value: function getAllSubscriptions() { return modulePrivateData.get(this).moduleSubscriptions; } /** * @method * gets the unique id of the module * @returns {string} */ }, { key: 'getUniqueId', value: function getUniqueId() { return modulePrivateData.get(this).uniqueId; } /** * @method * gets the unique id of the parent element * @returns {string} */ }, { key: 'getParentInstanceId', value: function getParentInstanceId() { if (this.meta.parent) { return this.meta.parent.id; } return ''; } /** * @method * * @returns {string} */ }, { key: 'getModuleContainer', value: function getModuleContainer() { return '#' + this.getUniqueId(); } /** * * @method * @returns {string|*} */ }, { key: 'getModuleName', value: function getModuleName() { return this.moduleName; } /** * * @method * @returns {*} */ }, { key: 'getInstanceConfig', value: function getInstanceConfig() { return this.instanceConfig.placeholders; } /** * * @method * @returns {*} */ }, { key: 'getCSSSelector', value: function getCSSSelector() { return utils_defaultExport.getCSSSelector(this, moduleS); } /** * * @method */ }, { key: 'destroy', value: function destroy() {} /** * * @method * @param subscription * @param eventName */ }, { key: 'subscribe', value: function subscribe(subscription) { var eventName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : subscription.eventName; subscription.eventSubscriber = this.getModuleContainer(); modulePrivateData.get(this).moduleSubscriptions.push(subscription); _get(Module.prototype.__proto__ || Object.getPrototypeOf(Module.prototype), 'subscribe', this).call(this, subscription, eventName); } /** * * @method * @param eventName * @param message */ }, { key: 'publish', value: function publish(eventName, message) { _get(Module.prototype.__proto__ || Object.getPrototypeOf(Module.prototype), 'publish', this).call(this, eventName, message); } /** * * @method */ }, { key: 'dequeueEvents', value: function dequeueEvents() { var moduleSubscriptions = this.getAllSubscriptions(); eventQ.store.forEach(function (evt) { var queuedEvent = moduleSubscriptions.filter(function (event) { if (evt.eventName === event.eventName && event.type === 'RE_PLAY') { return event; } }); queuedEvent.forEach(function (event) { event.callback && event.callback.call(event.context ? event.context : null, evt.message); }); }); } /** * * @method * @param eventName * @param callback */ }, { key: 'unsubscribe', value: function unsubscribe(eventName, callback) { if ((typeof eventName === 'undefined' ? 'undefined' : module__typeof(eventName)) === 'object') { callback = eventName.callback; eventName = eventName.eventName; } _get(Module.prototype.__proto__ || Object.getPrototypeOf(Module.prototype), 'unsubscribe', this).call(this, this.getModuleContainer(), eventName, callback); } /** * @method * actual rendering happens here. Puts the wrapper for the module and adds it to the container. * @param module {Object} * @param compiledHTML * @returns {*} */ }, { key: 'getInstanceName', /** * For internal use * This method is currently used to check is the event occured via Pub sub or a module * @returns {string} */ value: function getInstanceName() { return 'MODULE'; } }], [{ key: 'createModuleArena', value: function createModuleArena(module, compiledHTML) { // If compiledHTML is not provided, start creating dom element progressively. var themeClass = ''; if (module.instanceConfig.moduleClassName) { themeClass = module.instanceConfig.theme ? module.instanceConfig.moduleClassName + '-' + module.instanceConfig.theme : module.instanceConfig.moduleClassName + '-default'; } else { themeClass = module.instanceConfig.theme ? module.moduleName + '-' + module.instanceConfig.theme : module.moduleName + '-default'; } if (typeof compiledHTML !== 'string') { document.querySelector(module.instanceConfig.container).innerHTML = '<div id="' + module.getUniqueId() + '" class="' + themeClass + ' play-arena"></div>'; return; } // If compiledHTML is provided, create page string. if (compiledHTML.trim() === '') { compiledHTML = '<div id="' + module.getUniqueId() + '"></div>'; } else {} return compiledHTML; } }]); return Module; }(pubsub_defaultExport); return Module; }(); /* harmony default export */ var module_defaultExport = (module_Module); // CONCATENATED MODULE: ./src/constants.js /* harmony default export */ var constants_defaultExport = ({ /** * <ul> *<li> EVENT_ENUM: ENUM constant for the types of events *<li>"KEEP_ON": The event will be listened even when the module has not been rendered. *<li> "RE_PLAY": Non rendered modules with replay events will be queued on publishing. Will automatically call the callback once the rendering is complete. *<li> "PLAY_AFTER_RENDER",{@defaultvalue} If the event is of this type then the module starts listening * to the event once the rendering completes. * </ul> */ EVENT_ENUM: { keepOn: 'KEEP_ON', replay: 'RE_PLAY', playAfterRender: 'PLAY_AFTER_RENDER' }, /** * Based on the module lifecycle. The following events occur * <ul> *<li> 1) resolveRenderOn: event occurs just before resolveRenderOn method is called *<li> 2) render: event occurs when page renders(in case template passed) or just before render method is called *<li> 3) onRenderComplete: event is fired just before onRenderComplete method is called *<li> 4) onStatusChange: event is fired whenever the status of module is changed. The status change events are mentioned * on the next section *<li> 5) destroy: event occurs when module is destroyed. * </ul> */ MODULE_EVENTS: { resolveRenderOn: 'resolveRenderOn', render: 'render', onRenderComplete: 'onRenderComplete', onStatusChange: '__onStatusChange', destroy: 'destroy' }, /** * * LIFECYCLE EVENTS LIST: * <ul> *<li>1)"LIFECYCLE:CREATED", *<li>2)"LIFECYCLE:KEEP_ON_&_REPLAY_SUBSCRIBED", *<li>3)"LIFECYCLE:INIT_ON_SUBSCRIBED", *<li>4)"LIFECYCLE:RESOLVE_RENDER_ON_CALLED", *<li>5)"LIFECYCLE:LISTENS_TO_PLAY_AFTER_RENDER_SUBSCRIBED", *<li>6)"LIFECYCLE:ON_RENDER_CALLED", *<li>7)"LIFECYCLE:ON_RENDER_CAOMPLETE_CALLED" * </ul> */ onStatusChange_EVENTS: { onCreate: 'LIFECYCLE:CREATED', keepOnReplaySubscribed: 'LIFECYCLE:KEEP_ON_&_REPLAY_SUBSCRIBED', initOnSubscribed: 'LIFECYCLE:INIT_ON_SUBSCRIBED', resolveRenderOnCalled: 'LIFECYCLE:RESOLVE_RENDER_ON_CALLED', listensToPlayAfterRenderSubscribed: 'LIFECYCLE:LISTENS_TO_PLAY_AFTER_RENDER_SUBSCRIBED', renderCalled: 'LIFECYCLE:ON_RENDER_CALLED', onRenderCompleteCalled: 'LIFECYCLE:ON_RENDER_CAOMPLETE_CALLED' }, /** * @readonly * @private * @constant {Object} lifeCycleFlags following fields * <ul> * <li>booted: true </li> * <li>rendered: false</li> * <li>preRenderResolved: false</li> * </ul> */ lifeCycleFlags: { booted: true, preRenderResolved: false, rendered: false } }); // CONCATENATED MODULE: ./src/devtool.js /** * Created by anoof.shaikh on 03/01/17. */ var attachListener = function attachListener(moduleObject) { document.addEventListener('content-script-to-blinx', function (event) { var message = void 0; var moduleData = function moduleData() { var returnObject = []; // var objectToParse = _store.moduleS; var objectToParse = moduleObject(); objectToParse.forEach(function (module, moduleIndex) { var subModulesArray = function subModulesArray(thisModule) { if (!thisModule.config || !thisModule.config.modules) { return []; } var returnArr = []; thisModule.config.modules.forEach(function (subModule, subModuleIndex) { returnArr.push({ moduleName: subModule.moduleName, moduleConfig: { container: subModule.instanceConfig.container, listensTo: subModule.instanceConfig.listensTo, placeholders: JSON.stringify(subModule.instanceConfig.placeholders) }, subModules: subModulesArray(subModule), moduleInstanceConfig: JSON.stringify(subModule.instanceConfig) }); }); return returnArr; }; var moduleObj = { moduleName: module.moduleName, moduleConfig: { container: module.instanceConfig.container, listensTo: module.instanceConfig.listensTo, placeholders: JSON.stringify(module.instanceConfig.placeholders) }, subModules: subModulesArray(module), moduleInstanceConfig: JSON.stringify(module.instanceConfig) }; returnObject.push(moduleObj); }); return returnObject; }; switch (event.detail.eventId) { case 'GET_MODULES': message = { eventId: 'GET_MODULES_REPONSE', data: moduleData() }; break; } var event = new CustomEvent('blinx-to-content-script', { bubbles: true, detail: message }); document.dispatchEvent(event); }); }; /* harmony default export */ var devtool_defaultExport = ({ attachListener: attachListener }); // CONCATENATED MODULE: ./src/blinx.js /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_lodash_fp__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_lodash_fp___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_lodash_fp__); /** This is the major framework file. * @exports { * createInstance: creates a new instance of the module. * destroyModuleInstance: destroys the module instance, * use: use it if you want to extend Blinx * * } */ /** * * @param module [Object] Blinx module * @param eventName [string] * @private */ var blinx__onBreath = function _onBreath(module, eventName) { if (module[constants_defaultExport.MODULE_EVENTS.onStatusChange]) { module[constants_defaultExport.MODULE_EVENTS.onStatusChange](eventName); } }; /** * Publishes the event when state of the module changes * @param moduleDetail [object] module * @param eventName [string] * @private */ var _emitLifeCycleEvent = function _emitLifeCycleEvent(moduleDetail, eventName) { moduleDetail.publish('' + moduleDetail.getModuleName() + eventName, { moduleInstanceId: moduleDetail.getUniqueId() }); }; /** * This function resolves the Promise if initOn is true and module is already rendered. Refer {@link lifeCycleFlags} for * initial lifecycle values. * Calls {@link _callResolveRenderOn} if either case fails * @param {Module} module. The module to be rendered. * @returns {Promise} * @private */ var _listenForInitOn = function _listenForInitOn(module) { if (module.instanceConfig.initOn || module.lifeCycleFlags.rendered) { return Promise.resolve(module.path); } return blinx__callResolveRenderOn(module); }; // STEP:2 /** * * @param {Module} module to be rendered. * @param {*} data the data to be passed to module while initialization * <p>Calls {@link Module.resolveRenderOn} method . This method is passed from the config for the module and after * resolveRenderOn is resolved, lifecycle status is changed to "preRenderResolved". The resolveRenderOn should return * {Promise}</p> * @private */ var blinx__callResolveRenderOn = function _callResolveRenderOn(module, data) { module_defaultExport.createModuleArena(module); if (module[constants_defaultExport.MODULE_EVENTS.resolveRenderOn]) { var moduleResoved = module[constants_defaultExport.MODULE_EVENTS.resolveRenderOn](data); if (moduleResoved && moduleResoved.then && typeof moduleResoved.then === 'function') { var onPromiseComplete = function onPromiseComplete(res) { module.lifeCycleFlags.preRenderResolved = true; blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.resolveRenderOnCalled); return blinx__lockEvents(module, res); }; return moduleResoved.then(onPromiseComplete).catch(onPromiseComplete); } blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.resolveRenderOnCalled); return blinx__lockEvents(module, moduleResoved); } blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.resolveRenderOnCalled); return blinx__lockEvents(module, data); }; // STEP:3 [Hot events] /** * Subscribes to all the events of type playAfterRender * @param {Module} module to be rendered. * @param placeholderResponse * @private */ var blinx__lockEvents = function _lockEvents(module, placeholderResponse) { module.instanceConfig.listensTo && module.instanceConfig.listensTo.length && module.instanceConfig.listensTo.filter(function (evt) { if (evt.type === constants_defaultExport.EVENT_ENUM.playAfterRender || !evt.type) { return evt; } }).forEach(function (listener) { module.subscribe({ eventName: listener.eventName, callback: module[listener.callback], context: module, eventPublisher: listener.eventPublisher, once: listener.once }); }); blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.listensToPlayAfterRenderSubscribed); return blinx__callRender(module, placeholderResponse); }; // STEP:4 /** * <p>Renders the module by calling {@link Module.createModuleArena} * Changes the life cycle flag to rendered thereafter.</p> * @param {Module} module to be rendered. * @param placeholderResponse * @returns {Promise} * @private */ var blinx__callRender = function _callRender(module, placeholderResponse) { // if initOn is present exec below steps on initOn // exec resolveRenderOn (if available) // exec render after resolveRenderOn completes // throw error is render and template are not provided return new Promise(function (res, rej) { // Null to be replaced with resolveRenderOn data blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.renderCalled); var compiledHTML = module[constants_defaultExport.MODULE_EVENTS.render](placeholderResponse, compiledHTML); module.lifeCycleFlags.rendered = true; _emitLifeCycleEvent(module, '_READY'); blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.onRenderCompleteCalled); if (module[constants_defaultExport.MODULE_EVENTS.onRenderComplete]) { module[constants_defaultExport.MODULE_EVENTS.onRenderComplete](); } res(); // If there are any queued events , dequeue the events based on modules subscriptions module.dequeueEvents(); }); }; /** *<p>Called after the module is registered. Responsible for rendering the module. * The rendering will wait till the event occurs if initOn option is provided. </p> * <p>This method contains four steps * <ul> * <li>call resolveRenderOn method and wait for the promise to be resolved ({@link _callResolveRenderOn})</li> * <li>subscribe to the events of type "playAfterRender"</li> * <li>Render the module</li> * </ul> * </p> * * @recursive * @param patchModules {Array} The array of modules to be rendered. Initially list is taken from {@link moduleS} * @param promiseArr {Array} the array of promise objects * @private */ var _startExec = function _startExec(patchModules, promiseArr) { var rootModules = patchModules.filter(function (module) { return !module.meta.parent.id; }); if (!rootModules.length) { rootModules = [patchModules[0]]; } rootModules.forEach(function (rootModule) { // Render this module var moduleResolvePromise = new Promise(function (resolve, reject) { _listenForInitOn(rootModule).then(function () { if (rootModule.meta.children && rootModule.meta.children.length) { rootModule.meta.children && rootModule.meta.children.forEach(function (module) { if (!module.pointer.lifeCycleFlags.rendered) { _startExec([module.pointer], promiseArr); } }); } resolve(rootModule.meta.id); }); }); promiseArr.push(moduleResolvePromise); }); }; /** * * @param module {Module} The Module generated by {@link _registerModule}. If the module listens to any event or if the * module is instantiated based on an event then module is made to subscribe all the events. * <p>initOn will have following properties * <ul> * <li>eventName {String} The name of the event</li> * <li>eventPublisher {String} [Optional] CSS selector of the publisher of the event to which the module is subscribing. * The module listens to event from all the publishers if this field is not provided</li> * <li>context {Object} [Optional] The context in which event is subscribed</li> * <li>callback</li> {function} the callback method for the event * </ul> * </p> * <p> * listensTo {array} this is an array of objects (the events) to which the module subscribes * <ul> * <li>eventName {String} The name of the event</li> * <li>eventPublisher {String} [Optional] CSS selector of the publisher of the event to which the module is subscribing. * The module listens to event from all the publishers if this field is not provided</li> * <li>context {Object} [Optional] The context in which event is subscribed</li> * <li>callback {function} the callback method for the event</li> * <li>{boolean} [once = false] The callback of the function that can only be called one time if true. Repeated event publish * will have no effect.</li> * <li>[type= "PLAY_AFTER_RENDER"] {EVENT_ENUM} the type of the event </li> * </ul> * </p> * @returns {*} * @private */ var blinx__registerSubscription = function _registerSubscription(module) { module.instanceConfig.initOn && module.subscribe({ eventName: module.instanceConfig.initOn.eventName, eventPublisher: module.instanceConfig.initOn.eventPublisher, context: module.instanceConfig, callback: utils_defaultExport.partial(blinx__callResolveRenderOn, module), once: true }); blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.initOnSubscribed); module.instanceConfig.listensTo && module.instanceConfig.listensTo.length && module.instanceConfig.listensTo.filter(function (evt) { if (evt.type === constants_defaultExport.EVENT_ENUM.keepOn || evt.type === constants_defaultExport.EVENT_ENUM.replay) { return evt; } }).forEach(function (listener) { module.subscribe({ eventName: listener.eventName, callback: module[listener.callback], context: module, eventPublisher: listener.eventPublisher, once: listener.once, type: listener.type }); }); blinx__onBreath(module, constants_defaultExport.onStatusChange_EVENTS.keepOnReplaySubscribed); }; /** * * @param config {Object} The configuration of the module to be created. Creates instance of {@link Module} and keeps it * in {@link Store}.If the module has child modules then the child modules too will be registered. * <p>It must contain following properties * <ul style="list-style: none;"> * <li>1. moduleName {String} The unique name in the workspace of the module * <li>2. module {Object}: It is the reference of module to be consumed * <li>3. instanceConfig {Object}: the configuration to be passed for that particular module. It must contain following * properties: * <ul> * <li>placeholders {Object} * <li>container {String} Css selector of the container element. This should be unique. * <li>listensTo {Array} [Optional] the list of events that the module will listen to. * </ul> * </ul> * </p> * <p>If the module has already been registered on the same path then registration would be skipped and a warning will * be generated.</p> * <p></p> * @param {String} [moduleName = config.moduleName] The unique name in the workspace of the module * @param {Object}[instance = config.module] * @param {Object}[instanceConfig = config.instanceConfig] * @param {String}[path=""] * @private */ var blinx__registerModule = function _registerModule(moduleName, config) { var instance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : config.module; var instanceConfig = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : config.instanceConfig; var patchModuleArray = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; var parent = arguments[5]; var parentMeta = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : parent && parent.meta; if (typeof parent === 'string') { parent = moduleS.find(function (module) { return module.name === parent; }); parentMeta = parent && parent.meta; } var parentName = config.name ? config.name.split('.') : undefined, foundModules = void 0; if (parent && parent.instanceConfig && parent.instanceConfig.modules && parent.instanceConfig.modules.length) { var configFromParent = parent.instanceConfig.modules.filter(function (parentSibling) { return parentSibling.moduleName === moduleName; }); if (configFromParent && configFromParent.length) { var parentInstance = configFromParent[0].instanceConfig || {}; instanceConfig.placeholders = parentInstance.placeholders || instanceConfig.placeholders; instanceConfig.listensTo = parentInstance.listensTo || instanceConfig.listensTo; } } if (instanceConfig.placeholders && instance && instance.config && instance.config.placeholders) { instanceConfig.placeholders = __WEBPACK_IMPORTED_MODULE_1_lodash_fp__["merge"](instance.config.placeholders, instanceConfig.placeholders); } if (this instanceof module_defaultExport) { var parentId = this.getUniqueId(); foundModules = moduleS.filter(function (module) { return module.meta.id === parentId; }); } else if (!parent && parentName && parentName.length === 2) { foundModules = moduleS.filter(function (module) { return module.name === parentName[0]; }); } if (foundModules && foundModules.length) { parent = foundModules[0]; parentMeta = parent.meta; } var meta = { id: utils_defaultExport.getNextUniqueId(), parent: { id: parentMeta && parentMeta.id ? parentMeta.id : undefined, pointer: parent }, children: [], siblings: parentMeta ? [].concat(parentMeta.children) : [] }; var moduleDetail = new module_defaultExport(config.name, moduleName, constants_defaultExport.lifeCycleFlags, instanceConfig, instance, meta); // Store module moduleS.insertInstance(moduleDetail); patchModuleArray.push(moduleDetail); blinx__registerSubscription(moduleDetail); _emitLifeCycleEvent(moduleDetail, '_CREATED'); blinx__onBreath(moduleDetail, constants_defaultExport.onStatusChange_EVENTS.onCreate); if (parentMeta) { meta.siblings = [].concat(parentMeta.children); parentMeta.children.push({ id: meta.id, pointer: moduleDetail }); } // Has child modules if (instance.config && instance.config.modules && instance.config.modules.length) { instance.config.modules.forEach(function (childModule) { _registerModule(childModule.moduleName, childModule, childModule.module, childModule.instanceConfig, patchModuleArray, moduleDetail); }); } else { return patchModuleArray; } }; /** * * Destroys the module . Does the following * <ul> * <li>removed DOM element</li> * <li> Unsubscribes events.It calls {@link Module.unsubscribe}</li> * <li> Removes the entry of module from module store </li> * <li> Removes the entry of child modules from module store </li> * </ul> * @param module {Array| Object} The module to be destroyed * @param [context = window] {object} @todo . Reserved for future enhancement * @returns {boolean} true when module gets deleted successfully */ function destroyModuleInstance(module) { var context = arguments.length >