UNPKG

application-prototype

Version:
484 lines (451 loc) 14.3 kB
//@ /** * @example * Application.require('js-template-component') * .then(function ( * // @type {JSTemplateComponent} * JSTemplateComponentConstructor * ) { * new JSTemplateComponentConstructor( * 'my-custom-tagname', * { * context: { * numberOfClicks: 0 * }, * templateCode: ` * <div> * {{ this.numberOfClicks }} * <button (click)="this.increaseClicksNumber()"> * </button> * </div> * `, * sharedPrototypeMethods: { * increaseClicksNumber: function () { * this.numberOfClicks += 1; * } * }, * sharedReferences: {}, * cssStyles: [ * '/some/styles/style.css' * ] * }, * function (err) { * if (err) console.error(err); * } * ); * }).catch(console.error); * @class * @name JSTemplateComponent * @param {string} tagName * @param {JSTemplateComponent.options} options * @param {JSTemplateComponent.constructorCallback} callback */; /** * @memberof JSTemplateComponent * @callback Builder * @param {string} tagName * @param {JSTemplateComponent.options} options * @param {JSTemplateComponent.constructorCallback} callback * @returns {JSTemplateComponent} */ /** * @memberof JSTemplateComponent * @interface contextInstance */ /** * @memberof JSTemplateComponent.contextInstance * @method redraw */ /** * @memberof JSTemplateComponent.contextInstance * @method redrawForce */ /** * @memberof JSTemplateComponent.contextInstance * @name references * @type {Object<string,any>} */ /** * @memberof JSTemplateComponent.contextInstance * @name node * @type {HTMLElement} */ /** * @memberof JSTemplateComponent * @typedef {object} contextLifeCycle * @property {JSTemplateComponent.lifeCycleCallback} [init] callbacks on init * @property {JSTemplateComponent.lifeCycleCallbackGetReferences} [getReferences] returns * @property {JSTemplateComponent.lifeCycleCallback} [contentChange] callback on content change * @property {JSTemplateComponent.lifeCycleCallback} [attrChange] context object default is Node * @property {JSTemplateComponent.lifeCycleCallback} [remove] context object default is Node */ /** * @memberof JSTemplateComponent * @interface contextWithInstance * @implements JSTemplateComponent.contextInstance */ /** * @memberof JSTemplateComponent.contextWithInstance * @name __instance * @type {JSTemplateComponent.contextInstance} */ /** * @memberof JSTemplateComponent.contextWithInstance * @description context object default is Node * @name __lifeCycle * @type {JSTemplateComponent.contextLifeCycle} */ /** * @memberof JSTemplateComponent.contextWithInstance * @description context object default is Node * @name state * @type {Object<string,(string|number|Object<string,any>|null|any[])>} */ /** * @memberof JSTemplateComponent * @interface contextWithoutInstance */ /** * @memberof JSTemplateComponent.contextWithoutInstance * @description context object default is Node * @name __lifeCycle * @type {JSTemplateComponent.contextLifeCycle} */ /** * @memberof JSTemplateComponent.contextWithoutInstance * @description context object default is Node * @name state * @type {Object<string,(string|number|Object<string,any>|null|any[])>} */ /** * @memberof JSTemplateComponent * @typedef {object} options * @property {function ():JSTemplateComponent.contextWithoutInstance} [context] context object default is Node * @property {JSTemplateComponent.contextLifeCycle} [__lifeCycle] context object default is Node * @property {string} [templateCode] template Code * @property {string} [templateUrl] template URL * @property {Array<string>} [cssStyles] list of URLs that point to styles * @property {object} [sharedReferences] references that will be same for all created components * @property {object} [sharedPrototypeMethods] methods that will be on all components under method "methods" * @property {boolean} [__flag_RejectOnStylesError=false] */ /** * @memberof JSTemplateComponent * @callback lifeCycleCallbackGetReferences * @param {JSTemplateComponent.contextWithInstance} context * @param {object} sharedReferences * @param {object} sharedPrototypeMethods * @returns {object} */ /** * @memberof JSTemplateComponent * @callback lifeCycleCallback * @param {JSTemplateComponent.contextWithInstance} context * @param {Object<string,any>} references * @param {Object<string,any>} methods */ /** * @memberof JSTemplateComponent * @callback constructorCallback * @param {Error} err */ function JSTemplateComponentConstructor( /** * @private * @type {string} */ tagName, /** * @private * @type {JSTemplateComponent.options} */ options, /** * @private * @type {JSTemplateComponent.constructorCallback} */ callback ) { //@ts-ignore Application.require([ "uriLoad :: uri-load", "customElements :: custom-elements", "JSTemplate :: js-template", "request" ]).then(function (lib) { /** * @private * @var {object} __instance * @property {string} templateCode */ var __instance = { templateCode : '' }; function __getTemplate() { if (options.templateCode) { return Promise.resolve(options.templateCode); } else if (options.templateUrl) { return new Promise(function (resolve, reject) { new lib.request().url(options.templateUrl) .response("text") .then(function (templateCode) { __instance.templateCode = templateCode; resolve(); }).catch(reject); }); } else { return Promise.reject(Error('[OPTIONS_ERROR]: should be defined `templateCode` or `templateUrl`')); } } function __loadCssStyles() { if (!options.cssStyles.length) { return Promise.resolve(); } return new Promise(function (resolve, reject) { lib.uriLoad.link( options.cssStyles, function (err) { if (err) { if (options.__flag_RejectOnStylesError) { reject(err); } else { resolve(); } } else { resolve(); } } ); }); } __getTemplate().then( function () { __loadCssStyles().then( function () { var sharedPrototypeMethods = options.sharedPrototypeMethods || {}; lib.customElements.registerMethods( tagName, Object.assign( sharedPrototypeMethods, { "__onInit" : /** * @private * @this {HTMLElement} */ function () { /** * @private * @type {HTMLElement} */ var node = this; /** * @private * @type {JSTemplateComponent.contextWithInstance} */ var _contextDefault = { setState : function (state, callback) { ComponentContext.state = Object.assign( ComponentContext.state || {}, state || {} ); ComponentContext.__requireRender = true; ComponentContext.__instance.redraw(); if (callback) callback(); }, __requireRender: true, __instance : { node : node, redraw : function () { if (!ComponentContext.__requireRender) return; //@ts-ignore if (node.attrdata.JSRenderer) { //@ts-ignore ComponentContext.__requireRender = false; node.attrdata.JSRenderer.content.redraw(); // /** // * @deprecated // */ // node.attrdata.JSRenderer.attr.redraw(); } }, redrawForce: function () { ComponentContext.__requireRender = true; ComponentContext.__instance.redraw(); } }, __lifeCycle: { init: function () { if (options.__lifeCycle && options.__lifeCycle.init) { options.__lifeCycle.init( ComponentContext, envReferences, sharedPrototypeMethods ); } }, attrChange: function () { if (options.__lifeCycle && options.__lifeCycle.attrChange) { options.__lifeCycle.attrChange( ComponentContext, envReferences, sharedPrototypeMethods ); } }, getReferences: function () { // dummy function }, contentChange: function () { if (options.__lifeCycle && options.__lifeCycle.contentChange) { options.__lifeCycle.contentChange( ComponentContext, envReferences, sharedPrototypeMethods ); } }, remove: function () { if (options.__lifeCycle && options.__lifeCycle.remove) { options.__lifeCycle.remove( ComponentContext, envReferences, sharedPrototypeMethods ); } } } }; var sharedReferences = options.sharedReferences || {}; /** * @private * @type {JSTemplateComponent.contextWithInstance} */ var ComponentContext = Object.assign( options.context ? (options.context(_contextDefault, sharedReferences, sharedPrototypeMethods) || {}) : {}, _contextDefault ); var envReferences = Object.assign({}, sharedReferences); if (options.__lifeCycle && options.__lifeCycle.getReferences) { Object.assign( envReferences, options.__lifeCycle.getReferences( ComponentContext, sharedReferences, sharedPrototypeMethods ) || {} ); } ComponentContext.__instance.references = envReferences; node.innerHTML = __instance.templateCode; // @ts-ignore node.attrdata.JSRenderer = { ComponentContext: ComponentContext, envReferences: envReferences, content : lib.JSTemplate.parseContent(node, function () {}, { context : ComponentContext, args : envReferences }), attr : lib.JSTemplate.parseAttributes(node, function () {}, { context : ComponentContext, args : envReferences }) }; if (options.__lifeCycle && options.__lifeCycle.init) { options.__lifeCycle.init.apply( ComponentContext, [ ComponentContext, envReferences, sharedPrototypeMethods ] ); } ComponentContext.__instance.redraw(); }, "__onContentChange" : /** * @private * @this {HTMLElement} */ function () { if (this.attrdata.JSRenderer && this.attrdata.JSRenderer.ComponentContext) { if ( this.attrdata.JSRenderer.ComponentContext.__requireRender // !this.attrdata.JSRenderer.ComponentContext.__instance.__renderStarted ) { if (options.__lifeCycle && options.__lifeCycle.contentChange) { options.__lifeCycle.contentChange.apply( this.attrdata.JSRenderer.ComponentContext, [ this.attrdata.JSRenderer.ComponentContext, this.attrdata.JSRenderer.envReferences, this.methods ] ); } this.attrdata.JSRenderer.ComponentContext.__instance.redraw(); } } }, "__onAttrChange" : /** * @private * @this {HTMLElement} */ function () { if (this.attrdata.JSRenderer && this.attrdata.JSRenderer.ComponentContext) { if ( this.attrdata.JSRenderer.ComponentContext.__requireRender // !this.attrdata.JSRenderer.ComponentContext.__instance.__renderStarted ) { if (options.__lifeCycle && options.__lifeCycle.attrChange) { options.__lifeCycle.attrChange.apply( this.attrdata.JSRenderer.ComponentContext, [ this.attrdata.JSRenderer.ComponentContext, this.attrdata.JSRenderer.envReferences, this.methods ] ); } this.attrdata.JSRenderer.ComponentContext.__instance.redraw(); } } }, "__onRemove" : /** * @private * @this {HTMLElement} */ function () { if (this.attrdata.JSRenderer) { if (options.__lifeCycle && options.__lifeCycle.remove) { options.__lifeCycle.remove.apply( this.attrdata.JSRenderer.ComponentContext, [ this.attrdata.JSRenderer.ComponentContext, this.attrdata.JSRenderer.envReferences, this.methods ] ); } } } } ) ); } ).catch(function (err) { callback(err); }); } ).catch(function (err) { callback(err); }); }).catch(function (err) { callback(err); }); return this; } module.exports = JSTemplateComponentConstructor;