• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

preactjs / preact / 7508719663

13 Nov 2023 05:07AM UTC coverage: 99.788% (+0.3%) from 99.463%
7508719663

push

github

web-flow
Call options.vnode on rerender (#4209)

1798 of 1839 branches covered (0.0%)

942 of 944 relevant lines covered (99.79%)

1311.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/diff/props.js
1
import { IS_NON_DIMENSIONAL } from '../constants';
2
import options from '../options';
3

4
function setStyle(style, key, value) {
5
        if (key[0] === '-') {
46✔
6
                style.setProperty(key, value == null ? '' : value);
12✔
7
        } else if (value == null) {
34✔
8
                style[key] = '';
9
        } else if (typeof value != 'number' || IS_NON_DIMENSIONAL.test(key)) {
73✔
10
                style[key] = value;
11
        } else {
12
                style[key] = value + 'px';
13
        }
14
}
15

3,424✔
16
/**
1,241✔
17
 * Set a property value on a DOM node
18
 * @param {PreactElement} dom The DOM node to modify
19
 * @param {string} name The name of the property to set
20
 * @param {*} value The value to set the property to
21
 * @param {*} oldValue The old value the property had
3,424✔
22
 * @param {boolean} isSvg Whether or not this DOM node is an SVG node or not
23
 */
3,754✔
24
export function setProperty(dom, name, value, oldValue, isSvg) {
25
        let useCapture;
26

27
        o: if (name === 'style') {
617✔
28
                if (typeof value == 'string') {
41✔
29
                        dom.style.cssText = value;
6✔
30
                } else {
31
                        if (typeof oldValue == 'string') {
37✔
32
                                dom.style.cssText = oldValue = '';
33
                        }
34

35
                        if (oldValue) {
35✔
36
                                for (name in oldValue) {
66✔
37
                                        if (!(value && name in value)) {
21✔
38
                                                setStyle(dom.style, name, '');
34✔
39
                                        }
40
                                }
73✔
41
                        }
42

43
                        if (value) {
35✔
44
                                for (name in value) {
34✔
45
                                        if (!oldValue || value[name] !== oldValue[name]) {
49✔
46
                                                setStyle(dom.style, name, value[name]);
47
                                        }
48
                                }
49
                        }
50
                }
51
        }
52
        // Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6
53
        else if (name[0] === 'o' && name[1] === 'n') {
576✔
54
                useCapture =
165✔
55
                        name !== (name = name.replace(/(PointerCapture)$|Capture$/, '$1'));
56

57
                // Infer correct casing for DOM built-in events:
58
                if (name.toLowerCase() in dom) name = name.toLowerCase().slice(2);
629✔
59
                else name = name.slice(2);
41✔
60

6✔
61
                if (!dom._listeners) dom._listeners = {};
272✔
62
                dom._listeners[name + useCapture] = value;
37✔
63

64
                if (value) {
165✔
65
                        if (!oldValue) {
151✔
66
                                value._attached = Date.now();
35✔
67
                                const handler = useCapture ? eventProxyCapture : eventProxy;
20✔
68
                                dom.addEventListener(name, handler, useCapture);
21✔
69
                        } else {
70
                                value._attached = oldValue._attached;
71
                        }
72
                } else {
73
                        const handler = useCapture ? eventProxyCapture : eventProxy;
14!
74
                        dom.removeEventListener(name, handler, useCapture);
35✔
75
                }
34✔
76
        } else {
49✔
77
                if (isSvg) {
411✔
78
                        // Normalize incorrect prop usage for SVG:
79
                        // - xlink:href / xlinkHref --> href (xlink:href was removed from SVG and isn't needed)
80
                        // - className --> class
81
                        name = name.replace(/xlink(H|:h)/, 'h').replace(/sName$/, 's');
73✔
82
                } else if (
338✔
83
                        name !== 'width' &&
3,557✔
84
                        name !== 'height' &&
588✔
85
                        name !== 'href' &&
165✔
86
                        name !== 'list' &&
87
                        name !== 'form' &&
88
                        // Default value in browsers is `-1` and an empty string is
89
                        // cast to `0` instead
165✔
90
                        name !== 'tabIndex' &&
91
                        name !== 'download' &&
92
                        name !== 'rowSpan' &&
272✔
93
                        name !== 'colSpan' &&
94
                        name !== 'role' &&
95
                        name in dom
165✔
96
                ) {
151✔
97
                        try {
207✔
98
                                dom[name] = value == null ? '' : value;
207✔
99
                                // labelled break is 1b smaller here than a return statement (sorry)
100
                                break o;
203✔
101
                        } catch (e) {}
102
                }
103

104
                // aria- and data- attributes have no boolean representation.
14!
105
                // A `false` value is different from the attribute not being
106
                // present, so we can't remove it. For non-boolean aria
107
                // attributes we could treat false as a removal, but the
423✔
108
                // amount of exceptions would cost too many bytes. On top of
411✔
109
                // that other frameworks generally stringify `false`.
110

111
                if (typeof value == 'function') {
208✔
112
                        // never serialize functions as attribute values
73✔
113
                } else if (value != null && (value !== false || name[4] === '-')) {
338✔
114
                        dom.setAttribute(name, value);
3,557✔
115
                } else {
116
                        dom.removeAttribute(name);
117
                }
118
        }
119
}
120

121
/**
122
 * Proxy an event to hooked event handlers
123
 * @param {PreactEvent} e The event object from the browser
124
 * @private
125
 */
126
function eventProxy(e) {
127
        const eventHandler = this._listeners[e.type + false];
62✔
128
        /**
207✔
129
         * This trick is inspired by Vue https://github.com/vuejs/core/blob/main/packages/runtime-dom/src/modules/events.ts#L90-L101
207✔
130
         * when the dom performs an event it leaves micro-ticks in between bubbling up which means that an event can trigger on a newly
131
         * created DOM-node while the event bubbles up, this can cause quirky behavior as seen in https://github.com/preactjs/preact/issues/3927
203✔
132
         */
133
        if (!e._dispatched) {
62!
134
                // When an event has no _dispatched we know this is the first event-target in the chain
135
                // so we set the initial dispatched time.
136
                e._dispatched = Date.now();
62✔
137
                // When the _dispatched is smaller than the time when the targetted event handler was attached
138
                // we know we have bubbled up to an element that was added during patching the dom.
139
        } else if (e._dispatched <= eventHandler._attached) {
×
140
                return;
141
        }
142
        return eventHandler(options.event ? options.event(e) : e);
270✔
143
}
144

608✔
145
/**
146
 * Proxy an event to hooked event handlers
147
 * @param {PreactEvent} e The event object from the browser
148
 * @private
149
 */
150
function eventProxyCapture(e) {
151
        return this._listeners[e.type + true](options.event ? options.event(e) : e);
5✔
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc