/**
* @copyright 2020 Tridium, Inc. All Rights Reserved.
* @author Logan Byam
*/
/* eslint-env browser */
define([
'bajaux/spandrel/buildConfig',
'bajaux/spandrel/util',
'underscore' ], function (
buildConfig,
util,
_) {
'use strict';
const { $IS_SPANDREL_SYMBOL, $KEY_SYMBOL } = buildConfig;
const { isDynamic } = util;
const WIDGET_ATTRIBUTES = {
enabled: true,
formFactor: true,
properties: true,
readonly: true,
value: true
};
/**
* API Status: **Development**
* @exports bajaux/spandrel/jsx
*/
const exports = {};
/**
* @param {string|Function} type
* @param {object|null} props
* @param kids
* @returns {module:bajaux/spandrel~SpandrelArg}
*/
function jsxToSpandrel(type, props, kids) {
let dom, widgetType;
props = props || {};
const { spandrelKey, spandrelSrc } = props;
if (typeof type === 'string') {
dom = document.createElement(type);
} else {
dom = document.createElement(props.tagName || 'div');
widgetType = type;
}
setProps(dom, props, !!widgetType);
if (spandrelSrc) {
if (kids.length) {
throw new Error('spandrelSrc cannot be combined with children');
}
if (typeof type !== 'string') {
throw new Error('spandrelSrc can only be applied to a DOM element');
}
const sp = spandrelSrc.toSpandrel({ dom });
if (typeof sp === 'object' && !Array.isArray(sp)) {
sp[$IS_SPANDREL_SYMBOL] = true;
if (spandrelKey) {
sp[$KEY_SYMBOL] = spandrelKey;
}
}
return sp;
}
let { enabled, formFactor, properties, readonly, value } = props;
if (typeof enabled === 'string') { enabled = enabled !== 'false'; }
if (typeof readonly === 'string') { readonly = readonly !== 'false'; }
if (typeof value === 'undefined' && isDynamic(type)) { value = null; }
if (!kids.length) {
kids = undefined;
} else {
kids.forEach((kid, i) => {
if (!kid) {
return;
}
if (typeof kid === 'string') {
dom.appendChild(document.createTextNode(kid));
kids = undefined;
} else {
kid.key = kid.key || String(i);
}
});
}
return {
[$IS_SPANDREL_SYMBOL]: true,
[$KEY_SYMBOL]: spandrelKey,
dom,
enabled,
formFactor,
kids,
properties,
readonly,
type: widgetType,
value
};
}
function setProps(el, props, isWidget) {
Object.keys(props).forEach((name) => setProp(el, name, props[name], isWidget));
}
function setProp(el, name, value, isWidget) {
if (isWidget && WIDGET_ATTRIBUTES[name]) {
return;
}
if (name === '$init') { return value(el); }
if (name === 'spandrelKey' || name === 'spandrelSrc') { return; }
if (name === 'className') { name = 'class'; }
if (name === 'style' && typeof value === 'object') {
const { style } = el;
Object.keys(value).forEach((prop) => { style[prop] = value[prop]; });
} else if (typeof value === 'boolean') {
if (value) { el.setAttribute(name, true); }
el[name] = value;
} else {
el.setAttribute(name, value);
}
}
/**
* @param {string|Function} type HTML tag name, or a Widget constructor to instantiate
* @param {object|null} props
* @param {Array.<object>} children
* @returns {module:bajaux/spandrel~SpandrelArg}
*
* @example
* <caption>Basic JSX->spandrel example</caption>
* %** @jsx spandrel.jsx *%
* class ComponentToHTML extends spandrel((comp) => {
* return (
* <table>
* {
* comp.getSlots().properties().toArray().map((prop) => {
* return <tr>
* <td>{ prop.getName() }</td>
* <td>{ prop.getType() }</td>
* </tr>;
* })
* }
* </table>
* );
* }) {}
*/
exports.jsxToSpandrel = function (type, props, ...children) {
return jsxToSpandrel(type, props, _.flatten(children));
};
return exports;
});