版博士V2.0程序
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

416 wiersze
13 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 Element_1 = __importDefault(require("../element/Element"));
  7. const CSSStyleDeclaration_1 = __importDefault(require("../../css/declaration/CSSStyleDeclaration"));
  8. const FocusEvent_1 = __importDefault(require("../../event/events/FocusEvent"));
  9. const PointerEvent_1 = __importDefault(require("../../event/events/PointerEvent"));
  10. const DatasetUtility_1 = __importDefault(require("./DatasetUtility"));
  11. const NodeTypeEnum_1 = __importDefault(require("../node/NodeTypeEnum"));
  12. const DOMException_1 = __importDefault(require("../../exception/DOMException"));
  13. /**
  14. * HTML Element.
  15. *
  16. * Reference:
  17. * https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.
  18. */
  19. class HTMLElement extends Element_1.default {
  20. constructor() {
  21. super(...arguments);
  22. this.accessKey = '';
  23. this.accessKeyLabel = '';
  24. this.contentEditable = 'inherit';
  25. this.isContentEditable = false;
  26. this.offsetHeight = 0;
  27. this.offsetWidth = 0;
  28. this.offsetLeft = 0;
  29. this.offsetTop = 0;
  30. this.clientHeight = 0;
  31. this.clientWidth = 0;
  32. this._style = null;
  33. this._dataset = null;
  34. // Events
  35. this.oncopy = null;
  36. this.oncut = null;
  37. this.onpaste = null;
  38. this.oninvalid = null;
  39. this.onanimationcancel = null;
  40. this.onanimationend = null;
  41. this.onanimationiteration = null;
  42. this.onanimationstart = null;
  43. this.onbeforeinput = null;
  44. this.oninput = null;
  45. this.onchange = null;
  46. this.ongotpointercapture = null;
  47. this.onlostpointercapture = null;
  48. this.onpointercancel = null;
  49. this.onpointerdown = null;
  50. this.onpointerenter = null;
  51. this.onpointerleave = null;
  52. this.onpointermove = null;
  53. this.onpointerout = null;
  54. this.onpointerover = null;
  55. this.onpointerup = null;
  56. this.ontransitioncancel = null;
  57. this.ontransitionend = null;
  58. this.ontransitionrun = null;
  59. this.ontransitionstart = null;
  60. }
  61. /**
  62. * Returns tab index.
  63. *
  64. * @returns Tab index.
  65. */
  66. get tabIndex() {
  67. const tabIndex = this.getAttributeNS(null, 'tabindex');
  68. return tabIndex !== null ? Number(tabIndex) : -1;
  69. }
  70. /**
  71. * Returns tab index.
  72. *
  73. * @param tabIndex Tab index.
  74. */
  75. set tabIndex(tabIndex) {
  76. if (tabIndex === -1) {
  77. this.removeAttributeNS(null, 'tabindex');
  78. }
  79. else {
  80. this.setAttributeNS(null, 'tabindex', String(tabIndex));
  81. }
  82. }
  83. /**
  84. * Returns inner text, which is the rendered appearance of text.
  85. *
  86. * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute
  87. * @returns Inner text.
  88. */
  89. get innerText() {
  90. if (!this.isConnected) {
  91. return this.textContent;
  92. }
  93. let result = '';
  94. for (const childNode of this.childNodes) {
  95. if (childNode.nodeType === NodeTypeEnum_1.default.elementNode) {
  96. const childElement = childNode;
  97. const computedStyle = this.ownerDocument.defaultView.getComputedStyle(childElement);
  98. if (childElement.tagName !== 'SCRIPT' && childElement.tagName !== 'STYLE') {
  99. const display = computedStyle.display;
  100. if (display !== 'none') {
  101. const textTransform = computedStyle.textTransform;
  102. if ((display === 'block' || display === 'flex') && result) {
  103. result += '\n';
  104. }
  105. let text = childElement.innerText;
  106. switch (textTransform) {
  107. case 'uppercase':
  108. text = text.toUpperCase();
  109. break;
  110. case 'lowercase':
  111. text = text.toLowerCase();
  112. break;
  113. case 'capitalize':
  114. text = text.replace(/(^|\s)\S/g, (l) => l.toUpperCase());
  115. break;
  116. }
  117. result += text;
  118. }
  119. }
  120. }
  121. else if (childNode.nodeType === NodeTypeEnum_1.default.textNode) {
  122. result += childNode.textContent.replace(/[\n\r]/, '');
  123. }
  124. }
  125. return result;
  126. }
  127. /**
  128. * Sets the inner text, which is the rendered appearance of text.
  129. *
  130. * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute
  131. * @param innerText Inner text.
  132. */
  133. set innerText(text) {
  134. for (const child of this.childNodes.slice()) {
  135. this.removeChild(child);
  136. }
  137. const texts = text.split(/[\n\r]/);
  138. for (let i = 0, max = texts.length; i < max; i++) {
  139. if (i !== 0) {
  140. this.appendChild(this.ownerDocument.createElement('br'));
  141. }
  142. this.appendChild(this.ownerDocument.createTextNode(texts[i]));
  143. }
  144. }
  145. /**
  146. * Returns outer text.
  147. *
  148. * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute
  149. * @returns HTML.
  150. */
  151. get outerText() {
  152. return this.innerText;
  153. }
  154. /**
  155. * Sets outer text.
  156. *
  157. * @see https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute
  158. * @param text Text.
  159. */
  160. set outerText(text) {
  161. if (!this.parentNode) {
  162. throw new DOMException_1.default("Failed to set the 'outerHTML' property on 'Element': This element has no parent node.");
  163. }
  164. const texts = text.split(/[\n\r]/);
  165. for (let i = 0, max = texts.length; i < max; i++) {
  166. if (i !== 0) {
  167. this.parentNode.insertBefore(this.ownerDocument.createElement('br'), this);
  168. }
  169. this.parentNode.insertBefore(this.ownerDocument.createTextNode(texts[i]), this);
  170. }
  171. this.parentNode.removeChild(this);
  172. }
  173. /**
  174. * Returns style.
  175. *
  176. * @returns Style.
  177. */
  178. get style() {
  179. if (!this._style) {
  180. this._style = new CSSStyleDeclaration_1.default(this);
  181. }
  182. return this._style;
  183. }
  184. /**
  185. * Sets style.
  186. *
  187. * @param cssText Style as text.
  188. * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style#setting_styles
  189. */
  190. set style(cssText) {
  191. this.style.cssText = typeof cssText === 'string' ? cssText : '';
  192. }
  193. /**
  194. * Returns data set.
  195. *
  196. * @returns Data set.
  197. */
  198. get dataset() {
  199. if (this._dataset) {
  200. return this._dataset;
  201. }
  202. const dataset = {};
  203. const attributes = this._attributes;
  204. for (const name of Object.keys(attributes)) {
  205. if (name.startsWith('data-')) {
  206. const key = DatasetUtility_1.default.kebabToCamelCase(name.replace('data-', ''));
  207. dataset[key] = attributes[name].value;
  208. }
  209. }
  210. // Documentation for Proxy:
  211. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
  212. this._dataset = new Proxy(dataset, {
  213. get: (dataset, key) => {
  214. const name = 'data-' + DatasetUtility_1.default.camelCaseToKebab(key);
  215. if (this._attributes[name]) {
  216. dataset[key] = this._attributes[name].value;
  217. return this._attributes[name].value;
  218. }
  219. if (dataset[key] !== undefined) {
  220. delete dataset[key];
  221. }
  222. return undefined;
  223. },
  224. set: (dataset, key, value) => {
  225. this.setAttribute('data-' + DatasetUtility_1.default.camelCaseToKebab(key), value);
  226. dataset[key] = value;
  227. return true;
  228. },
  229. deleteProperty: (dataset, key) => {
  230. const name = 'data-' + DatasetUtility_1.default.camelCaseToKebab(key);
  231. const result1 = delete attributes[name];
  232. const result2 = delete dataset[key];
  233. return result1 && result2;
  234. },
  235. ownKeys: (dataset) => {
  236. // According to Mozilla we have to update the dataset object (target) to contain the same keys as what we return:
  237. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/ownKeys
  238. // "The result List must contain the keys of all non-configurable own properties of the target object."
  239. const keys = [];
  240. const deleteKeys = [];
  241. for (const name of Object.keys(attributes)) {
  242. if (name.startsWith('data-')) {
  243. const key = DatasetUtility_1.default.kebabToCamelCase(name.replace('data-', ''));
  244. keys.push(key);
  245. dataset[key] = attributes[name].value;
  246. if (!dataset[key]) {
  247. deleteKeys.push(key);
  248. }
  249. }
  250. }
  251. for (const key of deleteKeys) {
  252. delete dataset[key];
  253. }
  254. return keys;
  255. },
  256. has: (_dataset, key) => {
  257. return !!attributes['data-' + DatasetUtility_1.default.camelCaseToKebab(key)];
  258. }
  259. });
  260. return this._dataset;
  261. }
  262. /**
  263. * Returns direction.
  264. *
  265. * @returns Direction.
  266. */
  267. get dir() {
  268. return this.getAttributeNS(null, 'dir') || '';
  269. }
  270. /**
  271. * Returns direction.
  272. *
  273. * @param direction Direction.
  274. */
  275. set dir(direction) {
  276. this.setAttributeNS(null, 'dir', direction);
  277. }
  278. /**
  279. * Returns hidden.
  280. *
  281. * @returns Hidden.
  282. */
  283. get hidden() {
  284. return this.getAttributeNS(null, 'hidden') !== null;
  285. }
  286. /**
  287. * Returns hidden.
  288. *
  289. * @param hidden Hidden.
  290. */
  291. set hidden(hidden) {
  292. if (!hidden) {
  293. this.removeAttributeNS(null, 'hidden');
  294. }
  295. else {
  296. this.setAttributeNS(null, 'hidden', '');
  297. }
  298. }
  299. /**
  300. * Returns language.
  301. *
  302. * @returns Language.
  303. */
  304. get lang() {
  305. return this.getAttributeNS(null, 'lang') || '';
  306. }
  307. /**
  308. * Returns language.
  309. *
  310. * @param language Language.
  311. */
  312. set lang(lang) {
  313. this.setAttributeNS(null, 'lang', lang);
  314. }
  315. /**
  316. * Returns title.
  317. *
  318. * @returns Title.
  319. */
  320. get title() {
  321. return this.getAttributeNS(null, 'title') || '';
  322. }
  323. /**
  324. * Returns title.
  325. *
  326. * @param title Title.
  327. */
  328. set title(title) {
  329. this.setAttributeNS(null, 'title', title);
  330. }
  331. /**
  332. * Triggers a click event.
  333. */
  334. click() {
  335. const event = new PointerEvent_1.default('click', {
  336. bubbles: true,
  337. composed: true
  338. });
  339. event._target = this;
  340. event._currentTarget = this;
  341. this.dispatchEvent(event);
  342. }
  343. /**
  344. * Triggers a blur event.
  345. */
  346. blur() {
  347. if (this.ownerDocument['_activeElement'] !== this || !this.isConnected) {
  348. return;
  349. }
  350. this.ownerDocument['_activeElement'] = null;
  351. this.dispatchEvent(new FocusEvent_1.default('blur', {
  352. bubbles: false,
  353. composed: true
  354. }));
  355. this.dispatchEvent(new FocusEvent_1.default('focusout', {
  356. bubbles: true,
  357. composed: true
  358. }));
  359. }
  360. /**
  361. * Triggers a focus event.
  362. */
  363. focus() {
  364. if (this.ownerDocument['_activeElement'] === this || !this.isConnected) {
  365. return;
  366. }
  367. if (this.ownerDocument['_activeElement'] !== null) {
  368. this.ownerDocument['_activeElement'].blur();
  369. }
  370. this.ownerDocument['_activeElement'] = this;
  371. this.dispatchEvent(new FocusEvent_1.default('focus', {
  372. bubbles: false,
  373. composed: true
  374. }));
  375. this.dispatchEvent(new FocusEvent_1.default('focusin', {
  376. bubbles: true,
  377. composed: true
  378. }));
  379. }
  380. /**
  381. * @override
  382. */
  383. setAttributeNode(attribute) {
  384. const replacedAttribute = super.setAttributeNode(attribute);
  385. if (attribute.name === 'style' && this._style) {
  386. this._style.cssText = attribute.value;
  387. }
  388. return replacedAttribute;
  389. }
  390. /**
  391. * @override
  392. */
  393. removeAttributeNode(attribute) {
  394. super.removeAttributeNode(attribute);
  395. if (attribute.name === 'style' && this._style) {
  396. this._style.cssText = '';
  397. }
  398. return attribute;
  399. }
  400. /**
  401. * @override
  402. */
  403. cloneNode(deep = false) {
  404. const clone = super.cloneNode(deep);
  405. clone.accessKey = this.accessKey;
  406. clone.accessKeyLabel = this.accessKeyLabel;
  407. clone.contentEditable = this.contentEditable;
  408. clone.isContentEditable = this.isContentEditable;
  409. if (this._style) {
  410. clone.style.cssText = this._style.cssText;
  411. }
  412. return clone;
  413. }
  414. }
  415. exports.default = HTMLElement;
  416. //# sourceMappingURL=HTMLElement.js.map