UNPKG

nornj

Version:

A powerful template engine that can works with React, JSX enhancement or alternative tools.

394 lines (344 loc) 10.2 kB
import nj from '../core'; import * as tools from '../utils/tools'; import * as tranData from '../transforms/transformData'; import { ExtensionDelegate, ExtensionDelegateMultiParams, ExtensionPrefixConfig, ExtensionOption } from '../interface'; //Global extension list export const extensions: { [name: string]: ExtensionDelegate | ExtensionDelegateMultiParams } = { if: (value, options) => { if (value && value._njOpts) { options = value; value = options.props.condition; } if (value === 'false') { value = false; } let ret; const props = options.props; if (value) { ret = ((props && props.then) || options.children)(); } else if (props) { const elseFn = props['else']; if (props.elseifs) { const l = props.elseifs.length; tools.each( props.elseifs, (elseif, i) => { if (elseif.value) { ret = elseif.fn(); return false; } else if (i === l - 1) { if (elseFn) { ret = elseFn(); } } }, true ); } else { if (elseFn) { ret = elseFn(); } } } if (options.useString && ret == null) { return ''; } return ret; }, then: options => (options.tagProps.then = options.children), else: options => (options.tagProps['else'] = options.children), elseif: (value, options) => { if (value && value._njOpts) { options = value; value = options.props.condition || options.props.value; } const { tagProps } = options; if (!tagProps.elseifs) { tagProps.elseifs = []; } tagProps.elseifs.push({ value, fn: options.children }); }, switch: (value, options) => { if (value && value._njOpts) { options = value; value = options.props.value; } let ret; const props = options.props, elseifs = props.elseifs || [{}], l = elseifs.length; tools.each( elseifs, (elseif, i) => { if (value === elseif.value) { ret = elseif.fn(); return false; } else if (i === l - 1) { if (props['else']) { ret = props['else'](); } } }, true ); return ret; }, each: (list, options) => { if (list && list._njOpts) { options = list; list = options.props.of; } const useString = options.useString, props = options.props; let ret; if (list) { if (useString) { ret = ''; } else { ret = []; } const isArrayLike = tools.isArrayLike(list); const isArrayLoop = isArrayLike || tools.isSet(list) || tools.isWeakSet(list); tools.each( list, (item, index, len, lenObj) => { const param = { data: [item], index: isArrayLoop ? index : len, item, newParent: true }; const _len = isArrayLoop ? len : lenObj; const extra = { '@first': param.index === 0, '@last': param.index === _len - 1 }; if (!isArrayLoop) { extra['@key'] = index; } param.data.push(extra); const retI = options.children(param); if (useString) { ret += retI; } else { ret.push(retI); } }, isArrayLike ); //Return null when not use string and result is empty. if (!useString && !ret.length) { ret = null; } if ((!ret || !ret.length) && props && props['else']) { ret = props['else'](); } } else { if (props && props['else']) { ret = props['else'](); } if (useString && ret == null) { ret = ''; } } return ret; }, //Parameter prop: (name, options) => { const ret = options.value(); //Get parameter value let value; if (ret !== undefined) { value = ret; } else { //Match to Similar to "checked" or "disabled" attribute. value = !options.useString ? true : name; } options.tagProps[options.outputH ? tranData.fixPropName(name) : name] = value; }, //Spread parameters spread: (props, options) => { const { tagProps } = options; tools.each( props, (v, k) => { tagProps[k] === undefined && (options.tagProps[k] = v); }, false ); }, show: options => { if (!options.value()) { const { tagProps, useString } = options; if (!tagProps.style) { tagProps.style = useString ? '' : {}; } if (useString) { tagProps.style += (tagProps.style ? ';' : '') + 'display:none'; } else if (tools.isArray(tagProps.style)) { tagProps.style.push({ display: 'none' }); } else { tagProps.style.display = 'none'; } } }, obj: options => options.props, block: options => options.children(), with: function(originalData, options) { if (originalData && originalData._njOpts) { options = originalData; return options.children({ data: [options.props] }); } else { const { props } = options; return options.children({ data: [ props && props.as ? { [props.as]: originalData } : originalData ] }); } }, arg: options => { const { tagProps } = options; if (!tagProps.args) { tagProps.args = []; } tagProps.args.push(options.value()); }, css: options => options.props.style }; function _config(params?: ExtensionOption, extra?: ExtensionOption): ExtensionOption { let ret: ExtensionOption = { onlyGlobal: false, useString: false, newContext: true, isSubTag: false, isDirective: false, isBindable: false, useExpressionInProps: false, hasName: true, noTagName: false, hasTagProps: true, hasTmplCtx: true, hasOutputH: false }; if (params) { ret = tools.assign(ret, params); } if (extra) { ret = tools.assign(ret, extra); } return ret; } const _defaultCfg: ExtensionOption = { onlyGlobal: true, newContext: false, hasName: false, hasTagProps: false, hasTmplCtx: false }; const _defaultCfgExpInProps = _config(_defaultCfg, { useExpressionInProps: true }); //Extension default config export const extensionConfig: { [name: string]: ExtensionOption } = { if: _config(_defaultCfgExpInProps), else: _config(_defaultCfgExpInProps, { isSubTag: true, hasTagProps: true }), switch: _config(_defaultCfgExpInProps, { needPrefix: ExtensionPrefixConfig.onlyLowerCase }), each: _config(_defaultCfgExpInProps, { newContext: { item: 'item', index: 'index', data: { first: ['@first', 'first'], last: ['@last', 'last'], $key: ['@key', 'key'] } } }), prop: _config(_defaultCfg, { isDirective: true, needPrefix: true, hasTagProps: true }), obj: _config(_defaultCfg, { needPrefix: true }), with: _config(_defaultCfg, { newContext: { getDataFromProps: true } }), style: { needPrefix: true } }; extensionConfig.then = _config(extensionConfig['else']); extensionConfig.elseif = _config(extensionConfig['else']); extensionConfig.spread = _config(extensionConfig.prop); extensionConfig.block = _config(extensionConfig.obj); extensionConfig.arg = _config(extensionConfig.prop); extensionConfig.show = _config(extensionConfig.prop, { useExpressionInProps: true, noTagName: true, hasOutputH: true }); extensionConfig.css = _config(extensionConfig.obj); //Extension alias extensions['for'] = extensions.each; extensionConfig['for'] = _config(extensionConfig.each); extensions['case'] = extensions.elseif; extensionConfig['case'] = _config(extensionConfig.elseif); extensions.empty = extensions['default'] = extensions['else']; extensionConfig.empty = _config(extensionConfig['else']); extensionConfig['default'] = _config(extensionConfig['else']); extensions.strProp = extensions.prop; extensionConfig.strProp = _config(extensionConfig.prop, { useString: true }); extensions.strArg = extensions.arg; extensionConfig.strArg = _config(extensionConfig.strProp); extensions.pre = extensions.block; extensionConfig.pre = _config(extensionConfig.block); export function registerExtension<T extends ExtensionDelegate>(options: { [name: string]: T | { extension?: T; options?: ExtensionOption }; }): void; export function registerExtension<T extends ExtensionDelegate>( name: string, extension: T, options?: ExtensionOption, mergeConfig?: boolean ): void; export function registerExtension<T extends ExtensionDelegate>( name, extension?: T, options?: ExtensionOption, mergeConfig?: boolean ): void { let params = name; if (!tools.isObject(name)) { params = {}; params[name] = { extension, options }; } tools.each( params, function(v, name) { if (v) { const { extension, options }: { extension: T; options: ExtensionOption } = v; if (extension) { extensions[name] = extension; } else if (!mergeConfig) { extensions[name] = v; } if (mergeConfig) { if (!extensionConfig[name]) { extensionConfig[name] = _config(); } if (tools.isObject(options)) { tools.assign(extensionConfig[name], options); } else { extensionConfig[name] = _config(); } } else { extensionConfig[name] = _config(options); } } }, false ); } tools.assign(nj, { extensions, extensionConfig, registerExtension });