UNPKG

2.65 kBPlain TextView Raw
1import { getPageview, updatePageview } from './api';
2import { errorHandler, getQuery, getServerURL } from './utils';
3
4import type { WalineAbort } from './typings';
5
6export interface WalinePageviewCountOptions {
7 /**
8 * Waline 服务端地址
9 *
10 * Waline server url
11 */
12 serverURL: string;
13
14 /**
15 * 浏览量 CSS 选择器
16 *
17 * Pageview CSS selector
18 *
19 * @default '.waline-pageview-count'
20 */
21 selector?: string;
22
23 /**
24 * 需要更新和获取的路径
25 *
26 * Path to be fetched and updated
27 *
28 * @default window.location.pathname
29 */
30 path?: string;
31
32 /**
33 * 是否在查询时更新 path 的浏览量
34 *
35 * Whether update pageviews when fetching path result
36 *
37 * @default true
38 */
39 update?: boolean;
40
41 /**
42 * 错误提示消息所使用的语言
43 *
44 * Language of error message
45 *
46 * @default navigator.language
47 */
48 lang?: string;
49}
50
51const renderVisitorCount = (
52 counts: number[],
53 countElements: HTMLElement[]
54): void => {
55 countElements.forEach((element, index) => {
56 element.innerText = counts[index].toString();
57 });
58};
59
60export const pageviewCount = ({
61 serverURL,
62 path = window.location.pathname,
63 selector = '.waline-pageview-count',
64 update = true,
65 lang = navigator.language,
66}: WalinePageviewCountOptions): WalineAbort => {
67 const controller = new AbortController();
68
69 const elements = Array.from(
70 // pageview selectors
71 document.querySelectorAll<HTMLElement>(selector)
72 );
73
74 const filter = (element: HTMLElement): boolean => {
75 const query = getQuery(element);
76
77 return query !== null && path !== query;
78 };
79
80 const fetch = (elements: HTMLElement[]): Promise<void> =>
81 getPageview({
82 serverURL: getServerURL(serverURL),
83 paths: elements.map((element) => getQuery(element) || path),
84 lang,
85 signal: controller.signal,
86 })
87 .then((counts) => renderVisitorCount(counts, elements))
88 .catch(errorHandler);
89
90 // we should update pageviews
91 if (update) {
92 const normalElements = elements.filter((element) => !filter(element));
93 const elementsNeedstoBeFetched = elements.filter(filter);
94
95 void updatePageview({
96 serverURL: getServerURL(serverURL),
97 path,
98 lang,
99 }).then((count) =>
100 renderVisitorCount(
101 new Array<number>(normalElements.length).fill(count),
102 normalElements
103 )
104 );
105
106 // if we should fetch count of other pages
107 if (elementsNeedstoBeFetched.length) {
108 void fetch(elementsNeedstoBeFetched);
109 }
110 }
111 // we should not update pageviews
112 else {
113 void fetch(elements);
114 }
115
116 return controller.abort.bind(controller);
117};