版博士V2.0程序
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.
 
 
 
 

421 lines
12 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 HTMLElement_1 = __importDefault(require("../html-element/HTMLElement"));
  7. const ValidityState_1 = __importDefault(require("../validity-state/ValidityState"));
  8. const HTMLOptionsCollection_1 = __importDefault(require("../html-option-element/HTMLOptionsCollection"));
  9. const NodeTypeEnum_1 = __importDefault(require("../node/NodeTypeEnum"));
  10. /**
  11. * HTML Select Element.
  12. *
  13. * Reference:
  14. * https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement.
  15. */
  16. class HTMLSelectElement extends HTMLElement_1.default {
  17. constructor() {
  18. super(...arguments);
  19. this.options = new HTMLOptionsCollection_1.default(this);
  20. // Events
  21. this.onchange = null;
  22. this.oninput = null;
  23. }
  24. /**
  25. * Returns name.
  26. *
  27. * @returns Name.
  28. */
  29. get name() {
  30. return this.getAttributeNS(null, 'name') || '';
  31. }
  32. /**
  33. * Sets name.
  34. *
  35. * @param name Name.
  36. */
  37. set name(name) {
  38. this.setAttributeNS(null, 'name', name);
  39. }
  40. /**
  41. * Returns disabled.
  42. *
  43. * @returns Disabled.
  44. */
  45. get disabled() {
  46. return this.getAttributeNS(null, 'disabled') !== null;
  47. }
  48. /**
  49. * Sets disabled.
  50. *
  51. * @param disabled Disabled.
  52. */
  53. set disabled(disabled) {
  54. if (!disabled) {
  55. this.removeAttributeNS(null, 'disabled');
  56. }
  57. else {
  58. this.setAttributeNS(null, 'disabled', '');
  59. }
  60. }
  61. /**
  62. * Returns multiple.
  63. *
  64. * @returns Multiple.
  65. */
  66. get multiple() {
  67. return this.getAttributeNS(null, 'multiple') !== null;
  68. }
  69. /**
  70. * Sets multiple.
  71. *
  72. * @param multiple Multiple.
  73. */
  74. set multiple(multiple) {
  75. if (!multiple) {
  76. this.removeAttributeNS(null, 'multiple');
  77. }
  78. else {
  79. this.setAttributeNS(null, 'multiple', '');
  80. }
  81. }
  82. /**
  83. * Returns autofocus.
  84. *
  85. * @returns Autofocus.
  86. */
  87. get autofocus() {
  88. return this.getAttributeNS(null, 'autofocus') !== null;
  89. }
  90. /**
  91. * Sets autofocus.
  92. *
  93. * @param autofocus Autofocus.
  94. */
  95. set autofocus(autofocus) {
  96. if (!autofocus) {
  97. this.removeAttributeNS(null, 'autofocus');
  98. }
  99. else {
  100. this.setAttributeNS(null, 'autofocus', '');
  101. }
  102. }
  103. /**
  104. * Returns length.
  105. *
  106. * @returns length.
  107. */
  108. get length() {
  109. return this.options.length;
  110. }
  111. /**
  112. * Sets length.
  113. *
  114. * @param length Length.
  115. */
  116. set length(length) {
  117. this.options.length = length;
  118. }
  119. /**
  120. * Returns required.
  121. *
  122. * @returns Required.
  123. */
  124. get required() {
  125. return this.getAttributeNS(null, 'required') !== null;
  126. }
  127. /**
  128. * Sets required.
  129. *
  130. * @param required Required.
  131. */
  132. set required(required) {
  133. if (!required) {
  134. this.removeAttributeNS(null, 'required');
  135. }
  136. else {
  137. this.setAttributeNS(null, 'required', '');
  138. }
  139. }
  140. /**
  141. * Returns type.
  142. *
  143. * @returns type.
  144. */
  145. get type() {
  146. return this.hasAttributeNS(null, 'multiple') ? 'select-multiple' : 'select-one';
  147. }
  148. /**
  149. * Returns value.
  150. *
  151. * @returns Value.
  152. */
  153. get value() {
  154. for (let i = 0, max = this.options.length; i < max; i++) {
  155. const option = this.options[i];
  156. if (option._selectedness) {
  157. return option.value;
  158. }
  159. }
  160. return '';
  161. }
  162. /**
  163. * Sets value.
  164. *
  165. * @param value Value.
  166. */
  167. set value(value) {
  168. for (let i = 0, max = this.options.length; i < max; i++) {
  169. const option = this.options[i];
  170. if (option.value === value) {
  171. option._selectedness = true;
  172. option._dirtyness = true;
  173. }
  174. else {
  175. option._selectedness = false;
  176. }
  177. }
  178. }
  179. /**
  180. * Returns value.
  181. *
  182. * @returns Value.
  183. */
  184. get selectedIndex() {
  185. for (let i = 0, max = this.options.length; i < max; i++) {
  186. if (this.options[i]._selectedness) {
  187. return i;
  188. }
  189. }
  190. return -1;
  191. }
  192. /**
  193. * Sets value.
  194. *
  195. * @param selectedIndex Selected index.
  196. */
  197. set selectedIndex(selectedIndex) {
  198. if (typeof selectedIndex === 'number' && !isNaN(selectedIndex)) {
  199. for (let i = 0, max = this.options.length; i < max; i++) {
  200. this.options[i]._selectedness = false;
  201. }
  202. const selectedOption = this.options[selectedIndex];
  203. if (selectedOption) {
  204. selectedOption._selectedness = true;
  205. selectedOption._dirtyness = true;
  206. }
  207. }
  208. }
  209. /**
  210. * Returns the parent form element.
  211. *
  212. * @returns Form.
  213. */
  214. get form() {
  215. let parent = this.parentNode;
  216. while (parent && parent.tagName !== 'FORM') {
  217. parent = parent.parentNode;
  218. }
  219. return parent;
  220. }
  221. /**
  222. * Returns validity state.
  223. *
  224. * @returns Validity state.
  225. */
  226. get validity() {
  227. return new ValidityState_1.default(this);
  228. }
  229. /**
  230. * Returns "true" if it will validate.
  231. *
  232. * @returns "true" if it will validate.
  233. */
  234. get willValidate() {
  235. return (this.type !== 'hidden' &&
  236. this.type !== 'reset' &&
  237. this.type !== 'button' &&
  238. !this.disabled &&
  239. !this['readOnly']);
  240. }
  241. /**
  242. * Returns item from options collection by index.
  243. *
  244. * @param index Index.
  245. */
  246. item(index) {
  247. return this.options.item(index);
  248. }
  249. /**
  250. * Adds new option to options collection.
  251. *
  252. * @param element HTMLOptionElement or HTMLOptGroupElement to add.
  253. * @param before HTMLOptionElement or index number.
  254. */
  255. add(element, before) {
  256. this.options.add(element, before);
  257. }
  258. /**
  259. * Removes indexed element from collection or the select element.
  260. *
  261. * @param [index] Index.
  262. */
  263. remove(index) {
  264. if (typeof index === 'number') {
  265. this.options.remove(index);
  266. }
  267. else {
  268. super.remove();
  269. }
  270. }
  271. /**
  272. * @override
  273. */
  274. appendChild(node) {
  275. if (node.nodeType === NodeTypeEnum_1.default.elementNode) {
  276. const element = node;
  277. const previousLength = this.options.length;
  278. if (element.tagName === 'OPTION' || element.tagName === 'OPTGROUP') {
  279. this.options.push(element);
  280. }
  281. this._updateIndexProperties(previousLength, this.options.length);
  282. this._resetOptionSelectednes();
  283. }
  284. return super.appendChild(node);
  285. }
  286. /**
  287. * @override
  288. */
  289. insertBefore(newNode, referenceNode) {
  290. const returnValue = super.insertBefore(newNode, referenceNode);
  291. if (newNode.nodeType === NodeTypeEnum_1.default.elementNode &&
  292. referenceNode?.nodeType === NodeTypeEnum_1.default.elementNode) {
  293. const newElement = newNode;
  294. const previousLength = this.options.length;
  295. if (newElement.tagName === 'OPTION' || newElement.tagName === 'OPTGROUP') {
  296. const referenceElement = referenceNode;
  297. if (referenceElement &&
  298. (referenceElement.tagName === 'OPTION' || referenceElement.tagName === 'OPTGROUP')) {
  299. const referenceIndex = this.options.indexOf(referenceElement);
  300. if (referenceIndex !== -1) {
  301. this.options.splice(referenceIndex, 0, newElement);
  302. }
  303. }
  304. else {
  305. this.options.push(newElement);
  306. }
  307. }
  308. this._updateIndexProperties(previousLength, this.options.length);
  309. }
  310. if (newNode.nodeType === NodeTypeEnum_1.default.elementNode) {
  311. this._resetOptionSelectednes();
  312. }
  313. return returnValue;
  314. }
  315. /**
  316. * @override
  317. */
  318. removeChild(node) {
  319. if (node.nodeType === NodeTypeEnum_1.default.elementNode) {
  320. const element = node;
  321. const previousLength = this.options.length;
  322. if (element.tagName === 'OPTION' || element.tagName === 'OPTION') {
  323. const index = this.options.indexOf(node);
  324. if (index !== -1) {
  325. this.options.splice(index, 1);
  326. }
  327. }
  328. this._updateIndexProperties(previousLength, this.options.length);
  329. this._resetOptionSelectednes();
  330. }
  331. return super.removeChild(node);
  332. }
  333. /**
  334. * Resets the option selectedness.
  335. *
  336. * Based on:
  337. * https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/nodes/HTMLSelectElement-impl.js
  338. *
  339. * @param [newOption] Optional new option element to be selected.
  340. * @see https://html.spec.whatwg.org/multipage/form-elements.html#selectedness-setting-algorithm
  341. */
  342. _resetOptionSelectednes(newOption) {
  343. if (this.hasAttributeNS(null, 'multiple')) {
  344. return;
  345. }
  346. const selected = [];
  347. for (let i = 0, max = this.options.length; i < max; i++) {
  348. if (newOption) {
  349. this.options[i]._selectedness = this.options[i] === newOption;
  350. }
  351. if (this.options[i]._selectedness) {
  352. selected.push(this.options[i]);
  353. }
  354. }
  355. const size = this._getDisplaySize();
  356. if (size === 1 && !selected.length) {
  357. for (let i = 0, max = this.options.length; i < max; i++) {
  358. const option = this.options[i];
  359. let disabled = option.hasAttributeNS(null, 'disabled');
  360. const parentNode = option.parentNode;
  361. if (parentNode &&
  362. parentNode.nodeType === NodeTypeEnum_1.default.elementNode &&
  363. parentNode.tagName === 'OPTGROUP' &&
  364. parentNode.hasAttributeNS(null, 'disabled')) {
  365. disabled = true;
  366. }
  367. if (!disabled) {
  368. option._selectedness = true;
  369. break;
  370. }
  371. }
  372. }
  373. else if (selected.length >= 2) {
  374. for (let i = 0, max = this.options.length; i < max; i++) {
  375. this.options[i]._selectedness = i === selected.length - 1;
  376. }
  377. }
  378. }
  379. /**
  380. * Returns display size.
  381. *
  382. * @returns Display size.
  383. */
  384. _getDisplaySize() {
  385. if (this.hasAttributeNS(null, 'size')) {
  386. const size = parseInt(this.getAttributeNS(null, 'size'));
  387. if (!isNaN(size) && size >= 0) {
  388. return size;
  389. }
  390. }
  391. return this.hasAttributeNS(null, 'multiple') ? 4 : 1;
  392. }
  393. /**
  394. * Updates index properties.
  395. *
  396. * @param previousLength Length before the update.
  397. * @param newLength Length after the update.
  398. */
  399. _updateIndexProperties(previousLength, newLength) {
  400. if (previousLength > newLength) {
  401. for (let i = newLength; i < previousLength; i++) {
  402. if (this.hasOwnProperty(String(i))) {
  403. delete this[String(i)];
  404. }
  405. }
  406. }
  407. else if (previousLength < newLength) {
  408. for (let i = previousLength; i < newLength; i++) {
  409. Object.defineProperty(this, String(i), {
  410. get: () => {
  411. return this.options[i];
  412. },
  413. enumerable: true,
  414. configurable: true
  415. });
  416. }
  417. }
  418. }
  419. }
  420. exports.default = HTMLSelectElement;
  421. //# sourceMappingURL=HTMLSelectElement.js.map