radi
Version:
**Radi** is a tiny javascript framework.
207 lines (178 loc) • 6.71 kB
JavaScript
/* eslint-disable no-continue */
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-param-reassign */
import setStyles from './setStyles';
import Listener from '../listen/Listener';
import parseClass from './utils/parseClass';
import GLOBALS from '../consts/GLOBALS';
// import AttributeListener from './utils/AttributeListener';
/**
* @param {Structure} structure
* @param {object} propsSource
* @param {object} oldPropsSource
*/
const setAttributes = (structure, propsSource = {}, oldPropsSource = {}) => {
const props = propsSource || {};
const oldProps = oldPropsSource || {};
if (!structure.html || !structure.html[0]) return structure;
const element = structure.html[0];
if (!(element instanceof Node && element.nodeType !== 3)) return structure;
const toRemove = Object.keys(oldProps)
.filter(key => typeof props[key] === 'undefined');
for (const prop in props) {
if (props.hasOwnProperty(prop)) {
// Skip if proprs are the same
if (typeof oldProps !== 'undefined' && oldProps[prop] === props[prop]) continue;
if (prop === 'checked') {
element.checked = props[prop];
}
// Need to remove falsy attribute
if (!props[prop] && typeof props[prop] !== 'number' && typeof props[prop] !== 'string') {
element.removeAttribute(prop);
continue;
}
// Handle Listeners
if (props[prop] instanceof Listener) {
if (typeof structure.$attrListeners[prop] !== 'undefined') continue;
structure.$attrListeners[prop] = props[prop];
props[prop].applyDepth(structure.depth).init();
if (prop.toLowerCase() === 'model' || prop.toLowerCase() === 'checked') {
if (element.getAttribute('type') === 'radio') {
element.addEventListener('input', (e) => {
structure.$attrListeners[prop].updateValue(
(e.target.checked && e.target.value)
|| e.target.checked
);
}, false);
structure.$attrListeners[prop].onValueChange(value => {
setAttributes(structure, {
checked: element.value === value && Boolean(value),
}, {});
});
} else
if (element.getAttribute('type') === 'checkbox') {
element.addEventListener('input', (e) => {
structure.$attrListeners[prop].updateValue(
Boolean(e.target.checked)
);
}, false);
structure.$attrListeners[prop].onValueChange(value => {
setAttributes(structure, {
checked: Boolean(value),
}, {});
});
} else {
element.addEventListener('input', (e) => {
structure.$attrListeners[prop].updateValue(e.target.value);
}, false);
}
}
if (!/(checkbox|radio)/.test(element.getAttribute('type'))) {
structure.$attrListeners[prop].onValueChange(value => {
setAttributes(structure, {
[prop]: value,
}, {});
});
}
// structure.setProps(Object.assign(structure.data.props, {
// [prop]: props[prop].value,
// }));
props[prop] = structure.$attrListeners[prop].value;
continue;
}
if (prop === 'value' || prop === 'model') {
element.value = props[prop];
}
if (typeof GLOBALS.CUSTOM_ATTRIBUTES[prop] !== 'undefined') {
const { allowedTags } = GLOBALS.CUSTOM_ATTRIBUTES[prop];
if (!allowedTags || (
allowedTags
&& allowedTags.length > 0
&& allowedTags.indexOf(element.localName) >= 0
)) {
if (typeof GLOBALS.CUSTOM_ATTRIBUTES[prop].caller === 'function') {
GLOBALS.CUSTOM_ATTRIBUTES[prop].caller(element, props[prop]);
}
if (!GLOBALS.CUSTOM_ATTRIBUTES[prop].addToElement) continue;
}
}
if (prop.toLowerCase() === 'style') {
if (typeof props[prop] === 'object') {
setStyles(structure, props[prop], (oldProps && oldProps.style) || {});
// props[prop] = structure.setStyles(props[prop], (oldProps && oldProps.style) || {});
} else {
element.style = props[prop];
}
continue;
}
if (prop.toLowerCase() === 'class' || prop.toLowerCase() === 'classname') {
element.setAttribute('class', parseClass(props[prop]));
continue;
}
if (prop.toLowerCase() === 'loadfocus') {
element.addEventListener('mount', () => {
element.focus();
}, false);
continue;
}
if (prop.toLowerCase() === 'html') {
element.innerHTML = props[prop];
continue;
}
// Handles events 'on<event>'
if (prop.substring(0, 2).toLowerCase() === 'on' && typeof props[prop] === 'function') {
const fn = props[prop];
if (prop.substring(0, 8).toLowerCase() === 'onsubmit') {
element[prop] = (e) => {
if (props.prevent) {
e.preventDefault();
}
const data = [];
const inputs = e.target.elements || [];
for (const input of inputs) {
if ((input.name !== ''
&& (input.type !== 'radio' && input.type !== 'checkbox'))
|| input.checked) {
const item = {
name: input.name,
el: input,
type: input.type,
default: input.defaultValue,
value: input.value,
set(val) {
if (structure && structure.el && structure.el.value) {
structure.el.value = val;
}
},
reset(val) {
if (structure && structure.el && structure.el.value) {
structure.el.value = val;
structure.el.defaultValue = val;
}
},
};
data.push(item);
if (!data[item.name]) {
Object.defineProperty(data, item.name, {
value: item,
});
}
}
}
return fn(e, data);
};
} else {
element[prop] = (e, ...args) => fn(e, ...args);
}
continue;
}
element.setAttribute(prop, props[prop]);
}
}
for (let i = 0; i < toRemove.length; i++) {
element.removeAttribute(toRemove[i]);
}
structure.props = props;
return structure;
};
export default setAttributes;