All files / src/internal/client/dom/elements/bindings this.js

100% Statements 63/63
93.75% Branches 15/16
100% Functions 2/2
100% Lines 59/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 602x 2x 2x 2x 2x 2x 2x 2x 2x 2x 253x 253x 253x 253x 253x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 243x 243x 243x 243x 243x 243x 243x 243x 279x 279x 279x 279x 279x 279x 251x 251x 251x 251x 8x 8x 251x 279x 243x 243x 243x 241x 241x 241x 231x 231x 241x 243x 243x 243x  
import { STATE_SYMBOL } from '../../../constants.js';
import { effect, render_effect } from '../../../reactivity/effects.js';
import { untrack } from '../../../runtime.js';
import { queue_micro_task } from '../../task.js';
 
/**
 * @param {any} bound_value
 * @param {Element} element_or_component
 * @returns {boolean}
 */
function is_bound_this(bound_value, element_or_component) {
	// Find the original target if the value is proxied.
	var proxy_target = bound_value && bound_value[STATE_SYMBOL]?.t;
	return bound_value === element_or_component || proxy_target === element_or_component;
}
 
/**
 * @param {Element} element_or_component
 * @param {(value: unknown, ...parts: unknown[]) => void} update
 * @param {(...parts: unknown[]) => unknown} get_value
 * @param {() => unknown[]} [get_parts] Set if the this binding is used inside an each block,
 * 										returns all the parts of the each block context that are used in the expression
 * @returns {void}
 */
export function bind_this(element_or_component, update, get_value, get_parts) {
	effect(() => {
		/** @type {unknown[]} */
		var old_parts;
 
		/** @type {unknown[]} */
		var parts;
 
		render_effect(() => {
			old_parts = parts;
			// We only track changes to the parts, not the value itself to avoid unnecessary reruns.
			parts = get_parts?.() || [];
 
			untrack(() => {
				if (element_or_component !== get_value(...parts)) {
					update(element_or_component, ...parts);
					// If this is an effect rerun (cause: each block context changes), then nullfiy the binding at
					// the previous position if it isn't already taken over by a different effect.
					if (old_parts && is_bound_this(get_value(...old_parts), element_or_component)) {
						update(null, ...old_parts);
					}
				}
			});
		});
 
		return () => {
			// We cannot use effects in the teardown phase, we we use a microtask instead.
			queue_micro_task(() => {
				if (parts && is_bound_this(get_value(...parts), element_or_component)) {
					update(null, ...parts);
				}
			});
		};
	});
}