版博士V2.0程序
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

928 satır
29 KiB

  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. const Node_1 = __importDefault(require("../node/Node"));
  7. const ShadowRoot_1 = __importDefault(require("../shadow-root/ShadowRoot"));
  8. const Attr_1 = __importDefault(require("../attr/Attr"));
  9. const NamedNodeMap_1 = __importDefault(require("../../named-node-map/NamedNodeMap"));
  10. const DOMRect_1 = __importDefault(require("./DOMRect"));
  11. const DOMTokenList_1 = __importDefault(require("../../dom-token-list/DOMTokenList"));
  12. const QuerySelector_1 = __importDefault(require("../../query-selector/QuerySelector"));
  13. const MutationRecord_1 = __importDefault(require("../../mutation-observer/MutationRecord"));
  14. const MutationTypeEnum_1 = __importDefault(require("../../mutation-observer/MutationTypeEnum"));
  15. const NamespaceURI_1 = __importDefault(require("../../config/NamespaceURI"));
  16. const XMLParser_1 = __importDefault(require("../../xml-parser/XMLParser"));
  17. const XMLSerializer_1 = __importDefault(require("../../xml-serializer/XMLSerializer"));
  18. const ChildNodeUtility_1 = __importDefault(require("../child-node/ChildNodeUtility"));
  19. const ParentNodeUtility_1 = __importDefault(require("../parent-node/ParentNodeUtility"));
  20. const NonDocumentChildNodeUtility_1 = __importDefault(require("../child-node/NonDocumentChildNodeUtility"));
  21. const DOMException_1 = __importDefault(require("../../exception/DOMException"));
  22. const HTMLCollectionFactory_1 = __importDefault(require("./HTMLCollectionFactory"));
  23. const DOMRectListFactory_1 = __importDefault(require("./DOMRectListFactory"));
  24. /**
  25. * Element.
  26. */
  27. class Element extends Node_1.default {
  28. constructor() {
  29. super(...arguments);
  30. this.tagName = null;
  31. this.nodeType = Node_1.default.ELEMENT_NODE;
  32. this.shadowRoot = null;
  33. this.prefix = null;
  34. this.scrollTop = 0;
  35. this.scrollLeft = 0;
  36. this.children = HTMLCollectionFactory_1.default.create();
  37. this.namespaceURI = null;
  38. // Events
  39. this.oncancel = null;
  40. this.onerror = null;
  41. this.onscroll = null;
  42. this.onselect = null;
  43. this.onwheel = null;
  44. this.oncopy = null;
  45. this.oncut = null;
  46. this.onpaste = null;
  47. this.oncompositionend = null;
  48. this.oncompositionstart = null;
  49. this.oncompositionupdate = null;
  50. this.onblur = null;
  51. this.onfocus = null;
  52. this.onfocusin = null;
  53. this.onfocusout = null;
  54. this.onfullscreenchange = null;
  55. this.onfullscreenerror = null;
  56. this.onkeydown = null;
  57. this.onkeyup = null;
  58. this.onauxclick = null;
  59. this.onclick = null;
  60. this.oncontextmenu = null;
  61. this.ondblclick = null;
  62. this.onmousedown = null;
  63. this.onmouseenter = null;
  64. this.onmouseleave = null;
  65. this.onmousemove = null;
  66. this.onmouseout = null;
  67. this.onmouseover = null;
  68. this.onmouseup = null;
  69. this.ontouchcancel = null;
  70. this.ontouchend = null;
  71. this.ontouchmove = null;
  72. this.ontouchstart = null;
  73. // Used for being able to access closed shadow roots
  74. this._shadowRoot = null;
  75. this._attributes = {};
  76. this._classList = null;
  77. }
  78. /**
  79. * Returns class list.
  80. *
  81. * @returns Class list.
  82. */
  83. get classList() {
  84. if (!this._classList) {
  85. this._classList = new DOMTokenList_1.default(this, 'class');
  86. }
  87. return this._classList;
  88. }
  89. /**
  90. * Returns ID.
  91. *
  92. * @returns ID.
  93. */
  94. get id() {
  95. return this.getAttribute('id') || '';
  96. }
  97. /**
  98. * Sets ID.
  99. *
  100. * @param id ID.
  101. */
  102. set id(id) {
  103. this.setAttribute('id', id);
  104. }
  105. /**
  106. * Returns class name.
  107. *
  108. * @returns Class name.
  109. */
  110. get className() {
  111. return this.getAttribute('class') || '';
  112. }
  113. /**
  114. * Sets class name.
  115. *
  116. * @param className Class name.
  117. */
  118. set className(className) {
  119. this.setAttribute('class', className);
  120. }
  121. /**
  122. * Node name.
  123. *
  124. * @returns Node name.
  125. */
  126. get nodeName() {
  127. return this.tagName;
  128. }
  129. /**
  130. * Local name.
  131. *
  132. * @returns Local name.
  133. */
  134. get localName() {
  135. return this.tagName ? this.tagName.toLowerCase() : 'unknown';
  136. }
  137. /**
  138. * Previous element sibling.
  139. *
  140. * @returns Element.
  141. */
  142. get previousElementSibling() {
  143. return NonDocumentChildNodeUtility_1.default.previousElementSibling(this);
  144. }
  145. /**
  146. * Next element sibling.
  147. *
  148. * @returns Element.
  149. */
  150. get nextElementSibling() {
  151. return NonDocumentChildNodeUtility_1.default.nextElementSibling(this);
  152. }
  153. /**
  154. * Get text value of children.
  155. *
  156. * @returns Text content.
  157. */
  158. get textContent() {
  159. let result = '';
  160. for (const childNode of this.childNodes) {
  161. if (childNode.nodeType === Node_1.default.ELEMENT_NODE || childNode.nodeType === Node_1.default.TEXT_NODE) {
  162. result += childNode.textContent;
  163. }
  164. }
  165. return result;
  166. }
  167. /**
  168. * Sets text content.
  169. *
  170. * @param textContent Text content.
  171. */
  172. set textContent(textContent) {
  173. for (const child of this.childNodes.slice()) {
  174. this.removeChild(child);
  175. }
  176. if (textContent) {
  177. this.appendChild(this.ownerDocument.createTextNode(textContent));
  178. }
  179. }
  180. /**
  181. * Returns inner HTML.
  182. *
  183. * @returns HTML.
  184. */
  185. get innerHTML() {
  186. return this.getInnerHTML();
  187. }
  188. /**
  189. * Sets inner HTML.
  190. *
  191. * @param html HTML.
  192. */
  193. set innerHTML(html) {
  194. for (const child of this.childNodes.slice()) {
  195. this.removeChild(child);
  196. }
  197. for (const node of XMLParser_1.default.parse(this.ownerDocument, html).childNodes.slice()) {
  198. this.appendChild(node);
  199. }
  200. }
  201. /**
  202. * Returns outer HTML.
  203. *
  204. * @returns HTML.
  205. */
  206. get outerHTML() {
  207. return new XMLSerializer_1.default().serializeToString(this);
  208. }
  209. /**
  210. * Returns outer HTML.
  211. *
  212. * @param html HTML.
  213. */
  214. set outerHTML(html) {
  215. this.replaceWith(html);
  216. }
  217. /**
  218. * Returns attributes.
  219. *
  220. * @returns Attributes.
  221. */
  222. get attributes() {
  223. return Object.assign(new NamedNodeMap_1.default(this), Object.values(this._attributes), this._attributes);
  224. }
  225. /**
  226. * First element child.
  227. *
  228. * @returns Element.
  229. */
  230. get firstElementChild() {
  231. return this.children ? this.children[0] || null : null;
  232. }
  233. /**
  234. * Last element child.
  235. *
  236. * @returns Element.
  237. */
  238. get lastElementChild() {
  239. return this.children ? this.children[this.children.length - 1] || null : null;
  240. }
  241. /**
  242. * Last element child.
  243. *
  244. * @returns Element.
  245. */
  246. get childElementCount() {
  247. return this.children.length;
  248. }
  249. /**
  250. * Returns slot.
  251. *
  252. * @returns Slot.
  253. */
  254. get slot() {
  255. return this.getAttributeNS(null, 'slot') || '';
  256. }
  257. /**
  258. * Returns slot.
  259. *
  260. * @param slot Slot.
  261. */
  262. set slot(title) {
  263. this.setAttributeNS(null, 'slot', title);
  264. }
  265. /**
  266. * Returns inner HTML and optionally the content of shadow roots.
  267. *
  268. * This is a feature implemented in Chromium, but not supported by Mozilla yet.
  269. *
  270. * @see https://web.dev/declarative-shadow-dom/
  271. * @see https://chromestatus.com/feature/5191745052606464
  272. * @param [options] Options.
  273. * @param [options.includeShadowRoots] Set to "true" to include shadow roots.
  274. * @returns HTML.
  275. */
  276. getInnerHTML(options) {
  277. const xmlSerializer = new XMLSerializer_1.default();
  278. let xml = '';
  279. for (const node of this.childNodes) {
  280. xml += xmlSerializer.serializeToString(node, options);
  281. }
  282. return xml;
  283. }
  284. /**
  285. * Clones a node.
  286. *
  287. * @override
  288. * @param [deep=false] "true" to clone deep.
  289. * @returns Cloned node.
  290. */
  291. cloneNode(deep = false) {
  292. const clone = super.cloneNode(deep);
  293. Attr_1.default._ownerDocument = this.ownerDocument;
  294. for (const key of Object.keys(this._attributes)) {
  295. const attr = Object.assign(new Attr_1.default(), this._attributes[key]);
  296. attr.ownerElement = clone;
  297. clone._attributes[key] = attr;
  298. }
  299. if (deep) {
  300. for (const node of clone.childNodes) {
  301. if (node.nodeType === Node_1.default.ELEMENT_NODE) {
  302. clone.children.push(node);
  303. }
  304. }
  305. }
  306. clone.tagName = this.tagName;
  307. clone.scrollLeft = this.scrollLeft;
  308. clone.scrollTop = this.scrollTop;
  309. clone.namespaceURI = this.namespaceURI;
  310. return clone;
  311. }
  312. /**
  313. * @override
  314. */
  315. appendChild(node) {
  316. // If the type is DocumentFragment, then the child nodes of if it should be moved instead of the actual node.
  317. // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
  318. if (node.nodeType !== Node_1.default.DOCUMENT_FRAGMENT_NODE) {
  319. if (node.parentNode && node.parentNode['children']) {
  320. const index = node.parentNode['children'].indexOf(node);
  321. if (index !== -1) {
  322. node.parentNode['children'].splice(index, 1);
  323. }
  324. }
  325. if (node !== this && node.nodeType === Node_1.default.ELEMENT_NODE) {
  326. this.children.push(node);
  327. }
  328. }
  329. return super.appendChild(node);
  330. }
  331. /**
  332. * @override
  333. */
  334. removeChild(node) {
  335. if (node.nodeType === Node_1.default.ELEMENT_NODE) {
  336. const index = this.children.indexOf(node);
  337. if (index !== -1) {
  338. this.children.splice(index, 1);
  339. }
  340. }
  341. return super.removeChild(node);
  342. }
  343. /**
  344. * Removes the node from its parent.
  345. */
  346. remove() {
  347. ChildNodeUtility_1.default.remove(this);
  348. }
  349. /**
  350. * @override
  351. */
  352. insertBefore(newNode, referenceNode) {
  353. const returnValue = super.insertBefore(newNode, referenceNode);
  354. // If the type is DocumentFragment, then the child nodes of if it should be moved instead of the actual node.
  355. // See: https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
  356. if (newNode.nodeType !== Node_1.default.DOCUMENT_FRAGMENT_NODE) {
  357. if (newNode.parentNode && newNode.parentNode['children']) {
  358. const index = newNode.parentNode['children'].indexOf(newNode);
  359. if (index !== -1) {
  360. newNode.parentNode['children'].splice(index, 1);
  361. }
  362. }
  363. this.children.length = 0;
  364. for (const node of this.childNodes) {
  365. if (node.nodeType === Node_1.default.ELEMENT_NODE) {
  366. this.children.push(node);
  367. }
  368. }
  369. }
  370. return returnValue;
  371. }
  372. /**
  373. * The Node.replaceWith() method replaces this Node in the children list of its parent with a set of Node or DOMString objects.
  374. *
  375. * @param nodes List of Node or DOMString.
  376. */
  377. replaceWith(...nodes) {
  378. ChildNodeUtility_1.default.replaceWith(this, ...nodes);
  379. }
  380. /**
  381. * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just before this ChildNode. DOMString objects are inserted as equivalent Text nodes.
  382. *
  383. * @param nodes List of Node or DOMString.
  384. */
  385. before(...nodes) {
  386. ChildNodeUtility_1.default.before(this, ...nodes);
  387. }
  388. /**
  389. * Inserts a set of Node or DOMString objects in the children list of this ChildNode's parent, just after this ChildNode. DOMString objects are inserted as equivalent Text nodes.
  390. *
  391. * @param nodes List of Node or DOMString.
  392. */
  393. after(...nodes) {
  394. ChildNodeUtility_1.default.after(this, ...nodes);
  395. }
  396. /**
  397. * Inserts a set of Node objects or DOMString objects after the last child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.
  398. *
  399. * @param nodes List of Node or DOMString.
  400. */
  401. append(...nodes) {
  402. ParentNodeUtility_1.default.append(this, ...nodes);
  403. }
  404. /**
  405. * Inserts a set of Node objects or DOMString objects before the first child of the ParentNode. DOMString objects are inserted as equivalent Text nodes.
  406. *
  407. * @param nodes List of Node or DOMString.
  408. */
  409. prepend(...nodes) {
  410. ParentNodeUtility_1.default.prepend(this, ...nodes);
  411. }
  412. /**
  413. * Replaces the existing children of a node with a specified new set of children.
  414. *
  415. * @param nodes List of Node or DOMString.
  416. */
  417. replaceChildren(...nodes) {
  418. ParentNodeUtility_1.default.replaceChildren(this, ...nodes);
  419. }
  420. /**
  421. * Inserts a node to the given position.
  422. *
  423. * @param position Position to insert element.
  424. * @param element Node to insert.
  425. * @returns Inserted node or null if couldn't insert.
  426. */
  427. insertAdjacentElement(position, element) {
  428. if (position === 'beforebegin') {
  429. if (!this.parentElement) {
  430. return null;
  431. }
  432. this.parentElement.insertBefore(element, this);
  433. }
  434. else if (position === 'afterbegin') {
  435. this.insertBefore(element, this.firstChild);
  436. }
  437. else if (position === 'beforeend') {
  438. this.appendChild(element);
  439. }
  440. else if (position === 'afterend') {
  441. if (!this.parentElement) {
  442. return null;
  443. }
  444. this.parentElement.insertBefore(element, this.nextSibling);
  445. }
  446. return element;
  447. }
  448. /**
  449. * Inserts an HTML string to the given position.
  450. *
  451. * @param position Position to insert text.
  452. * @param text HTML string to insert.
  453. */
  454. insertAdjacentHTML(position, text) {
  455. for (const node of XMLParser_1.default.parse(this.ownerDocument, text).childNodes.slice()) {
  456. this.insertAdjacentElement(position, node);
  457. }
  458. }
  459. /**
  460. * Inserts text to the given position.
  461. *
  462. * @param position Position to insert text.
  463. * @param text String to insert.
  464. */
  465. insertAdjacentText(position, text) {
  466. if (!text) {
  467. return;
  468. }
  469. const textNode = this.ownerDocument.createTextNode(text);
  470. this.insertAdjacentElement(position, textNode);
  471. }
  472. /**
  473. * Sets an attribute.
  474. *
  475. * @param name Name.
  476. * @param value Value.
  477. */
  478. setAttribute(name, value) {
  479. const attribute = this.ownerDocument.createAttributeNS(null, name);
  480. attribute.value = String(value);
  481. this.setAttributeNode(attribute);
  482. }
  483. /**
  484. * Sets a namespace attribute.
  485. *
  486. * @param namespaceURI Namespace URI.
  487. * @param name Name.
  488. * @param value Value.
  489. */
  490. setAttributeNS(namespaceURI, name, value) {
  491. const attribute = this.ownerDocument.createAttributeNS(namespaceURI, name);
  492. attribute.value = String(value);
  493. this.setAttributeNode(attribute);
  494. }
  495. /**
  496. * Returns attribute names.
  497. *
  498. * @returns Attribute names.
  499. */
  500. getAttributeNames() {
  501. return Object.keys(this._attributes);
  502. }
  503. /**
  504. * Returns attribute value.
  505. *
  506. * @param name Name.
  507. */
  508. getAttribute(name) {
  509. const attribute = this.getAttributeNode(name);
  510. if (attribute) {
  511. return attribute.value;
  512. }
  513. return null;
  514. }
  515. /**
  516. * Toggle an attribute.
  517. * Returns `true` if attribute name is eventually present, and `false` otherwise.
  518. *
  519. * @param name A DOMString specifying the name of the attribute to be toggled.
  520. * @param force A boolean value to determine whether the attribute should be added or removed, no matter whether the attribute is present or not at the moment.
  521. */
  522. toggleAttribute(name, force) {
  523. name = name.toLowerCase();
  524. const attribute = this.getAttributeNode(name);
  525. if (attribute) {
  526. if (force === true) {
  527. return true;
  528. }
  529. this.removeAttributeNode(attribute);
  530. return false;
  531. }
  532. if (force === false) {
  533. return false;
  534. }
  535. this.setAttribute(name, '');
  536. return true;
  537. }
  538. /**
  539. * Returns namespace attribute value.
  540. *
  541. * @param namespace Namespace URI.
  542. * @param localName Local name.
  543. */
  544. getAttributeNS(namespace, localName) {
  545. const attribute = this.getAttributeNodeNS(namespace, localName);
  546. if (attribute) {
  547. return attribute.value;
  548. }
  549. return null;
  550. }
  551. /**
  552. * Returns a boolean value indicating whether the specified element has the attribute or not.
  553. *
  554. * @param name Attribute name.
  555. * @returns True if attribute exists, false otherwise.
  556. */
  557. hasAttribute(name) {
  558. return !!this.getAttributeNode(name);
  559. }
  560. /**
  561. * Returns a boolean value indicating whether the specified element has the namespace attribute or not.
  562. *
  563. * @param namespace Namespace URI.
  564. * @param localName Local name.
  565. * @returns True if attribute exists, false otherwise.
  566. */
  567. hasAttributeNS(namespace, localName) {
  568. for (const name of Object.keys(this._attributes)) {
  569. const attribute = this._attributes[name];
  570. if (attribute.namespaceURI === namespace && attribute.localName === localName) {
  571. return true;
  572. }
  573. }
  574. return false;
  575. }
  576. /**
  577. * Returns "true" if the element has attributes.
  578. *
  579. * @returns "true" if the element has attributes.
  580. */
  581. hasAttributes() {
  582. return Object.keys(this._attributes).length > 0;
  583. }
  584. /**
  585. * Removes an attribute.
  586. *
  587. * @param name Name.
  588. */
  589. removeAttribute(name) {
  590. const attribute = this._attributes[this._getAttributeName(name)];
  591. if (attribute) {
  592. this.removeAttributeNode(attribute);
  593. }
  594. }
  595. /**
  596. * Removes a namespace attribute.
  597. *
  598. * @param namespace Namespace URI.
  599. * @param localName Local name.
  600. */
  601. removeAttributeNS(namespace, localName) {
  602. for (const name of Object.keys(this._attributes)) {
  603. const attribute = this._attributes[name];
  604. if (attribute.namespaceURI === namespace && attribute.localName === localName) {
  605. this.removeAttribute(attribute.name);
  606. }
  607. }
  608. }
  609. /**
  610. * Attaches a shadow root.
  611. *
  612. * @param _shadowRootInit Shadow root init.
  613. * @param shadowRootInit
  614. * @param shadowRootInit.mode
  615. * @returns Shadow root.
  616. */
  617. attachShadow(shadowRootInit) {
  618. if (this._shadowRoot) {
  619. throw new DOMException_1.default('Shadow root has already been attached.');
  620. }
  621. this._shadowRoot = new ShadowRoot_1.default();
  622. this._shadowRoot.ownerDocument = this.ownerDocument;
  623. this._shadowRoot.host = this;
  624. this._shadowRoot.mode = shadowRootInit.mode;
  625. this._shadowRoot._connectToNode(this);
  626. if (this._shadowRoot.mode === 'open') {
  627. this.shadowRoot = this._shadowRoot;
  628. }
  629. return this._shadowRoot;
  630. }
  631. /**
  632. * Converts to string.
  633. *
  634. * @returns String.
  635. */
  636. toString() {
  637. return this.outerHTML;
  638. }
  639. /**
  640. * Returns the size of an element and its position relative to the viewport.
  641. *
  642. * @returns DOM rect.
  643. */
  644. getBoundingClientRect() {
  645. // TODO: Not full implementation
  646. return new DOMRect_1.default();
  647. }
  648. /**
  649. * Returns a collection of DOMRect objects that indicate the bounding rectangles for each CSS border box in a client.
  650. *
  651. * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects
  652. * @returns DOM rect list.
  653. */
  654. getClientRects() {
  655. // TODO: Not full implementation
  656. return DOMRectListFactory_1.default.create([this.getBoundingClientRect()]);
  657. }
  658. /**
  659. * The matches() method checks to see if the Element would be selected by the provided selectorString.
  660. *
  661. * @param selector Selector.
  662. * @returns "true" if matching.
  663. */
  664. matches(selector) {
  665. return QuerySelector_1.default.match(this, selector).matches;
  666. }
  667. /**
  668. * Traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string.
  669. *
  670. * @param selector Selector.
  671. * @returns Closest matching element.
  672. */
  673. closest(selector) {
  674. let rootElement = this.ownerDocument.documentElement;
  675. if (!this.isConnected) {
  676. rootElement = this;
  677. while (rootElement.parentNode) {
  678. rootElement = rootElement.parentNode;
  679. }
  680. }
  681. const elements = rootElement.querySelectorAll(selector);
  682. // eslint-disable-next-line
  683. let parent = this;
  684. while (parent) {
  685. if (elements.includes(parent)) {
  686. return parent;
  687. }
  688. parent = parent.parentElement;
  689. }
  690. // QuerySelectorAll() will not match the element it is looking in when searched for
  691. // Therefore we need to check if it matches the root
  692. if (rootElement.matches(selector)) {
  693. return rootElement;
  694. }
  695. return null;
  696. }
  697. /**
  698. * Query CSS selector to find matching nodes.
  699. *
  700. * @param selector CSS selector.
  701. * @returns Matching elements.
  702. */
  703. querySelectorAll(selector) {
  704. return QuerySelector_1.default.querySelectorAll(this, selector);
  705. }
  706. /**
  707. * Query CSS Selector to find matching node.
  708. *
  709. * @param selector CSS selector.
  710. * @returns Matching element.
  711. */
  712. querySelector(selector) {
  713. return QuerySelector_1.default.querySelector(this, selector);
  714. }
  715. /**
  716. * Returns an elements by class name.
  717. *
  718. * @param className Tag name.
  719. * @returns Matching element.
  720. */
  721. getElementsByClassName(className) {
  722. return ParentNodeUtility_1.default.getElementsByClassName(this, className);
  723. }
  724. /**
  725. * Returns an elements by tag name.
  726. *
  727. * @param tagName Tag name.
  728. * @returns Matching element.
  729. */
  730. getElementsByTagName(tagName) {
  731. return ParentNodeUtility_1.default.getElementsByTagName(this, tagName);
  732. }
  733. /**
  734. * Returns an elements by tag name and namespace.
  735. *
  736. * @param namespaceURI Namespace URI.
  737. * @param tagName Tag name.
  738. * @returns Matching element.
  739. */
  740. getElementsByTagNameNS(namespaceURI, tagName) {
  741. return ParentNodeUtility_1.default.getElementsByTagNameNS(this, namespaceURI, tagName);
  742. }
  743. /**
  744. * The setAttributeNode() method adds a new Attr node to the specified element.
  745. *
  746. * @param attribute Attribute.
  747. * @returns Replaced attribute.
  748. */
  749. setAttributeNode(attribute) {
  750. const name = this._getAttributeName(attribute.name);
  751. const replacedAttribute = this._attributes[name];
  752. const oldValue = replacedAttribute ? replacedAttribute.value : null;
  753. attribute.name = name;
  754. attribute.ownerElement = this;
  755. attribute.ownerDocument = this.ownerDocument;
  756. if (this.isConnected) {
  757. this.ownerDocument['_cacheID']++;
  758. }
  759. this._attributes[name] = attribute;
  760. if (attribute.name === 'class' && this._classList) {
  761. this._classList._updateIndices();
  762. }
  763. if (this.attributeChangedCallback &&
  764. this.constructor._observedAttributes &&
  765. this.constructor._observedAttributes.includes(name)) {
  766. this.attributeChangedCallback(name, oldValue, attribute.value);
  767. }
  768. // MutationObserver
  769. if (this._observers.length > 0) {
  770. for (const observer of this._observers) {
  771. if (observer.options.attributes &&
  772. (!observer.options.attributeFilter || observer.options.attributeFilter.includes(name))) {
  773. const record = new MutationRecord_1.default();
  774. record.target = this;
  775. record.type = MutationTypeEnum_1.default.attributes;
  776. record.attributeName = name;
  777. record.oldValue = observer.options.attributeOldValue ? oldValue : null;
  778. observer.callback([record]);
  779. }
  780. }
  781. }
  782. return replacedAttribute || null;
  783. }
  784. /**
  785. * The setAttributeNodeNS() method adds a new Attr node to the specified element.
  786. *
  787. * @param attribute Attribute.
  788. * @returns Replaced attribute.
  789. */
  790. setAttributeNodeNS(attribute) {
  791. return this.setAttributeNode(attribute);
  792. }
  793. /**
  794. * Returns an Attr node.
  795. *
  796. * @param name Name.
  797. * @returns Replaced attribute.
  798. */
  799. getAttributeNode(name) {
  800. return this._attributes[this._getAttributeName(name)] || null;
  801. }
  802. /**
  803. * Returns a namespaced Attr node.
  804. *
  805. * @param namespace Namespace.
  806. * @param name Name.
  807. * @returns Replaced attribute.
  808. */
  809. getAttributeNodeNS(namespace, name) {
  810. const attributeName = this._getAttributeName(name);
  811. if (this._attributes[attributeName] &&
  812. this._attributes[attributeName].namespaceURI === namespace &&
  813. this._attributes[attributeName].localName === attributeName) {
  814. return this._attributes[attributeName];
  815. }
  816. for (const name of Object.keys(this._attributes)) {
  817. const attribute = this._attributes[name];
  818. if (attribute.namespaceURI === namespace && attribute.localName === attributeName) {
  819. return attribute;
  820. }
  821. }
  822. return null;
  823. }
  824. /**
  825. * Removes an Attr node.
  826. *
  827. * @param attribute Attribute.
  828. * @returns Removed attribute.
  829. */
  830. removeAttributeNode(attribute) {
  831. const removedAttribute = this._attributes[attribute.name];
  832. if (removedAttribute !== attribute) {
  833. throw new DOMException_1.default(`Failed to execute 'removeAttributeNode' on 'Element': The node provided is owned by another element.`);
  834. }
  835. delete this._attributes[attribute.name];
  836. if (this.isConnected) {
  837. this.ownerDocument['_cacheID']++;
  838. }
  839. if (attribute.name === 'class' && this._classList) {
  840. this._classList._updateIndices();
  841. }
  842. if (this.attributeChangedCallback &&
  843. this.constructor._observedAttributes &&
  844. this.constructor._observedAttributes.includes(attribute.name)) {
  845. this.attributeChangedCallback(attribute.name, attribute.value, null);
  846. }
  847. // MutationObserver
  848. if (this._observers.length > 0) {
  849. for (const observer of this._observers) {
  850. if (observer.options.attributes &&
  851. (!observer.options.attributeFilter ||
  852. observer.options.attributeFilter.includes(attribute.name))) {
  853. const record = new MutationRecord_1.default();
  854. record.target = this;
  855. record.type = MutationTypeEnum_1.default.attributes;
  856. record.attributeName = attribute.name;
  857. record.oldValue = observer.options.attributeOldValue ? attribute.value : null;
  858. observer.callback([record]);
  859. }
  860. }
  861. }
  862. return attribute;
  863. }
  864. /**
  865. * Removes an Attr node.
  866. *
  867. * @param attribute Attribute.
  868. * @returns Removed attribute.
  869. */
  870. removeAttributeNodeNS(attribute) {
  871. return this.removeAttributeNode(attribute);
  872. }
  873. /**
  874. * Scrolls to a particular set of coordinates.
  875. *
  876. * @param x X position or options object.
  877. * @param y Y position.
  878. */
  879. scroll(x, y) {
  880. if (typeof x === 'object') {
  881. if (x.behavior === 'smooth') {
  882. this.ownerDocument.defaultView.setTimeout(() => {
  883. if (x.top !== undefined) {
  884. this.scrollTop = x.top;
  885. }
  886. if (x.left !== undefined) {
  887. this.scrollLeft = x.left;
  888. }
  889. });
  890. }
  891. else {
  892. if (x.top !== undefined) {
  893. this.scrollTop = x.top;
  894. }
  895. if (x.left !== undefined) {
  896. this.scrollLeft = x.left;
  897. }
  898. }
  899. }
  900. else if (x !== undefined && y !== undefined) {
  901. this.scrollLeft = x;
  902. this.scrollTop = y;
  903. }
  904. }
  905. /**
  906. * Scrolls to a particular set of coordinates.
  907. *
  908. * @param x X position or options object.
  909. * @param y Y position.
  910. */
  911. scrollTo(x, y) {
  912. this.scroll(x, y);
  913. }
  914. /**
  915. * Returns attribute name.
  916. *
  917. * @param name Name.
  918. * @returns Attribute name based on namespace.
  919. */
  920. _getAttributeName(name) {
  921. if (this.namespaceURI === NamespaceURI_1.default.svg) {
  922. return name;
  923. }
  924. return name.toLowerCase();
  925. }
  926. }
  927. exports.default = Element;
  928. //# sourceMappingURL=Element.js.map