7ca1c363aaacefefbd00139e8b265a2abfb0b9ffdd576780c97f178ba4eb943874c48778216d6403e3d7d7106a407e2a31d172ad699aaa9c8aef771bdfb477 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { ie, ios } from "./browser.js"
  2. export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
  3. export let rmClass = function(node, cls) {
  4. let current = node.className
  5. let match = classTest(cls).exec(current)
  6. if (match) {
  7. let after = current.slice(match.index + match[0].length)
  8. node.className = current.slice(0, match.index) + (after ? match[1] + after : "")
  9. }
  10. }
  11. export function removeChildren(e) {
  12. for (let count = e.childNodes.length; count > 0; --count)
  13. e.removeChild(e.firstChild)
  14. return e
  15. }
  16. export function removeChildrenAndAdd(parent, e) {
  17. return removeChildren(parent).appendChild(e)
  18. }
  19. export function elt(tag, content, className, style) {
  20. let e = document.createElement(tag)
  21. if (className) e.className = className
  22. if (style) e.style.cssText = style
  23. if (typeof content == "string") e.appendChild(document.createTextNode(content))
  24. else if (content) for (let i = 0; i < content.length; ++i) e.appendChild(content[i])
  25. return e
  26. }
  27. // wrapper for elt, which removes the elt from the accessibility tree
  28. export function eltP(tag, content, className, style) {
  29. let e = elt(tag, content, className, style)
  30. e.setAttribute("role", "presentation")
  31. return e
  32. }
  33. export let range
  34. if (document.createRange) range = function(node, start, end, endNode) {
  35. let r = document.createRange()
  36. r.setEnd(endNode || node, end)
  37. r.setStart(node, start)
  38. return r
  39. }
  40. else range = function(node, start, end) {
  41. let r = document.body.createTextRange()
  42. try { r.moveToElementText(node.parentNode) }
  43. catch(e) { return r }
  44. r.collapse(true)
  45. r.moveEnd("character", end)
  46. r.moveStart("character", start)
  47. return r
  48. }
  49. export function contains(parent, child) {
  50. if (child.nodeType == 3) // Android browser always returns false when child is a textnode
  51. child = child.parentNode
  52. if (parent.contains)
  53. return parent.contains(child)
  54. do {
  55. if (child.nodeType == 11) child = child.host
  56. if (child == parent) return true
  57. } while (child = child.parentNode)
  58. }
  59. export function activeElt(rootNode) {
  60. // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
  61. // IE < 10 will throw when accessed while the page is loading or in an iframe.
  62. // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
  63. let doc = rootNode.ownerDocument || rootNode
  64. let activeElement
  65. try {
  66. activeElement = rootNode.activeElement
  67. } catch(e) {
  68. activeElement = doc.body || null
  69. }
  70. while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
  71. activeElement = activeElement.shadowRoot.activeElement
  72. return activeElement
  73. }
  74. export function addClass(node, cls) {
  75. let current = node.className
  76. if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls
  77. }
  78. export function joinClasses(a, b) {
  79. let as = a.split(" ")
  80. for (let i = 0; i < as.length; i++)
  81. if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]
  82. return b
  83. }
  84. export let selectInput = function(node) { node.select() }
  85. if (ios) // Mobile Safari apparently has a bug where select() is broken.
  86. selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length }
  87. else if (ie) // Suppress mysterious IE10 errors
  88. selectInput = function(node) { try { node.select() } catch(_e) {} }
  89. export function doc(cm) { return cm.display.wrapper.ownerDocument }
  90. export function root(cm) {
  91. return rootNode(cm.display.wrapper)
  92. }
  93. export function rootNode(element) {
  94. // Detect modern browsers (2017+).
  95. return element.getRootNode ? element.getRootNode() : element.ownerDocument
  96. }
  97. export function win(cm) { return doc(cm).defaultView }