-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix whitespace creation * fix browser rendering * use pelo * rm unused deps * fixup! clean up files field * fixup! pull in pelo code * fixup! rm more global calls * detect if running in Electron * split off regexes
- Loading branch information
1 parent
3a05345
commit 672ebab
Showing
6 changed files
with
235 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
var hyperx = require('hyperx') | ||
var onload = require('on-load') | ||
|
||
var headRegex = /^\n[\s]+/ | ||
var tailRegex = /\n[\s]+$/ | ||
|
||
var SVGNS = 'http://www.w3.org/2000/svg' | ||
var XLINKNS = 'http://www.w3.org/1999/xlink' | ||
|
||
var BOOL_PROPS = { | ||
autofocus: 1, | ||
checked: 1, | ||
defaultchecked: 1, | ||
disabled: 1, | ||
formnovalidate: 1, | ||
indeterminate: 1, | ||
readonly: 1, | ||
required: 1, | ||
selected: 1, | ||
willvalidate: 1 | ||
} | ||
var COMMENT_TAG = '!--' | ||
var SVG_TAGS = [ | ||
'svg', | ||
'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', | ||
'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', | ||
'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', | ||
'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', | ||
'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', | ||
'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', | ||
'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', | ||
'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', | ||
'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', | ||
'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 'line', | ||
'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 'mpath', | ||
'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', | ||
'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', | ||
'tspan', 'use', 'view', 'vkern' | ||
] | ||
|
||
function belCreateElement (tag, props, children) { | ||
var el | ||
|
||
// If an svg tag, it needs a namespace | ||
if (SVG_TAGS.indexOf(tag) !== -1) { | ||
props.namespace = SVGNS | ||
} | ||
|
||
// If we are using a namespace | ||
var ns = false | ||
if (props.namespace) { | ||
ns = props.namespace | ||
delete props.namespace | ||
} | ||
|
||
// Create the element | ||
if (ns) { | ||
el = document.createElementNS(ns, tag) | ||
} else if (tag === COMMENT_TAG) { | ||
return document.createComment(props.comment) | ||
} else { | ||
el = document.createElement(tag) | ||
} | ||
|
||
// If adding onload events | ||
if (props.onload || props.onunload) { | ||
var load = props.onload || function () {} | ||
var unload = props.onunload || function () {} | ||
onload(el, function belOnload () { | ||
load(el) | ||
}, function belOnunload () { | ||
unload(el) | ||
}, | ||
// We have to use non-standard `caller` to find who invokes `belCreateElement` | ||
belCreateElement.caller.caller.caller) | ||
delete props.onload | ||
delete props.onunload | ||
} | ||
|
||
// Create the properties | ||
for (var p in props) { | ||
if (props.hasOwnProperty(p)) { | ||
var key = p.toLowerCase() | ||
var val = props[p] | ||
// Normalize className | ||
if (key === 'classname') { | ||
key = 'class' | ||
p = 'class' | ||
} | ||
// The for attribute gets transformed to htmlFor, but we just set as for | ||
if (p === 'htmlFor') { | ||
p = 'for' | ||
} | ||
// If a property is boolean, set itself to the key | ||
if (BOOL_PROPS[key]) { | ||
if (val === 'true') val = key | ||
else if (val === 'false') continue | ||
} | ||
// If a property prefers being set directly vs setAttribute | ||
if (key.slice(0, 2) === 'on') { | ||
el[p] = val | ||
} else { | ||
if (ns) { | ||
if (p === 'xlink:href') { | ||
el.setAttributeNS(XLINKNS, p, val) | ||
} else if (/^xmlns($|:)/i.test(p)) { | ||
// skip xmlns definitions | ||
} else { | ||
el.setAttributeNS(null, p, val) | ||
} | ||
} else { | ||
el.setAttribute(p, val) | ||
} | ||
} | ||
} | ||
} | ||
|
||
function appendChild (childs) { | ||
if (!Array.isArray(childs)) return | ||
var hadText = false | ||
for (var i = 0, len = childs.length; i < len; i++) { | ||
var node = childs[i] | ||
if (Array.isArray(node)) { | ||
appendChild(node) | ||
continue | ||
} | ||
|
||
if (typeof node === 'number' || | ||
typeof node === 'boolean' || | ||
typeof node === 'function' || | ||
node instanceof Date || | ||
node instanceof RegExp) { | ||
node = node.toString() | ||
} | ||
|
||
var lastChild = el.childNodes[el.childNodes.length - 1] | ||
if (typeof node === 'string') { | ||
hadText = true | ||
if (lastChild && lastChild.nodeName === '#text') { | ||
lastChild.nodeValue += node | ||
} else { | ||
node = document.createTextNode(node) | ||
el.appendChild(node) | ||
lastChild = node | ||
} | ||
if (i === len - 1) { | ||
hadText = false | ||
var value = lastChild.nodeValue | ||
.replace(headRegex, '') | ||
.replace(tailRegex, '') | ||
if (value !== '') lastChild.nodeValue = value | ||
else el.removeChild(lastChild) | ||
} | ||
} else if (node && node.nodeType) { | ||
if (hadText) { | ||
hadText = false | ||
var val = lastChild.nodeValue | ||
.replace(headRegex, '') | ||
.replace(tailRegex, '') | ||
if (val !== '') lastChild.nodeValue = val | ||
else el.removeChild(lastChild) | ||
} | ||
el.appendChild(node) | ||
} | ||
} | ||
} | ||
appendChild(children) | ||
|
||
return el | ||
} | ||
|
||
module.exports = hyperx(belCreateElement, {comments: true}) | ||
module.exports.default = module.exports | ||
module.exports.createElement = belCreateElement |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,53 @@ | ||
var document = require('global/document') | ||
var hyperx = require('hyperx') | ||
var onload = require('on-load') | ||
|
||
var SVGNS = 'http://www.w3.org/2000/svg' | ||
var XLINKNS = 'http://www.w3.org/1999/xlink' | ||
|
||
var BOOL_PROPS = { | ||
autofocus: 1, | ||
checked: 1, | ||
defaultchecked: 1, | ||
disabled: 1, | ||
formnovalidate: 1, | ||
indeterminate: 1, | ||
readonly: 1, | ||
required: 1, | ||
selected: 1, | ||
willvalidate: 1 | ||
// See https://github.com/shuhei/pelo/issues/5 | ||
var isElectron = require('is-electron') | ||
var browser = require('./browser') | ||
|
||
if (typeof window !== 'undefined' && isElectron()) { | ||
module.exports = browser | ||
} else { | ||
module.exports = stringify | ||
} | ||
var COMMENT_TAG = '!--' | ||
var SVG_TAGS = [ | ||
'svg', | ||
'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', | ||
'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', | ||
'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', | ||
'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', | ||
'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', | ||
'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', | ||
'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', | ||
'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', | ||
'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', | ||
'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 'line', | ||
'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 'mpath', | ||
'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', | ||
'set', 'stop', 'switch', 'symbol', 'text', 'textPath', 'title', 'tref', | ||
'tspan', 'use', 'view', 'vkern' | ||
] | ||
|
||
function belCreateElement (tag, props, children) { | ||
var el | ||
|
||
// If an svg tag, it needs a namespace | ||
if (SVG_TAGS.indexOf(tag) !== -1) { | ||
props.namespace = SVGNS | ||
function handleValue (value) { | ||
if (Array.isArray(value)) { | ||
// Suppose that each item is a result of html``. | ||
return value.join('') | ||
} | ||
|
||
// If we are using a namespace | ||
var ns = false | ||
if (props.namespace) { | ||
ns = props.namespace | ||
delete props.namespace | ||
// Ignore event handlers. | ||
// onclick=${(e) => doSomething(e)} | ||
// will become | ||
// onclick="" | ||
if (typeof value === 'function') { | ||
return '""' | ||
} | ||
|
||
// Create the element | ||
if (ns) { | ||
el = document.createElementNS(ns, tag) | ||
} else if (tag === COMMENT_TAG) { | ||
return document.createComment(props.comment) | ||
} else { | ||
el = document.createElement(tag) | ||
if (value === null || value === undefined) { | ||
return '' | ||
} | ||
|
||
// If adding onload events | ||
if (props.onload || props.onunload) { | ||
var load = props.onload || function () {} | ||
var unload = props.onunload || function () {} | ||
onload(el, function belOnload () { | ||
load(el) | ||
}, function belOnunload () { | ||
unload(el) | ||
}, | ||
// We have to use non-standard `caller` to find who invokes `belCreateElement` | ||
belCreateElement.caller.caller.caller) | ||
delete props.onload | ||
delete props.onunload | ||
if (value.__encoded) { | ||
return value | ||
} | ||
var str = value.toString() | ||
return str | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, ''') | ||
} | ||
|
||
// Create the properties | ||
for (var p in props) { | ||
if (props.hasOwnProperty(p)) { | ||
var key = p.toLowerCase() | ||
var val = props[p] | ||
// Normalize className | ||
if (key === 'classname') { | ||
key = 'class' | ||
p = 'class' | ||
} | ||
// The for attribute gets transformed to htmlFor, but we just set as for | ||
if (p === 'htmlFor') { | ||
p = 'for' | ||
} | ||
// If a property is boolean, set itself to the key | ||
if (BOOL_PROPS[key]) { | ||
if (val === 'true') val = key | ||
else if (val === 'false') continue | ||
} | ||
// If a property prefers being set directly vs setAttribute | ||
if (key.slice(0, 2) === 'on') { | ||
el[p] = val | ||
} else { | ||
if (ns) { | ||
if (p === 'xlink:href') { | ||
el.setAttributeNS(XLINKNS, p, val) | ||
} else if (/^xmlns($|:)/i.test(p)) { | ||
// skip xmlns definitions | ||
} else { | ||
el.setAttributeNS(null, p, val) | ||
} | ||
} else { | ||
el.setAttribute(p, val) | ||
} | ||
} | ||
} | ||
} | ||
|
||
function appendChild (childs) { | ||
if (!Array.isArray(childs)) return | ||
for (var i = 0; i < childs.length; i++) { | ||
var node = childs[i] | ||
if (Array.isArray(node)) { | ||
appendChild(node) | ||
continue | ||
} | ||
|
||
if (typeof node === 'number' || | ||
typeof node === 'boolean' || | ||
typeof node === 'function' || | ||
node instanceof Date || | ||
node instanceof RegExp) { | ||
node = node.toString() | ||
} | ||
|
||
if (typeof node === 'string') { | ||
if (/^[\n\r\s]+$/.test(node)) continue | ||
if (el.lastChild && el.lastChild.nodeName === '#text') { | ||
el.lastChild.nodeValue += node | ||
continue | ||
} | ||
node = document.createTextNode(node) | ||
} | ||
|
||
if (node && node.nodeType) { | ||
el.appendChild(node) | ||
} | ||
function stringify () { | ||
var pieces = arguments[0] | ||
var output = '' | ||
for (var i = 0; i < pieces.length; i++) { | ||
output += pieces[i] | ||
if (i < pieces.length - 1) { | ||
output += handleValue(arguments[i + 1]) | ||
} | ||
} | ||
appendChild(children) | ||
|
||
return el | ||
// HACK: Avoid double encoding by marking encoded string | ||
// You cannot add properties to string literals | ||
// eslint-disable-next-line no-new-wrappers | ||
var wrapper = new String(output) | ||
wrapper.__encoded = true | ||
return wrapper | ||
} | ||
|
||
module.exports = hyperx(belCreateElement, {comments: true}) | ||
module.exports.default = module.exports | ||
module.exports.createElement = belCreateElement |
Oops, something went wrong.