-
Notifications
You must be signed in to change notification settings - Fork 143
/
hooks.ts
89 lines (78 loc) 路 3.25 KB
/
hooks.ts
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { isPlatformServer } from '@angular/common';
import { ObservableInput } from 'rxjs';
import { Attributes, Hooks } from '../types';
import { addCssClassName, cssClassNames, hasCssClassName, removeCssClassName } from '../util/css.util';
import { isChildOfPicture, isImageElement, setImage, setImageAndSourcesToDefault, setImageAndSourcesToError, setImageAndSourcesToLazy, setSourcesToLazy } from '../util/util';
export abstract class SharedHooks<E> extends Hooks<E> {
setup(attributes: Attributes): void {
setImageAndSourcesToDefault(attributes.element, attributes.defaultImagePath, attributes.useSrcset);
if (attributes.imagePath) {
addCssClassName(attributes.element, cssClassNames.loading);
}
if (hasCssClassName(attributes.element, cssClassNames.loaded)) {
removeCssClassName(attributes.element, cssClassNames.loaded);
}
}
finally(attributes: Attributes): void {
addCssClassName(attributes.element, cssClassNames.loaded);
removeCssClassName(attributes.element, cssClassNames.loading);
}
loadImage(attributes: Attributes): ObservableInput<string> {
if (this.skipLazyLoading(attributes)) {
// Set the image right away for bots for better SEO
return [attributes.imagePath];
}
const { element, useSrcset, imagePath, decode } = attributes;
let img: HTMLImageElement;
if (isImageElement(element) && isChildOfPicture(element)) {
const parentClone = element.parentNode!.cloneNode(true) as HTMLPictureElement;
img = parentClone.getElementsByTagName('img')[0];
setSourcesToLazy(img);
setImage(img, imagePath, useSrcset);
} else {
img = new Image();
if (isImageElement(element) && element.referrerPolicy) {
img.referrerPolicy = element.referrerPolicy;
}
if (isImageElement(element) && element.sizes) {
img.sizes = element.sizes;
}
if (useSrcset && 'srcset' in img) {
img.srcset = imagePath;
} else {
img.src = imagePath;
}
}
if (decode && img.decode) {
return img.decode().then(() => imagePath);
}
return new Promise<string>((resolve, reject) => {
img.onload = () => resolve(imagePath);
img.onerror = () => reject(null);
});
}
setErrorImage(error: Error, attributes: Attributes): void {
const { element, useSrcset, errorImagePath } = attributes;
setImageAndSourcesToError(element, errorImagePath, useSrcset);
addCssClassName(element, cssClassNames.failed);
}
setLoadedImage(imagePath: string, attributes: Attributes): void {
const { element, useSrcset } = attributes;
setImageAndSourcesToLazy(element, imagePath, useSrcset);
}
isDisabled(): boolean {
// Disable if SSR and the user isn't a bot
return isPlatformServer(this.platformId) && !this.isBot();
}
skipLazyLoading(attributes: Attributes): boolean {
return this.isBot(attributes);
}
isBot(attributes?: Attributes): boolean {
if (this.navigator?.userAgent) {
return /googlebot|bingbot|yandex|baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest\/0\.|pinterestbot|slackbot|vkShare|W3C_Validator|whatsapp|duckduckbot|prerender/i.test(
this.navigator.userAgent
);
}
return false;
}
}