pseudo-dom 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,6 +66,11 @@ the DOM's. Every `*NS` method (`getAttributeNS`, `hasAttributeNS`, `setAttribute
66
66
  `getAttributeNodeNS`, `setAttributeNodeNS`) behaves exactly like its non-NS counterpart, ignoring the namespace
67
67
  argument entirely - there's no real namespace parsing here, matching `getElementsByTagNameNS`.
68
68
 
69
+ **Form controls** have a real `value` (`input`, `textarea`, `select`, `button`, `option`, `output`) and `checked`
70
+ (`input`). Like the DOM's, they start from the `value` / `checked` attributes (a checkbox with no `value` reads
71
+ `'on'`), and once set they stop following the attribute - setting them never changes the attribute. `value` is always
72
+ a string, so `parseInt(input.value)` works on a number attribute. `cloneNode` keeps the current value and checkedness.
73
+
69
74
  **`style`** is a real, live `CSSStyleDeclaration`:
70
75
 
71
76
  - Named property access (`el.style.backgroundColor = 'red'`) alongside `getPropertyValue` / `setProperty` /
@@ -2437,9 +2442,14 @@ Simulate the behaviour of the HTMLElement Class when there is no DOM available.
2437
2442
  * [new HTMLElementService([elementOptions])](#new_HTMLElementService_new)
2438
2443
  * [.style](#HTMLElementService+style) ⇒ [<code>CSSStyleDeclarationService</code>](#CSSStyleDeclarationService)
2439
2444
  * [.dataset](#HTMLElementService+dataset) ⇒ <code>Object.&lt;string, string&gt;</code>
2445
+ * [.value](#HTMLElementService+value) ⇒ <code>string</code> \| <code>undefined</code>
2446
+ * [.checked](#HTMLElementService+checked) ⇒ <code>boolean</code> \| <code>undefined</code>
2440
2447
  * [.innerHTML](#HTMLElementService+innerHTML) ⇒ <code>undefined</code>
2441
2448
  * [.outerHTML](#HTMLElementService+outerHTML) ⇒ <code>undefined</code>
2442
2449
  * [.canFocus](#HTMLElementService+canFocus) ⇒ <code>boolean</code>
2450
+ * [.hasValueProperty()](#HTMLElementService+hasValueProperty) ⇒ <code>boolean</code>
2451
+ * [.hasCheckedProperty()](#HTMLElementService+hasCheckedProperty) ⇒ <code>boolean</code>
2452
+ * [.setExpando(name, value)](#HTMLElementService+setExpando) ⇒ <code>undefined</code>
2443
2453
  * [.cloneShallow()](#HTMLElementService+cloneShallow) ⇒ [<code>NodeService</code>](#NodeService)
2444
2454
  * [.equalsShallow(other)](#HTMLElementService+equalsShallow) ⇒ <code>boolean</code>
2445
2455
  * [.parse(html)](#HTMLElementService+parse) ⇒ <code>Array.&lt;\*&gt;</code>
@@ -2474,6 +2484,21 @@ and style.color = 'red' work.
2474
2484
  The element's data-* attributes, live, under their camelCase names (data-foo-bar <-> dataset.fooBar). Backed
2475
2485
  directly by getAttribute / setAttribute, so it is never out of sync with the attributes themselves.
2476
2486
 
2487
+ **Kind**: instance property of [<code>HTMLElementService</code>](#HTMLElementService)
2488
+ <a name="HTMLElementService+value"></a>
2489
+
2490
+ ### htmlElementService.value ⇒ <code>string</code> \| <code>undefined</code>
2491
+ The current value of a form control. Until it is set (or edited), it is the value attribute (the default value),
2492
+ or '' when there is none ('on' for a checkbox or radio); setting it never changes the attribute, like the DOM's.
2493
+ Only form controls (input, textarea, select, button, option, output) have one.
2494
+
2495
+ **Kind**: instance property of [<code>HTMLElementService</code>](#HTMLElementService)
2496
+ <a name="HTMLElementService+checked"></a>
2497
+
2498
+ ### htmlElementService.checked ⇒ <code>boolean</code> \| <code>undefined</code>
2499
+ Whether a checkbox or radio input is checked. Until it is set, it follows the checked attribute (which sets the
2500
+ default); setting it never changes the attribute, like the DOM's. Only input has one.
2501
+
2477
2502
  **Kind**: instance property of [<code>HTMLElementService</code>](#HTMLElementService)
2478
2503
  <a name="HTMLElementService+innerHTML"></a>
2479
2504
 
@@ -2505,10 +2530,35 @@ replaceWith. outerHTML's setter is here rather than on ElementService for the sa
2505
2530
  Whether this element can have the focus: form controls and links which are not disabled, and anything with a tabindex.
2506
2531
 
2507
2532
  **Kind**: instance property of [<code>HTMLElementService</code>](#HTMLElementService)
2533
+ <a name="HTMLElementService+hasValueProperty"></a>
2534
+
2535
+ ### htmlElementService.hasValueProperty() ⇒ <code>boolean</code>
2536
+ Whether this tag has a `value` (the form controls which do).
2537
+
2538
+ **Kind**: instance method of [<code>HTMLElementService</code>](#HTMLElementService)
2539
+ <a name="HTMLElementService+hasCheckedProperty"></a>
2540
+
2541
+ ### htmlElementService.hasCheckedProperty() ⇒ <code>boolean</code>
2542
+ Whether this tag has a `checked` (only input does).
2543
+
2544
+ **Kind**: instance method of [<code>HTMLElementService</code>](#HTMLElementService)
2545
+ <a name="HTMLElementService+setExpando"></a>
2546
+
2547
+ ### htmlElementService.setExpando(name, value) ⇒ <code>undefined</code>
2548
+ Put a plain own property on the element, as assigning a property this element does not have does in the DOM.
2549
+
2550
+ **Kind**: instance method of [<code>HTMLElementService</code>](#HTMLElementService)
2551
+
2552
+ | Param | Type |
2553
+ | --- | --- |
2554
+ | name | <code>string</code> |
2555
+ | value | <code>\*</code> |
2556
+
2508
2557
  <a name="HTMLElementService+cloneShallow"></a>
2509
2558
 
2510
2559
  ### htmlElementService.cloneShallow() ⇒ [<code>NodeService</code>](#NodeService)
2511
- Style is not attribute-backed like most properties (see the constructor), so cloneNode needs its own copy of it.
2560
+ Style is not attribute-backed like most properties (see the constructor), so cloneNode needs its own copy of it,
2561
+ and a form control keeps its current value and checkedness (as the DOM's cloneNode does).
2512
2562
 
2513
2563
  **Kind**: instance method of [<code>HTMLElementService</code>](#HTMLElementService)
2514
2564
  <a name="HTMLElementService+equalsShallow"></a>
@@ -3908,6 +3908,8 @@
3908
3908
  parent,
3909
3909
  children
3910
3910
  })
3911
+ this.dirtyValue = null
3912
+ this.dirtyChecked = null
3911
3913
  this.styleDeclaration = (0, createStyleDeclaration_1.default)()
3912
3914
  this.datasetProxy = (0, createDataset_1.default)(this)
3913
3915
  }
@@ -3931,12 +3933,94 @@
3931
3933
  }
3932
3934
 
3933
3935
  /**
3934
- * Style is not attribute-backed like most properties (see the constructor), so cloneNode needs its own copy of it.
3936
+ * Whether this tag has a `value` (the form controls which do).
3937
+ * @returns {boolean}
3938
+ */
3939
+ hasValueProperty () {
3940
+ return ['input', 'textarea', 'select', 'button', 'option', 'output'].indexOf(this.tagName.toLowerCase()) >= 0
3941
+ }
3942
+
3943
+ /**
3944
+ * Whether this tag has a `checked` (only input does).
3945
+ * @returns {boolean}
3946
+ */
3947
+ hasCheckedProperty () {
3948
+ return this.tagName.toLowerCase() === 'input'
3949
+ }
3950
+
3951
+ /**
3952
+ * Put a plain own property on the element, as assigning a property this element does not have does in the DOM.
3953
+ * @param {string} name
3954
+ * @param {*} value
3955
+ * @returns {undefined}
3956
+ */
3957
+ setExpando (name, value) {
3958
+ Object.defineProperty(this, name, {
3959
+ value,
3960
+ writable: true,
3961
+ configurable: true,
3962
+ enumerable: true
3963
+ })
3964
+ }
3965
+
3966
+ /**
3967
+ * The current value of a form control. Until it is set (or edited), it is the value attribute (the default value),
3968
+ * or '' when there is none ('on' for a checkbox or radio); setting it never changes the attribute, like the DOM's.
3969
+ * Only form controls (input, textarea, select, button, option, output) have one.
3970
+ * @returns {string|undefined}
3971
+ */
3972
+ get value () {
3973
+ if (!this.hasValueProperty()) {
3974
+ return undefined
3975
+ }
3976
+ if (this.dirtyValue !== null) {
3977
+ return this.dirtyValue
3978
+ }
3979
+ const attribute = this.getAttribute('value')
3980
+ if (attribute !== null) {
3981
+ return String(attribute)
3982
+ }
3983
+ return this.tagName.toLowerCase() === 'input' && /^(checkbox|radio)$/i.test(String(this.getAttribute('type'))) ? 'on' : ''
3984
+ }
3985
+
3986
+ set value (value) {
3987
+ if (this.hasValueProperty()) {
3988
+ this.dirtyValue = String(value)
3989
+ } else {
3990
+ this.setExpando('value', value)
3991
+ }
3992
+ }
3993
+
3994
+ /**
3995
+ * Whether a checkbox or radio input is checked. Until it is set, it follows the checked attribute (which sets the
3996
+ * default); setting it never changes the attribute, like the DOM's. Only input has one.
3997
+ * @returns {boolean|undefined}
3998
+ */
3999
+ get checked () {
4000
+ if (!this.hasCheckedProperty()) {
4001
+ return undefined
4002
+ }
4003
+ return this.dirtyChecked !== null ? this.dirtyChecked : this.hasAttribute('checked')
4004
+ }
4005
+
4006
+ set checked (checked) {
4007
+ if (this.hasCheckedProperty()) {
4008
+ this.dirtyChecked = Boolean(checked)
4009
+ } else {
4010
+ this.setExpando('checked', checked)
4011
+ }
4012
+ }
4013
+
4014
+ /**
4015
+ * Style is not attribute-backed like most properties (see the constructor), so cloneNode needs its own copy of it,
4016
+ * and a form control keeps its current value and checkedness (as the DOM's cloneNode does).
3935
4017
  * @returns {NodeService}
3936
4018
  */
3937
4019
  cloneShallow () {
3938
4020
  const copy = super.cloneShallow()
3939
4021
  copy.style.cssText = this.style.cssText
4022
+ copy.dirtyValue = this.dirtyValue
4023
+ copy.dirtyChecked = this.dirtyChecked
3940
4024
  return copy
3941
4025
  }
3942
4026