|
1 | 1 | import { DEV } from 'esm-env'; |
2 | | -import { hydrating } from '../hydration.js'; |
3 | | -import { get_descriptors, get_prototype_of } from '../../../shared/utils.js'; |
4 | | -import { create_event, delegate } from './events.js'; |
5 | | -import { add_form_reset_listener, autofocus } from './misc.js'; |
6 | | -import * as w from '../../warnings.js'; |
7 | | -import { LOADING_ATTR_SYMBOL } from '../../constants.js'; |
8 | | -import { queue_idle_task } from '../task.js'; |
9 | 2 | import { is_capture_event, is_delegated, normalize_attribute } from '../../../../utils.js'; |
| 3 | +import { clsx } from '../../../shared/attributes.js'; |
| 4 | +import { define_property, get_descriptors, get_prototype_of } from '../../../shared/utils.js'; |
| 5 | +import { LOADING_ATTR_SYMBOL } from '../../constants.js'; |
10 | 6 | import { |
11 | 7 | active_effect, |
12 | 8 | active_reaction, |
13 | 9 | set_active_effect, |
14 | 10 | set_active_reaction |
15 | 11 | } from '../../runtime.js'; |
16 | | -import { clsx } from '../../../shared/attributes.js'; |
| 12 | +import * as w from '../../warnings.js'; |
| 13 | +import { hydrating } from '../hydration.js'; |
| 14 | +import { queue_idle_task } from '../task.js'; |
| 15 | +import { create_event, delegate } from './events.js'; |
| 16 | +import { add_form_reset_listener, autofocus } from './misc.js'; |
17 | 17 |
|
18 | 18 | /** |
19 | 19 | * The value/checked attribute in the template actually corresponds to the defaultValue property, so we need |
@@ -515,11 +515,54 @@ export function handle_lazy_img(element) { |
515 | 515 | // templates. |
516 | 516 | if (!hydrating && element.loading === 'lazy') { |
517 | 517 | var src = element.src; |
| 518 | + var loading = element.loading; |
518 | 519 | // @ts-expect-error |
519 | 520 | element[LOADING_ATTR_SYMBOL] = null; |
520 | 521 | element.loading = 'eager'; |
521 | 522 | element.removeAttribute('src'); |
| 523 | + |
| 524 | + // since we are removing src before the first animation frame if someone |
| 525 | + // access src or loading on mount or in an action they will have the wrong value |
| 526 | + // so we define those two properties so that if accessed through JS it will |
| 527 | + // return the correct value. Since we can't undo this we also mimic the behavior |
| 528 | + // of setting the attribute in the setter |
| 529 | + define_property(element, 'src', { |
| 530 | + get() { |
| 531 | + return src; |
| 532 | + }, |
| 533 | + set(new_src) { |
| 534 | + element.setAttribute('src', new_src); |
| 535 | + src = new_src; |
| 536 | + }, |
| 537 | + configurable: true, |
| 538 | + enumerable: true |
| 539 | + }); |
| 540 | + define_property(element, 'loading', { |
| 541 | + get() { |
| 542 | + return loading; |
| 543 | + }, |
| 544 | + set(new_loading) { |
| 545 | + element.setAttribute('loading', new_loading); |
| 546 | + loading = new_loading; |
| 547 | + }, |
| 548 | + configurable: true, |
| 549 | + enumerable: true |
| 550 | + }); |
| 551 | + |
| 552 | + // same story as above with getAttribute...we fake it until we restore the |
| 553 | + // old `setAttribute` value after the first animation frame |
| 554 | + const old_get_attribute = element.getAttribute; |
| 555 | + element.getAttribute = (name) => { |
| 556 | + if (name === 'src') { |
| 557 | + return src; |
| 558 | + } |
| 559 | + if (name === 'loading') { |
| 560 | + return loading; |
| 561 | + } |
| 562 | + return old_get_attribute.call(element, name); |
| 563 | + }; |
522 | 564 | requestAnimationFrame(() => { |
| 565 | + element.getAttribute = old_get_attribute; |
523 | 566 | // @ts-expect-error |
524 | 567 | if (element[LOADING_ATTR_SYMBOL] !== 'eager') { |
525 | 568 | element.loading = 'lazy'; |
|
0 commit comments