function createDOM(domObj) {
'use strict';
// 2017.03.12
var
dom = {},
eventTypes = ['click', 'focus', 'blur',
'mouseover', 'mouseout', 'submit', 'reset',
'keydown', 'keypress', 'keyup', 'change',
'mousedown', 'mouseup', 'dblclick'
],
cssPseudoClasses = ['hover', 'focus', 'active', 'checked'],
cssPseudoElements = ['after', 'before', 'firstLetter',
'firstLine', 'selection'
];
dom.delimiter = domObj.delimiter || '|';
if (Array.isArray(domObj)) {
dom = {
tag: 'FRAGMENT',
desc: domObj
};
} else if (typeof domObj === 'string') {
dom = Object.assign(dom, parseTag(domObj.replace(/\s\s+/g, ' ')));
} else if (typeof domObj === 'object') {
dom = Object.assign(dom, domObj);
}
if (dom.className) {
if (Array.isArray(dom.className)) {
dom.className = dom.className.join(' ');
}
dom.className = dom.className.replace(/,/g, ' ').replace(/\s\s+/g, ' ');
}
if (dom.tag) {
var parsedTag = parseTag(dom.tag);
if (parsedTag.className && dom.className) {
parsedTag.className += ' ' + dom.className;
}
dom = Object.assign(dom, parsedTag);
} else dom.tag = 'DIV';
if (dom.scopedCSS) {
var tmpScopedCSS = Object.assign({}, dom.scopedCSS);
delete dom.scopedCSS;
dom = {
tag: 'SPAN',
style: {
display: 'inline',
margin: 0,
padding: 0
},
className: scopeCSS(tmpScopedCSS),
desc: dom
};
}
var
cleanTag = dom.tag.trim().toUpperCase(),
elm = (cleanTag === 'FRAGMENT') ?
document.createDocumentFragment() : document.createElement(cleanTag);
eventTypes.forEach(function(etype) {
if (dom[etype]) {
if (!dom.events) dom.events = {};
dom.events[etype] = dom[etype];
delete dom[etype];
}
});
if (dom.html || dom.desc || dom.text) {
var appendCalls = {
html: function() {
elm.innerHTML = elm.innerHTML + dom.html;
},
text: function() {
elm.appendChild(document.createTextNode(dom.text));
},
desc: function() {
if (Array.isArray(dom.desc)) dom.desc.forEach(function(i) {
appendElm(i);
});
else appendElm(dom.desc);
}
};
Object.keys(dom).forEach(function(k) {
if (appendCalls.hasOwnProperty(k)) {
appendCalls[k]();
delete dom[k];
}
});
}
if (dom.style) {
if (typeof dom.style === 'string') {
setAttr('style', dom.style);
} else if (typeof dom.style === 'object') {
Object.keys(dom.style).forEach(function(s) {
elm.style[s] = isNumber(dom.style[s]) ? dom.style[s] += 'px' : dom.style[s];
});
}
delete dom.style;
}
if (dom.events) {
Object.keys(dom.events).forEach(function(evt) {
if (typeof window.addEventListener === 'function')
elm.addEventListener(evt, dom.events[evt], false);
else if (typeof window.attachEvent === 'function')
elm.attachEvent('on' + evt, dom.events[evt]);
else elm['on' + evt] = dom.events[evt];
if (dom.registerEvents) {
dom.registerEvents(elm, evt, dom.events[evt]);
}
});
delete dom.events;
delete dom.registerEvents;
}
delete dom.delimiter;
delete dom.tag;
Object.keys(dom).forEach(function(k) {
var prop = checkReplaceHash(k);
setAttr(prop, dom[k]);
});
return elm;
// Sub Functions
function isNumber(val) {
return Number(parseFloat(val)) === val;
}
function isElm(el) {
return (el.nodeType && el.nodeType === 1);
}
function appendElm(el) {
if (isElm(el)) elm.appendChild(el);
else {
var childElm = (typeof el === 'object') ?
Object.assign({}, el) : (typeof el === 'string') ?
Object.assign({}, parseTag(el.replace(/\s\s+/g, ' '))) : {};
childElm.delimiter = childElm.delimiter || dom.delimiter;
elm.appendChild(createDOM(childElm));
}
}
function setAttr(key, val) {
try {
if (key === 'class') {
val.split(' ').forEach(function(c) {
elm.classList.add(c);
});
} else elm.setAttribute(key, val);
} catch (err) {
console.log(err);
}
}
function makeUniqueKey() {
var num = 2;
var res = '';
while (!!num) {
var array = new Uint32Array(num);
window.crypto.getRandomValues(array);
for (var i = 0; i < array.length; i++) {
res += array[i].toString(36);
}
num--;
}
return '_' + res;
}
function camelToHyphen(s) {
var res = s.replace(/[a-z][A-Z]/g, function(str, offset) {
return str[0] + '-' + str[1].toLowerCase();
});
return res;
}
function jsToCSS(o) {
var res = '';
Object.keys(o).forEach(function(k) {
if (isNumber(o[k])) o[k] += 'px';
res = res.concat(camelToHyphen(k) + ':' + o[k] + ';');
});
return res;
}
function parseTag(str) {
var
attrs = str.split(dom.delimiter),
tagString = attrs.shift(),
res = {},
symHash = {
'.': 'className',
'#': 'id',
'~': 'name',
'^': 'type'
},
flags = Object.keys(symHash),
prop = 'tag',
classStart = false;
for (var ii = 0; ii < tagString.length; ii++) {
if (!flags.includes(tagString[ii])) {
if (prop === 'className' && classStart) {
res.className = res.className ? res.className + ' ' : '';
classStart = false;
}
res[prop] = res[prop] ? res[prop] + tagString[ii] : tagString[ii];
continue;
} else {
prop = symHash[tagString[ii]];
if (prop === 'className') classStart = true;
}
}
if (attrs.length > 0) {
attrs.forEach(function(kp) {
var p = kp.split('=');
if (p[0].trim() !== '') {
res[p[0].trim()] = (p[1] && p[1].trim) ? p[1].trim() : '';
}
});
}
res.tag = res.tag || 'DIV';
return res;
}
function createStyleSheet() {
if (document.getElementById('createDOM_Generated_Style_Sheet')) {
return document.getElementById('createDOM_Generated_Style_Sheet');
} else {
var style = createDOM({
tag: 'style',
type: 'text/css',
media: 'screen',
id: 'createDOM_Generated_Style_Sheet'
});
document.getElementsByTagName('head')[0].appendChild(style);
return style;
}
}
function writeStyleSheet(o) {
var style = createStyleSheet();
if (!(style.sheet || {}).insertRule) {
(style.styleSheet || style.sheet).addRule(o.name, o.rules);
} else {
style.appendChild(document.createTextNode(o.name + " {" + o.rules + "}"));
}
}
function writeKeyframes(keyframeObj, name) {
var style = createStyleSheet();
var str = name + '{';
Object.keys(keyframeObj).forEach(function(frame) {
str += frame + '{';
str += jsToCSS(keyframeObj[frame]) + '}';
});
str += '}';
style.appendChild(document.createTextNode(str));
}
function writeMediaQuery(cls, css, mediaObj) {
var style = createStyleSheet();
var str = mediaObj + '{';
Object.keys(css[mediaObj]).forEach(function(mediaRule) {
var mRule = css[mediaObj][mediaRule];
Object.keys(mRule).forEach(function(mr) {
if (cssPseudoClasses.includes(mr) || cssPseudoElements.includes(mr)) {
var colons = cssPseudoElements.includes(mr) ? '::' : ':';
str += '.' + cls + ' ' + mediaRule + colons + mr + ' ' + '{';
str += jsToCSS(css[mediaObj][mediaRule][mr]) + '}';
delete css[mediaObj][mediaRule][mr];
}
});
str += '.' + cls + ' ' + mediaRule + ' ' + '{';
str += jsToCSS(css[mediaObj][mediaRule]) + '}';
});
str += '}';
style.appendChild(document.createTextNode(str));
}
function scopeCSS(css) {
var rootClass = makeUniqueKey();
Object.keys(css).forEach(function(item) {
if (item.substr(0, '@keyframes'.length) === '@keyframes') {
writeKeyframes(css[item], item);
return;
}
if (item.substr(0, '@media'.length) === '@media') {
writeMediaQuery(rootClass, css, item);
return;
}
Object.keys(css[item]).forEach(function(prop) {
if (cssPseudoClasses.includes(prop) || cssPseudoElements.includes(prop)) {
var colons = cssPseudoElements.includes(prop) ? '::' : ':';
if (prop === 'selection') {
writeStyleSheet({
name: '.' + rootClass + ' ' + camelToHyphen(item) + colons + '-moz-' + camelToHyphen(prop),
rules: jsToCSS(css[item][prop])
});
}
writeStyleSheet({
name: '.' + rootClass + ' ' + camelToHyphen(item) + colons + camelToHyphen(prop),
rules: jsToCSS(css[item][prop])
});
delete css[item][prop];
return;
}
});
writeStyleSheet({
name: '.' + rootClass + ' ' + camelToHyphen(item.replace(/\$/g, ':')),
rules: jsToCSS(css[item])
});
return;
});
return rootClass;
}
function checkReplaceHash(prop) {
var replaceHash = {
'className': 'class',
'data_': 'data-',
'@': 'v-on:',
'v_on_': 'v-on:',
'v_bind_': 'v-bind:',
'v_if': 'v-if',
'v_for': 'v-for',
'v_text': 'v-text',
'v_html': 'v-html',
'v_else_if': 'v-else-if',
'v_else': 'v-else',
'v_show': 'v-show',
'v_pre': 'v-pre',
'v_model': 'v-model',
'v_once': 'v-once',
'v_cloak': 'v-cloak'
};
var res = prop;
Object.keys(replaceHash).forEach(function(k) {
if (prop.startsWith(k)) {
res = prop.replace(k, replaceHash[k]);
if (res.startsWith('v-on:') && res.includes('$')) {
res = res.replace(/\$/g, '.');
}
return;
}
});
return res;
}
}