146 lines
3.5 KiB
JavaScript
146 lines
3.5 KiB
JavaScript
import { addMethodNames } from './methods.js'
|
|
import { capitalize } from './utils.js'
|
|
import { svg } from '../modules/core/namespaces.js'
|
|
import { globals } from '../utils/window.js'
|
|
import Base from '../types/Base.js'
|
|
|
|
const elements = {}
|
|
export const root = '___SYMBOL___ROOT___'
|
|
|
|
// Method for element creation
|
|
export function create(name, ns = svg) {
|
|
// create element
|
|
return globals.document.createElementNS(ns, name)
|
|
}
|
|
|
|
export function makeInstance(element, isHTML = false) {
|
|
if (element instanceof Base) return element
|
|
|
|
if (typeof element === 'object') {
|
|
return adopter(element)
|
|
}
|
|
|
|
if (element == null) {
|
|
return new elements[root]()
|
|
}
|
|
|
|
if (typeof element === 'string' && element.charAt(0) !== '<') {
|
|
return adopter(globals.document.querySelector(element))
|
|
}
|
|
|
|
// Make sure, that HTML elements are created with the correct namespace
|
|
const wrapper = isHTML ? globals.document.createElement('div') : create('svg')
|
|
wrapper.innerHTML = element
|
|
|
|
// We can use firstChild here because we know,
|
|
// that the first char is < and thus an element
|
|
element = adopter(wrapper.firstChild)
|
|
|
|
// make sure, that element doesn't have its wrapper attached
|
|
wrapper.removeChild(wrapper.firstChild)
|
|
return element
|
|
}
|
|
|
|
export function nodeOrNew(name, node) {
|
|
return node &&
|
|
(node instanceof globals.window.Node ||
|
|
(node.ownerDocument &&
|
|
node instanceof node.ownerDocument.defaultView.Node))
|
|
? node
|
|
: create(name)
|
|
}
|
|
|
|
// Adopt existing svg elements
|
|
export function adopt(node) {
|
|
// check for presence of node
|
|
if (!node) return null
|
|
|
|
// make sure a node isn't already adopted
|
|
if (node.instance instanceof Base) return node.instance
|
|
|
|
if (node.nodeName === '#document-fragment') {
|
|
return new elements.Fragment(node)
|
|
}
|
|
|
|
// initialize variables
|
|
let className = capitalize(node.nodeName || 'Dom')
|
|
|
|
// Make sure that gradients are adopted correctly
|
|
if (className === 'LinearGradient' || className === 'RadialGradient') {
|
|
className = 'Gradient'
|
|
|
|
// Fallback to Dom if element is not known
|
|
} else if (!elements[className]) {
|
|
className = 'Dom'
|
|
}
|
|
|
|
return new elements[className](node)
|
|
}
|
|
|
|
let adopter = adopt
|
|
|
|
export function mockAdopt(mock = adopt) {
|
|
adopter = mock
|
|
}
|
|
|
|
export function register(element, name = element.name, asRoot = false) {
|
|
elements[name] = element
|
|
if (asRoot) elements[root] = element
|
|
|
|
addMethodNames(Object.getOwnPropertyNames(element.prototype))
|
|
|
|
return element
|
|
}
|
|
|
|
export function getClass(name) {
|
|
return elements[name]
|
|
}
|
|
|
|
// Element id sequence
|
|
let did = 1000
|
|
|
|
// Get next named element id
|
|
export function eid(name) {
|
|
return 'Svgjs' + capitalize(name) + did++
|
|
}
|
|
|
|
// Deep new id assignment
|
|
export function assignNewId(node) {
|
|
// do the same for SVG child nodes as well
|
|
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
assignNewId(node.children[i])
|
|
}
|
|
|
|
if (node.id) {
|
|
node.id = eid(node.nodeName)
|
|
return node
|
|
}
|
|
|
|
return node
|
|
}
|
|
|
|
// Method for extending objects
|
|
export function extend(modules, methods) {
|
|
let key, i
|
|
|
|
modules = Array.isArray(modules) ? modules : [modules]
|
|
|
|
for (i = modules.length - 1; i >= 0; i--) {
|
|
for (key in methods) {
|
|
modules[i].prototype[key] = methods[key]
|
|
}
|
|
}
|
|
}
|
|
|
|
export function wrapWithAttrCheck(fn) {
|
|
return function (...args) {
|
|
const o = args[args.length - 1]
|
|
|
|
if (o && o.constructor === Object && !(o instanceof Array)) {
|
|
return fn.apply(this, args.slice(0, -1)).attr(o)
|
|
} else {
|
|
return fn.apply(this, args)
|
|
}
|
|
}
|
|
}
|