blinx
Version:
The Scalable JavaScript Application Framework
1,518 lines (1,306 loc) • 156 kB
JavaScript
(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 >