mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-14 18:10:53 +00:00
4.0.0 Beta 1
This commit is contained in:
parent
c2688646af
commit
262757a20d
187 changed files with 22878 additions and 38882 deletions
149
src/utilities/dom.js
Normal file
149
src/utilities/dom.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
'use strict';
|
||||
|
||||
import {has} from 'utilities/object';
|
||||
|
||||
const ATTRS = [
|
||||
'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'async',
|
||||
'autocomplete', 'autofocus', 'autoplay', 'bgcolor', 'border', 'buffered',
|
||||
'challenge', 'charset', 'checked', 'cite', 'class', 'code', 'codebase',
|
||||
'color', 'cols', 'colspan', 'content', 'contenteditable', 'contextmenu',
|
||||
'controls', 'coords', 'crossorigin', 'data', 'data-*', 'datetime',
|
||||
'default', 'defer', 'dir', 'dirname', 'disabled', 'download', 'draggable',
|
||||
'dropzone', 'enctype', 'for', 'form', 'formaction', 'headers', 'height',
|
||||
'hidden', 'high', 'href', 'hreflang', 'http-equiv', 'icon', 'id',
|
||||
'integrity', 'ismap', 'itemprop', 'keytype', 'kind', 'label', 'lang',
|
||||
'language', 'list', 'loop', 'low', 'manifest', 'max', 'maxlength',
|
||||
'minlength', 'media', 'method', 'min', 'multiple', 'muted', 'name',
|
||||
'novalidate', 'open', 'optimum', 'pattern', 'ping', 'placeholder', 'poster',
|
||||
'preload', 'radiogroup', 'readonly', 'rel', 'required', 'reversed', 'rows',
|
||||
'rowspan', 'sandbox', 'scope', 'scoped', 'seamless', 'selected', 'shape',
|
||||
'size', 'sizes', 'slot', 'span', 'spellcheck', 'src', 'srcdoc', 'srclang',
|
||||
'srcset', 'start', 'step', 'style', 'summary', 'tabindex', 'target',
|
||||
'title', 'type', 'usemap', 'value', 'width', 'wrap'
|
||||
];
|
||||
|
||||
|
||||
const range = document.createRange();
|
||||
|
||||
function camelCase(name) {
|
||||
return name.replace(/[-_]\w/g, m => m[1].toUpperCase());
|
||||
}
|
||||
|
||||
|
||||
export function createElement(tag, props, children, no_sanitize) {
|
||||
const el = document.createElement(tag);
|
||||
|
||||
if ( typeof props === 'string' )
|
||||
el.className = props;
|
||||
else if ( props )
|
||||
for(const key in props)
|
||||
if ( has(props, key) ) {
|
||||
const lk = key.toLowerCase(),
|
||||
prop = props[key];
|
||||
|
||||
if ( lk === 'style' ) {
|
||||
if ( typeof prop === 'string' )
|
||||
el.style.cssText = prop;
|
||||
else
|
||||
for(const k in prop)
|
||||
if ( has(prop, k) )
|
||||
el.style[k] = prop[k];
|
||||
|
||||
} else if ( lk === 'dataset' ) {
|
||||
for(const k in prop)
|
||||
if ( has(prop, k) )
|
||||
el.dataset[camelCase(k)] = prop[k];
|
||||
|
||||
} else if ( key === 'dangerouslySetInnerHTML' ) {
|
||||
// React compatibility is cool. SeemsGood
|
||||
if ( prop && prop.__html )
|
||||
el.innerHTML = prop.__html;
|
||||
|
||||
} else if ( lk.startsWith('on') )
|
||||
el.addEventListener(lk.slice(2), prop);
|
||||
|
||||
else if ( lk.startsWith('data-') )
|
||||
el.dataset[camelCase(lk.slice(5))] = prop;
|
||||
|
||||
else if ( lk.startsWith('aria-') || ATTRS.includes(lk) )
|
||||
el.setAttribute(key, prop);
|
||||
|
||||
else
|
||||
el[key] = props[key];
|
||||
}
|
||||
|
||||
if ( children )
|
||||
setChildren(el, children, no_sanitize);
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
export function setChildren(el, children, no_sanitize) {
|
||||
if ( typeof children === 'string' ) {
|
||||
if ( no_sanitize )
|
||||
el.innerHTML = children;
|
||||
else
|
||||
el.textContent = children;
|
||||
|
||||
} else if ( Array.isArray(children) ) {
|
||||
for(const child of children)
|
||||
if ( typeof child === 'string' )
|
||||
el.appendChild(no_sanitize ?
|
||||
range.createContextualFragment(child) :
|
||||
document.createTextNode(child)
|
||||
);
|
||||
|
||||
else if ( child )
|
||||
el.appendChild(child);
|
||||
|
||||
} else if ( children )
|
||||
el.appendChild(children);
|
||||
}
|
||||
|
||||
|
||||
const el = createElement('span');
|
||||
|
||||
export function sanitize(text) {
|
||||
el.textContent = text;
|
||||
return el.innerHTML;
|
||||
}
|
||||
|
||||
|
||||
let last_id = 0;
|
||||
|
||||
export class ManagedStyle {
|
||||
constructor(id) {
|
||||
this.id = id || last_id++;
|
||||
|
||||
this._blocks = {};
|
||||
|
||||
this._style = createElement('style', {
|
||||
type: 'text/css',
|
||||
id: `ffz--managed-style--${this.id}`
|
||||
});
|
||||
|
||||
document.head.appendChild(this._style);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
document.head.removeChild(this._style);
|
||||
this._blocks = null;
|
||||
this._style = null;
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
let block = this._blocks[key];
|
||||
if ( block )
|
||||
block.textContent = value;
|
||||
else
|
||||
this._style.appendChild(this._blocks[key] = document.createTextNode(value));
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const block = this._blocks[key];
|
||||
if ( block ) {
|
||||
this._style.removeChild(block);
|
||||
this._blocks[key] = null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue