You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

adopter.js 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { addMethodNames } from './methods.js'
  2. import { capitalize } from './utils.js'
  3. import { svg } from '../modules/core/namespaces.js'
  4. import { globals } from '../utils/window.js'
  5. import Base from '../types/Base.js'
  6. const elements = {}
  7. export const root = '___SYMBOL___ROOT___'
  8. // Method for element creation
  9. export function create(name, ns = svg) {
  10. // create element
  11. return globals.document.createElementNS(ns, name)
  12. }
  13. export function makeInstance(element, isHTML = false) {
  14. if (element instanceof Base) return element
  15. if (typeof element === 'object') {
  16. return adopter(element)
  17. }
  18. if (element == null) {
  19. return new elements[root]()
  20. }
  21. if (typeof element === 'string' && element.charAt(0) !== '<') {
  22. return adopter(globals.document.querySelector(element))
  23. }
  24. // Make sure, that HTML elements are created with the correct namespace
  25. const wrapper = isHTML ? globals.document.createElement('div') : create('svg')
  26. wrapper.innerHTML = element
  27. // We can use firstChild here because we know,
  28. // that the first char is < and thus an element
  29. element = adopter(wrapper.firstChild)
  30. // make sure, that element doesn't have its wrapper attached
  31. wrapper.removeChild(wrapper.firstChild)
  32. return element
  33. }
  34. export function nodeOrNew(name, node) {
  35. return node &&
  36. (node instanceof globals.window.Node ||
  37. (node.ownerDocument &&
  38. node instanceof node.ownerDocument.defaultView.Node))
  39. ? node
  40. : create(name)
  41. }
  42. // Adopt existing svg elements
  43. export function adopt(node) {
  44. // check for presence of node
  45. if (!node) return null
  46. // make sure a node isn't already adopted
  47. if (node.instance instanceof Base) return node.instance
  48. if (node.nodeName === '#document-fragment') {
  49. return new elements.Fragment(node)
  50. }
  51. // initialize variables
  52. let className = capitalize(node.nodeName || 'Dom')
  53. // Make sure that gradients are adopted correctly
  54. if (className === 'LinearGradient' || className === 'RadialGradient') {
  55. className = 'Gradient'
  56. // Fallback to Dom if element is not known
  57. } else if (!elements[className]) {
  58. className = 'Dom'
  59. }
  60. return new elements[className](node)
  61. }
  62. let adopter = adopt
  63. export function mockAdopt(mock = adopt) {
  64. adopter = mock
  65. }
  66. export function register(element, name = element.name, asRoot = false) {
  67. elements[name] = element
  68. if (asRoot) elements[root] = element
  69. addMethodNames(Object.getOwnPropertyNames(element.prototype))
  70. return element
  71. }
  72. export function getClass(name) {
  73. return elements[name]
  74. }
  75. // Element id sequence
  76. let did = 1000
  77. // Get next named element id
  78. export function eid(name) {
  79. return 'Svgjs' + capitalize(name) + did++
  80. }
  81. // Deep new id assignment
  82. export function assignNewId(node) {
  83. // do the same for SVG child nodes as well
  84. for (let i = node.children.length - 1; i >= 0; i--) {
  85. assignNewId(node.children[i])
  86. }
  87. if (node.id) {
  88. node.id = eid(node.nodeName)
  89. return node
  90. }
  91. return node
  92. }
  93. // Method for extending objects
  94. export function extend(modules, methods) {
  95. let key, i
  96. modules = Array.isArray(modules) ? modules : [modules]
  97. for (i = modules.length - 1; i >= 0; i--) {
  98. for (key in methods) {
  99. modules[i].prototype[key] = methods[key]
  100. }
  101. }
  102. }
  103. export function wrapWithAttrCheck(fn) {
  104. return function (...args) {
  105. const o = args[args.length - 1]
  106. if (o && o.constructor === Object && !(o instanceof Array)) {
  107. return fn.apply(this, args.slice(0, -1)).attr(o)
  108. } else {
  109. return fn.apply(this, args)
  110. }
  111. }
  112. }