@waline/client 3.5.1 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,465 @@
1
+ import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
+
3
+ type WalineCommentSorting = 'latest' | 'oldest' | 'hottest';
4
+
5
+ type WalineEmojiPresets =
6
+ | `//${string}`
7
+ | `http://${string}`
8
+ | `https://${string}`;
9
+
10
+ interface WalineEmojiInfo {
11
+ /**
12
+ * 选项卡上的 Emoji 名称
13
+ *
14
+ * Emoji name show on tab
15
+ */
16
+ name: string;
17
+ /**
18
+ * 所在文件夹链接
19
+ *
20
+ * Current folder link
21
+ */
22
+ folder?: string;
23
+ /**
24
+ * Emoji 通用路径前缀
25
+ *
26
+ * Common prefix of Emoji icons
27
+ */
28
+ prefix?: string;
29
+ /**
30
+ * Emoji 图片的类型,会作为文件扩展名使用
31
+ *
32
+ * Type of Emoji icons, will be regarded as file extension
33
+ */
34
+ type?: string;
35
+ /**
36
+ * 选项卡显示的 Emoji 图标
37
+ *
38
+ * Emoji icon show on tab
39
+ */
40
+ icon: string;
41
+ /**
42
+ * Emoji 图片列表
43
+ *
44
+ * Emoji image list
45
+ */
46
+ items: string[];
47
+ }
48
+
49
+ type WalineLoginStatus = 'enable' | 'disable' | 'force';
50
+
51
+ interface WalineSearchImageData extends Record<string, unknown> {
52
+ /**
53
+ * 图片链接
54
+ *
55
+ * Image link
56
+ */
57
+ src: string;
58
+
59
+ /**
60
+ * 图片标题
61
+ *
62
+ * @description 用于图片的 alt 属性
63
+ *
64
+ * Image title
65
+ *
66
+ * @description Used for alt attribute of image
67
+ */
68
+ title?: string;
69
+
70
+ /**
71
+ * 图片缩略图
72
+ *
73
+ * @description 为了更好的加载性能,我们会优先在列表中使用此缩略图
74
+ *
75
+ * Image preview link
76
+ *
77
+ * @description For better loading performance, we will use this thumbnail first in the list
78
+ *
79
+ * @default src
80
+ */
81
+ preview?: string;
82
+ }
83
+
84
+ type WalineSearchResult = WalineSearchImageData[];
85
+
86
+ interface WalineSearchOptions {
87
+ /**
88
+ * 搜索操作
89
+ *
90
+ * Search action
91
+ */
92
+ search: (word: string) => Promise<WalineSearchResult>;
93
+
94
+ /**
95
+ * 打开列表时展示的默认结果
96
+ *
97
+ * Default result when opening list
98
+ *
99
+ * @default () => search('')
100
+ */
101
+ default?: () => Promise<WalineSearchResult>;
102
+
103
+ /**
104
+ * 获取更多的操作
105
+ *
106
+ * @description 会在列表滚动到底部时触发,如果你的搜索服务支持分页功能,你应该设置此项实现无限滚动
107
+ *
108
+ * Fetch more action
109
+ *
110
+ * @description It will be triggered when the list scrolls to the bottom. If your search service supports paging, you should set this to achieve infinite scrolling
111
+ *
112
+ * @default (word) => search(word)
113
+ */
114
+ more?: (word: string, currentCount: number) => Promise<WalineSearchResult>;
115
+ }
116
+
117
+ type WalineMeta = 'nick' | 'mail' | 'link';
118
+
119
+ type WalineImageUploader = (image: File) => Promise<string>;
120
+
121
+ type WalineHighlighter = (code: string, lang: string) => string;
122
+
123
+ type WalineTeXRenderer = (blockMode: boolean, tex: string) => string;
124
+
125
+ interface WalineDateLocale {
126
+ seconds: string;
127
+ minutes: string;
128
+ hours: string;
129
+ days: string;
130
+ now: string;
131
+ }
132
+
133
+ type WalineLevelLocale = Record<`level${number}`, string>;
134
+
135
+ interface WalineReactionLocale {
136
+ reactionTitle: string;
137
+ reaction0: string;
138
+ reaction1: string;
139
+ reaction2: string;
140
+ reaction3: string;
141
+ reaction4: string;
142
+ reaction5: string;
143
+ reaction6: string;
144
+ reaction7: string;
145
+ reaction8: string;
146
+ }
147
+
148
+ interface WalineLocale
149
+ extends WalineDateLocale,
150
+ WalineLevelLocale,
151
+ WalineReactionLocale {
152
+ nick: string;
153
+ mail: string;
154
+ link: string;
155
+ optional: string;
156
+ placeholder: string;
157
+ sofa: string;
158
+ submit: string;
159
+ comment: string;
160
+ refresh: string;
161
+ more: string;
162
+ uploading: string;
163
+ login: string;
164
+ admin: string;
165
+ sticky: string;
166
+ word: string;
167
+ anonymous: string;
168
+ gif: string;
169
+ gifSearchPlaceholder: string;
170
+
171
+ // manage
172
+ approved: string;
173
+ waiting: string;
174
+ spam: string;
175
+ unsticky: string;
176
+
177
+ // sorting
178
+ oldest: string;
179
+ latest: string;
180
+ hottest: string;
181
+
182
+ // hint
183
+ nickError: string;
184
+ mailError: string;
185
+ wordHint: string;
186
+
187
+ // i18n
188
+ like: string;
189
+ cancelLike: string;
190
+ reply: string;
191
+ cancelReply: string;
192
+ preview: string;
193
+ emoji: string;
194
+ uploadImage: string;
195
+ profile: string;
196
+ logout: string;
197
+ }
198
+
199
+ interface WalineProps {
200
+ /**
201
+ * Waline 的服务端地址
202
+ *
203
+ * Waline server address url
204
+ */
205
+ serverURL: string;
206
+
207
+ /**
208
+ * 当前 _文章页_ 路径,用于区分不同的 _文章页_ ,以保证正确读取该 _文章页_ 下的评论列表
209
+ *
210
+ * 你可以将其设置为 `window.location.pathname`
211
+ *
212
+ * Article path id. Used to distinguish different _article pages_ to ensure loading the correct comment list under the _article page_.
213
+ *
214
+ * You can set it to `window.location.pathname`
215
+ */
216
+ path: string;
217
+
218
+ /**
219
+ * 评论者相关属性
220
+ *
221
+ * `Meta` 可选值: `'nick'`, `'mail'`, `'link'`
222
+ *
223
+ * Reviewer attributes.
224
+ *
225
+ * Optional values for `Meta`: `'nick'`, `'mail'`, `'link'`
226
+ *
227
+ * @default ['nick', 'mail', 'link']
228
+ */
229
+ meta?: WalineMeta[];
230
+
231
+ /**
232
+ * 设置**必填项**,默认昵称为匿名
233
+ *
234
+ * Set required fields, default anonymous with nickname
235
+ *
236
+ * @default []
237
+ */
238
+ requiredMeta?: WalineMeta[];
239
+
240
+ /**
241
+ * 评论字数限制。填入单个数字时为最大字数限制
242
+ *
243
+ * @more 设置为 `0` 时无限制
244
+ *
245
+ * Comment word s limit. When a single number is filled in, it 's the maximum number of comment words.
246
+ *
247
+ * @more No limit when set to `0`.
248
+ *
249
+ * @default 0
250
+ */
251
+ wordLimit?: number | [number, number];
252
+
253
+ /**
254
+ * 评论列表分页,每页条数
255
+ *
256
+ * number of pages per page
257
+ *
258
+ * @default 10
259
+ */
260
+ pageSize?: number;
261
+
262
+ /**
263
+ * Waline 显示语言
264
+ *
265
+ * 可选值:
266
+ *
267
+ * - `'zh'`
268
+ * - `'zh-cn'`
269
+ * - `'zh-CN'`
270
+ * - `'zh-tw'`
271
+ * - `'zh-TW'`
272
+ * - `'en'`
273
+ * - `'en-US'`
274
+ * - `'en-us'`
275
+ * - `'jp'`
276
+ * - `'jp-jp'`
277
+ * - `'jp-JP'`
278
+ * - `'pt-br'`
279
+ * - `'pt-BR'`
280
+ * - `'ru'`
281
+ * - `'ru-ru'`
282
+ * - `'ru-RU'`
283
+ * - `'fr-FR'`
284
+ * - `'fr'`
285
+ *
286
+ * Display language for waline
287
+ *
288
+ * Optional value:
289
+ *
290
+ * - `'zh'`
291
+ * - `'zh-cn'`
292
+ * - `'zh-CN'`
293
+ * - `'zh-tw'`
294
+ * - `'zh-TW'`
295
+ * - `'en'`
296
+ * - `'en-US'`
297
+ * - `'en-us'`
298
+ * - `'jp'`
299
+ * - `'jp-jp'`
300
+ * - `'jp-JP'`
301
+ * - `'pt-br'`
302
+ * - `'pt-BR'`
303
+ * - `'ru'`
304
+ * - `'ru-ru'`
305
+ * - `'ru-RU'`
306
+ * - `'fr-FR'`
307
+ * - `'fr'`
308
+ *
309
+ * @default navigator.language
310
+ */
311
+ lang?: string;
312
+
313
+ /**
314
+ * 自定义 waline 语言显示
315
+ *
316
+ * @see [自定义语言](https://waline.js.org/client/i18n.html)
317
+ *
318
+ * Custom display language in waline
319
+ *
320
+ * @see [I18n](https://waline.js.org/en/client/i18n.html)
321
+ */
322
+ locale?: Partial<WalineLocale>;
323
+
324
+ /**
325
+ * 评论列表排序方式
326
+ *
327
+ * Sorting method for comment list
328
+ *
329
+ * @default 'latest'
330
+ */
331
+ commentSorting?: WalineCommentSorting;
332
+
333
+ /**
334
+ * 是否启用暗黑模式适配
335
+ *
336
+ * @more 设置 `'auto'` 会根据设备暗黑模式自适应。填入 CSS 选择器会在对应选择器生效时启用夜间模式。
337
+ *
338
+ * Whether to enable darkmode support
339
+ *
340
+ * @more Setting `'auto'` will display darkmode due to device settings. Filling in CSS selector will enable darkmode only when the selector match waline ancestor nodes.
341
+ */
342
+ dark?: string | boolean;
343
+
344
+ /**
345
+ *
346
+ * 登录模式状态,可选值:
347
+ *
348
+ * - `'enable'`: 启用登录 (默认)
349
+ * - `'disable'`: 禁用登录,用户只能填写信息评论
350
+ * - `'force'`: 强制登录,用户必须注册并登录才可发布评论
351
+ *
352
+ * Login mode status, optional values:
353
+ *
354
+ * - `'enable'`: enable login (default)
355
+ * - `'disable'`: Login is disabled, users should fill in information to comment
356
+ * - `'force'`: Forced login, users must login to comment
357
+ *
358
+ * @default 'enable'
359
+ */
360
+ login?: WalineLoginStatus;
361
+
362
+ /**
363
+ * 是否在页脚隐藏版权信息
364
+ *
365
+ * 为了支持 Waline,我们强烈建议你开启它
366
+ *
367
+ * Whether hide copyright in footer
368
+ *
369
+ * We strongly recommended you to keep it on to support waline
370
+ *
371
+ */
372
+ noCopyright?: boolean;
373
+
374
+ /**
375
+ * recaptcha v3 客户端 key
376
+ *
377
+ * recaptcha v3 client key
378
+ */
379
+ recaptchaV3Key?: string;
380
+
381
+ /**
382
+ * turnstile 客户端 key
383
+ *
384
+ * turnstile client key
385
+ */
386
+ turnstileKey?: string;
387
+
388
+ /**
389
+ * 文章反应
390
+ *
391
+ * Article reaction
392
+ */
393
+ reaction?: string[];
394
+
395
+ /**
396
+ * 设置表情包
397
+ *
398
+ * Set Emojis
399
+ *
400
+ * @default ['//unpkg.com/@waline/emojis@1.1.0/weibo']
401
+ */
402
+ emoji?: (WalineEmojiInfo | WalineEmojiPresets)[];
403
+
404
+ /**
405
+ * 设置搜索功能
406
+ *
407
+ * Customize Search feature
408
+ */
409
+ search?: WalineSearchOptions;
410
+
411
+ /**
412
+ * 代码块高亮器
413
+ *
414
+ * Code fence highlighter
415
+ */
416
+
417
+ highlighter?: WalineHighlighter;
418
+
419
+ /**
420
+ * 自定义图片上传方法,方便更好的存储图片
421
+ *
422
+ * 方法执行时会将图片对象传入。
423
+ *
424
+ * Custom image upload callback to manage picture by yourself.
425
+ *
426
+ * We will pass a picture file object when execute it.
427
+ */
428
+
429
+ imageUploader?: WalineImageUploader;
430
+
431
+ /**
432
+ * 自定义数学公式处理方法,用于预览。
433
+ *
434
+ * Custom math formula parse callback for preview.
435
+ */
436
+ texRenderer?: WalineTeXRenderer;
437
+ }
438
+
439
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
440
+
441
+
442
+ declare const _default: DefineComponent<
443
+ WalineProps,
444
+ {},
445
+ {},
446
+ {},
447
+ {},
448
+ ComponentOptionsMixin,
449
+ ComponentOptionsMixin,
450
+ {},
451
+ string,
452
+ PublicProps,
453
+ Readonly<WalineProps> & Readonly<{}>,
454
+ {},
455
+ {},
456
+ {},
457
+ {},
458
+ string,
459
+ ComponentProvideOptions,
460
+ false,
461
+ {},
462
+ HTMLDivElement
463
+ >;
464
+
465
+ export { _default as default };
package/dist/pageview.js CHANGED
@@ -1,2 +1,2 @@
1
- const v="3.5.1",$={"Content-Type":"application/json"},h=e=>`${e.replace(/\/?$/,"/")}api/`,u=(e,t="")=>{if(typeof e=="object"&&e.errno)throw new TypeError(`${t} failed with ${e.errno}: ${e.errmsg}`);return e},f=({serverURL:e,lang:t,paths:r,type:o,signal:a})=>fetch(`${h(e)}article?path=${encodeURIComponent(r.join(","))}&type=${encodeURIComponent(o.join(","))}&lang=${t}`,{signal:a}).then(n=>n.json()).then(n=>u(n,"Get counter").data),R=({serverURL:e,lang:t,path:r,type:o,action:a})=>fetch(`${h(e)}article?lang=${t}`,{method:"POST",headers:$,body:JSON.stringify({path:r,type:o,action:a})}).then(n=>n.json()).then(n=>u(n,"Update counter").data),U=({serverURL:e,lang:t,paths:r,signal:o})=>f({serverURL:e,lang:t,paths:r,type:["time"],signal:o}),w=e=>R({...e,type:"time",action:"inc"}),L=(e="")=>e.replace(/\/$/u,""),b=e=>/^(https?:)?\/\//.test(e),d=e=>{const t=L(e);return b(t)?t:`https://${t}`},j=e=>{e.name!=="AbortError"&&console.error(e.message)},m=e=>{const{path:t}=e.dataset;return t!=null&&t.length?t:null},y=(e,t)=>{t.forEach((r,o)=>{const a=e[o].time;typeof a=="number"&&(r.innerText=a.toString())})},S=({serverURL:e,path:t=window.location.pathname,selector:r=".waline-pageview-count",update:o=!0,lang:a=navigator.language})=>{const n=new AbortController,i=Array.from(document.querySelectorAll(r)),p=l=>{const s=m(l);return s!==null&&t!==s},g=l=>U({serverURL:d(e),paths:l.map(s=>m(s)??t),lang:a,signal:n.signal}).then(s=>y(s,l)).catch(j);if(o){const l=i.filter(c=>!p(c)),s=i.filter(p);w({serverURL:d(e),path:t,lang:a}).then(c=>y(c,l)),s.length&&g(s)}else g(i);return n.abort.bind(n)};export{S as pageviewCount,v as version};
1
+ const v="3.5.3",$={"Content-Type":"application/json"},h=e=>`${e.replace(/\/?$/,"/")}api/`,u=(e,t="")=>{if(typeof e=="object"&&e.errno)throw new TypeError(`${t} failed with ${e.errno}: ${e.errmsg}`);return e},f=({serverURL:e,lang:t,paths:r,type:o,signal:a})=>fetch(`${h(e)}article?path=${encodeURIComponent(r.join(","))}&type=${encodeURIComponent(o.join(","))}&lang=${t}`,{signal:a}).then(n=>n.json()).then(n=>u(n,"Get counter").data),R=({serverURL:e,lang:t,path:r,type:o,action:a})=>fetch(`${h(e)}article?lang=${t}`,{method:"POST",headers:$,body:JSON.stringify({path:r,type:o,action:a})}).then(n=>n.json()).then(n=>u(n,"Update counter").data),U=({serverURL:e,lang:t,paths:r,signal:o})=>f({serverURL:e,lang:t,paths:r,type:["time"],signal:o}),w=e=>R({...e,type:"time",action:"inc"}),L=(e="")=>e.replace(/\/$/u,""),b=e=>/^(https?:)?\/\//.test(e),d=e=>{const t=L(e);return b(t)?t:`https://${t}`},j=e=>{e.name!=="AbortError"&&console.error(e.message)},m=e=>{const{path:t}=e.dataset;return t!=null&&t.length?t:null},y=(e,t)=>{t.forEach((r,o)=>{const a=e[o].time;typeof a=="number"&&(r.innerText=a.toString())})},S=({serverURL:e,path:t=window.location.pathname,selector:r=".waline-pageview-count",update:o=!0,lang:a=navigator.language})=>{const n=new AbortController,i=Array.from(document.querySelectorAll(r)),p=l=>{const s=m(l);return s!==null&&t!==s},g=l=>U({serverURL:d(e),paths:l.map(s=>m(s)??t),lang:a,signal:n.signal}).then(s=>y(s,l)).catch(j);if(o){const l=i.filter(c=>!p(c)),s=i.filter(p);w({serverURL:d(e),path:t,lang:a}).then(c=>y(c,l)),s.length&&g(s)}else g(i);return n.abort.bind(n)};export{S as pageviewCount,v as version};
2
2
  //# sourceMappingURL=pageview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pageview.js","sources":["../src/version.ts","../../api/dist/api.js","../src/utils/path.ts","../src/utils/config.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","const m={\"Content-Type\":\"application/json\"},s=e=>`${e.replace(/\\/?$/,\"/\")}api/`,c=(e,n=\"\")=>{if(typeof e==\"object\"&&e.errno)throw new TypeError(`${n} failed with ${e.errno}: ${e.errmsg}`);return e},p=({serverURL:e,lang:n,paths:o,type:a,signal:t})=>fetch(`${s(e)}article?path=${encodeURIComponent(o.join(\",\"))}&type=${encodeURIComponent(a.join(\",\"))}&lang=${n}`,{signal:t}).then(r=>r.json()).then(r=>c(r,\"Get counter\").data),d=({serverURL:e,lang:n,path:o,type:a,action:t})=>fetch(`${s(e)}article?lang=${n}`,{method:\"POST\",headers:m,body:JSON.stringify({path:o,type:a,action:t})}).then(r=>r.json()).then(r=>c(r,\"Update counter\").data),$=({serverURL:e,lang:n,path:o,page:a,pageSize:t,sortBy:r,signal:h,token:i})=>{const l={};return i&&(l.Authorization=`Bearer ${i}`),fetch(`${s(e)}comment?path=${encodeURIComponent(o)}&pageSize=${t}&page=${a}&lang=${n}&sortBy=${r}`,{signal:h,headers:l}).then(g=>g.json()).then(g=>c(g,\"Get comment data\").data)},u=({serverURL:e,lang:n,token:o,comment:a})=>{const t={\"Content-Type\":\"application/json\"};return o&&(t.Authorization=`Bearer ${o}`),fetch(`${s(e)}comment?lang=${n}`,{method:\"POST\",headers:t,body:JSON.stringify(a)}).then(r=>r.json())},y=({serverURL:e,lang:n,token:o,objectId:a})=>fetch(`${s(e)}comment/${a}?lang=${n}`,{method:\"DELETE\",headers:{Authorization:`Bearer ${o}`}}).then(t=>t.json()).then(t=>c(t,\"Delete comment\")),U=({serverURL:e,lang:n,token:o,objectId:a,comment:t})=>fetch(`${s(e)}comment/${a}?lang=${n}`,{method:\"PUT\",headers:{...m,Authorization:`Bearer ${o}`},body:JSON.stringify(t)}).then(r=>r.json()).then(r=>c(r,\"Update comment\")),f=({serverURL:e,lang:n,paths:o,signal:a})=>fetch(`${s(e)}comment?type=count&url=${encodeURIComponent(o.join(\",\"))}&lang=${n}`,{signal:a}).then(t=>t.json()).then(t=>c(t,\"Get comment count\").data),R=({lang:e,serverURL:n})=>{const o=(window.innerWidth-450)/2,a=(window.innerHeight-450)/2,t=window.open(`${n.replace(/\\/$/,\"\")}/ui/login?lng=${encodeURIComponent(e)}`,\"_blank\",`width=450,height=450,left=${o},top=${a},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`);return t?.postMessage({type:\"TOKEN\",data:null},\"*\"),new Promise(r=>{const h=({data:i})=>{!i||typeof i!=\"object\"||i.type!==\"userInfo\"||i.data.token&&(t?.close(),window.removeEventListener(\"message\",h),r(i.data))};window.addEventListener(\"message\",h)})},j=({serverURL:e,lang:n,paths:o,signal:a})=>p({serverURL:e,lang:n,paths:o,type:[\"time\"],signal:a}),v=e=>d({...e,type:\"time\",action:\"inc\"}),w=({serverURL:e,lang:n,count:o,signal:a,token:t})=>{const r={};return t&&(r.Authorization=`Bearer ${t}`),fetch(`${s(e)}comment?type=recent&count=${o}&lang=${n}`,{signal:a,headers:r}).then(h=>h.json())},C=({serverURL:e,signal:n,pageSize:o,lang:a})=>fetch(`${s(e)}user?pageSize=${o}&lang=${a}`,{signal:n}).then(t=>t.json()).then(t=>c(t,\"user list\")).then(t=>t.data);export{u as addComment,y as deleteComment,f as fetchCommentCount,p as getArticleCounter,$ as getComment,j as getPageview,w as getRecentComment,C as getUserList,R as login,d as updateArticleCounter,U as updateComment,v as updatePageview};\n//# sourceMappingURL=api.js.map\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch {\n // ignore error\n }\n\n return path;\n};\n\nexport const removeEndingSplash = (content = ''): string =>\n content.replace(/\\/$/u, '');\n\nexport const isLinkHttp = (link: string): boolean =>\n /^(https?:)?\\/\\//.test(link);\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_REACTION,\n defaultHighlighter,\n defaultTeXRenderer,\n defaultUploadImage,\n getDefaultSearchOptions,\n getLang,\n getLocale,\n getMeta,\n} from '../config/index.js';\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineEmojiPresets,\n WalineHighlighter,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n WalineSearchOptions,\n WalineTeXRenderer,\n} from '../typings/index.js';\n\nexport interface WalineEmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface WalineConfig\n extends Required<\n Omit<\n WalineProps,\n | 'emoji'\n | 'imageUploader'\n | 'highlighter'\n | 'texRenderer'\n | 'wordLimit'\n | 'reaction'\n | 'search'\n >\n > {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n emoji: (WalineEmojiInfo | WalineEmojiPresets)[] | null;\n highlighter: WalineHighlighter | null;\n imageUploader: WalineImageUploader | null;\n texRenderer: WalineTeXRenderer | null;\n search: WalineSearchOptions | null;\n reaction: string[] | null;\n}\n\nexport const getServerURL = (serverURL: string): string => {\n const result = removeEndingSplash(serverURL);\n\n return isLinkHttp(result) ? result : `https://${result}`;\n};\n\nconst getWordLimit = (\n wordLimit: WalineProps['wordLimit'],\n): [number, number] | false =>\n Array.isArray(wordLimit) ? wordLimit : wordLimit ? [0, wordLimit] : false;\n\nconst fallback = <T = unknown>(\n value: T | boolean | undefined,\n fallback: T,\n): T | null =>\n value == undefined || value === true\n ? fallback\n : value === false\n ? null\n : value;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n noCopyright = false,\n login = 'enable',\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n emoji = DEFAULT_EMOJI,\n imageUploader,\n highlighter,\n texRenderer,\n search,\n reaction,\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n lang: getLang(lang),\n locale: {\n ...getLocale(getLang(lang)),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n dark,\n pageSize,\n commentSorting,\n login,\n noCopyright,\n recaptchaV3Key,\n turnstileKey,\n ...more,\n reaction: fallback(reaction, DEFAULT_REACTION),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTeXRenderer),\n emoji: fallback(emoji, DEFAULT_EMOJI),\n search: fallback(search, getDefaultSearchOptions(lang)),\n});\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","export const getQuery = (element: HTMLElement): string | null => {\n const { path } = element.dataset;\n\n return path?.length ? path : null;\n};\n","import type { GetArticleCounterResponse } from '@waline/api';\nimport { getPageview, updatePageview } from '@waline/api';\n\nimport type { WalineAbort } from './typings/index.js';\nimport { errorHandler, getQuery, getServerURL } from './utils/index.js';\n\nexport interface WalinePageviewCountOptions {\n /**\n * Waline 服务端地址\n *\n * Waline server url\n */\n serverURL: string;\n\n /**\n * 浏览量 CSS 选择器\n *\n * Pageview CSS selector\n *\n * @default '.waline-pageview-count'\n */\n selector?: string;\n\n /**\n * 需要更新和获取的路径\n *\n * Path to be fetched and updated\n *\n * @default window.location.pathname\n */\n path?: string;\n\n /**\n * 是否在查询时更新 path 的浏览量\n *\n * Whether update pageviews when fetching path result\n *\n * @default true\n */\n update?: boolean;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default navigator.language\n */\n lang?: string;\n}\n\nconst renderVisitorCount = (\n counts: GetArticleCounterResponse,\n countElements: HTMLElement[],\n): void => {\n countElements.forEach((element, index) => {\n const count = counts[index].time;\n\n if (typeof count !== 'number') {\n return;\n }\n\n element.innerText = count.toString();\n });\n};\n\nexport const pageviewCount = ({\n serverURL,\n path = window.location.pathname,\n selector = '.waline-pageview-count',\n update = true,\n lang = navigator.language,\n}: WalinePageviewCountOptions): WalineAbort => {\n const controller = new AbortController();\n\n const elements = Array.from(\n // pageview selectors\n document.querySelectorAll<HTMLElement>(selector),\n );\n\n const filter = (element: HTMLElement): boolean => {\n const query = getQuery(element);\n\n return query !== null && path !== query;\n };\n\n const fetch = (elements: HTMLElement[]): Promise<void> =>\n getPageview({\n serverURL: getServerURL(serverURL),\n paths: elements.map((element) => getQuery(element) ?? path),\n lang,\n signal: controller.signal,\n })\n .then((counts) => renderVisitorCount(counts, elements))\n .catch(errorHandler);\n\n // we should update pageviews\n if (update) {\n const normalElements = elements.filter((element) => !filter(element));\n const elementsNeedstoBeFetched = elements.filter(filter);\n\n void updatePageview({\n serverURL: getServerURL(serverURL),\n path,\n lang,\n }).then((counts) => renderVisitorCount(counts, normalElements));\n\n // if we should fetch count of other pages\n if (elementsNeedstoBeFetched.length) {\n void fetch(elementsNeedstoBeFetched);\n }\n }\n // we should not update pageviews\n else {\n void fetch(elements);\n }\n\n return controller.abort.bind(controller);\n};\n"],"names":["version","m","s","e","c","n","p","o","a","t","r","d","j","v","removeEndingSplash","content","isLinkHttp","link","getServerURL","serverURL","result","errorHandler","err","getQuery","element","path","renderVisitorCount","counts","countElements","index","count","pageviewCount","selector","update","lang","controller","elements","filter","query","fetch","getPageview","normalElements","elementsNeedstoBeFetched","updatePageview"],"mappings":"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"}
1
+ {"version":3,"file":"pageview.js","sources":["../src/version.ts","../../api/dist/api.js","../src/utils/path.ts","../src/utils/config.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","const m={\"Content-Type\":\"application/json\"},s=e=>`${e.replace(/\\/?$/,\"/\")}api/`,c=(e,n=\"\")=>{if(typeof e==\"object\"&&e.errno)throw new TypeError(`${n} failed with ${e.errno}: ${e.errmsg}`);return e},p=({serverURL:e,lang:n,paths:o,type:a,signal:t})=>fetch(`${s(e)}article?path=${encodeURIComponent(o.join(\",\"))}&type=${encodeURIComponent(a.join(\",\"))}&lang=${n}`,{signal:t}).then(r=>r.json()).then(r=>c(r,\"Get counter\").data),d=({serverURL:e,lang:n,path:o,type:a,action:t})=>fetch(`${s(e)}article?lang=${n}`,{method:\"POST\",headers:m,body:JSON.stringify({path:o,type:a,action:t})}).then(r=>r.json()).then(r=>c(r,\"Update counter\").data),$=({serverURL:e,lang:n,path:o,page:a,pageSize:t,sortBy:r,signal:h,token:i})=>{const l={};return i&&(l.Authorization=`Bearer ${i}`),fetch(`${s(e)}comment?path=${encodeURIComponent(o)}&pageSize=${t}&page=${a}&lang=${n}&sortBy=${r}`,{signal:h,headers:l}).then(g=>g.json()).then(g=>c(g,\"Get comment data\").data)},u=({serverURL:e,lang:n,token:o,comment:a})=>{const t={\"Content-Type\":\"application/json\"};return o&&(t.Authorization=`Bearer ${o}`),fetch(`${s(e)}comment?lang=${n}`,{method:\"POST\",headers:t,body:JSON.stringify(a)}).then(r=>r.json())},y=({serverURL:e,lang:n,token:o,objectId:a})=>fetch(`${s(e)}comment/${a}?lang=${n}`,{method:\"DELETE\",headers:{Authorization:`Bearer ${o}`}}).then(t=>t.json()).then(t=>c(t,\"Delete comment\")),U=({serverURL:e,lang:n,token:o,objectId:a,comment:t})=>fetch(`${s(e)}comment/${a}?lang=${n}`,{method:\"PUT\",headers:{...m,Authorization:`Bearer ${o}`},body:JSON.stringify(t)}).then(r=>r.json()).then(r=>c(r,\"Update comment\")),f=({serverURL:e,lang:n,paths:o,signal:a})=>fetch(`${s(e)}comment?type=count&url=${encodeURIComponent(o.join(\",\"))}&lang=${n}`,{signal:a}).then(t=>t.json()).then(t=>c(t,\"Get comment count\").data),R=({lang:e,serverURL:n})=>{const o=(window.innerWidth-450)/2,a=(window.innerHeight-450)/2,t=window.open(`${n.replace(/\\/$/,\"\")}/ui/login?lng=${encodeURIComponent(e)}`,\"_blank\",`width=450,height=450,left=${o},top=${a},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`);return t?.postMessage({type:\"TOKEN\",data:null},\"*\"),new Promise(r=>{const h=({data:i})=>{!i||typeof i!=\"object\"||i.type!==\"userInfo\"||i.data.token&&(t?.close(),window.removeEventListener(\"message\",h),r(i.data))};window.addEventListener(\"message\",h)})},j=({serverURL:e,lang:n,paths:o,signal:a})=>p({serverURL:e,lang:n,paths:o,type:[\"time\"],signal:a}),v=e=>d({...e,type:\"time\",action:\"inc\"}),w=({serverURL:e,lang:n,count:o,signal:a,token:t})=>{const r={};return t&&(r.Authorization=`Bearer ${t}`),fetch(`${s(e)}comment?type=recent&count=${o}&lang=${n}`,{signal:a,headers:r}).then(h=>h.json())},C=({serverURL:e,signal:n,pageSize:o,lang:a})=>fetch(`${s(e)}user?pageSize=${o}&lang=${a}`,{signal:n}).then(t=>t.json()).then(t=>c(t,\"user list\")).then(t=>t.data);export{u as addComment,y as deleteComment,f as fetchCommentCount,p as getArticleCounter,$ as getComment,j as getPageview,w as getRecentComment,C as getUserList,R as login,d as updateArticleCounter,U as updateComment,v as updatePageview};\n//# sourceMappingURL=api.js.map\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch {\n // ignore error\n }\n\n return path;\n};\n\nexport const removeEndingSplash = (content = ''): string =>\n content.replace(/\\/$/u, '');\n\nexport const isLinkHttp = (link: string): boolean =>\n /^(https?:)?\\/\\//.test(link);\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_REACTION,\n defaultHighlighter,\n defaultTeXRenderer,\n defaultUploadImage,\n getDefaultSearchOptions,\n getLang,\n getLocale,\n getMeta,\n} from '../config/index.js';\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineEmojiPresets,\n WalineHighlighter,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n WalineSearchOptions,\n WalineTeXRenderer,\n} from '../typings/index.js';\n\nexport interface WalineEmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface WalineConfig\n extends Required<\n Omit<\n WalineProps,\n | 'emoji'\n | 'imageUploader'\n | 'highlighter'\n | 'texRenderer'\n | 'wordLimit'\n | 'reaction'\n | 'search'\n >\n > {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n emoji: (WalineEmojiInfo | WalineEmojiPresets)[] | null;\n highlighter: WalineHighlighter | null;\n imageUploader: WalineImageUploader | null;\n texRenderer: WalineTeXRenderer | null;\n search: WalineSearchOptions | null;\n reaction: string[] | null;\n}\n\nexport const getServerURL = (serverURL: string): string => {\n const result = removeEndingSplash(serverURL);\n\n return isLinkHttp(result) ? result : `https://${result}`;\n};\n\nconst getWordLimit = (\n wordLimit: WalineProps['wordLimit'],\n): [number, number] | false =>\n Array.isArray(wordLimit) ? wordLimit : wordLimit ? [0, wordLimit] : false;\n\nconst fallback = <T = unknown>(\n value: T | boolean | undefined,\n fallback: T,\n): T | null =>\n value == undefined || value === true\n ? fallback\n : value === false\n ? null\n : value;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n noCopyright = false,\n login = 'enable',\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n emoji = DEFAULT_EMOJI,\n imageUploader,\n highlighter,\n texRenderer,\n search,\n reaction,\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n lang: getLang(lang),\n locale: {\n ...getLocale(getLang(lang)),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n dark,\n pageSize,\n commentSorting,\n login,\n noCopyright,\n recaptchaV3Key,\n turnstileKey,\n ...more,\n reaction: fallback(reaction, DEFAULT_REACTION),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTeXRenderer),\n emoji: fallback(emoji, DEFAULT_EMOJI),\n search: fallback(search, getDefaultSearchOptions(lang)),\n});\n","export const errorHandler = (err: Error): void => {\n // eslint-disable-next-line no-console\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","export const getQuery = (element: HTMLElement): string | null => {\n const { path } = element.dataset;\n\n return path?.length ? path : null;\n};\n","import type { GetArticleCounterResponse } from '@waline/api';\nimport { getPageview, updatePageview } from '@waline/api';\n\nimport type { WalineAbort } from './typings/index.js';\nimport { errorHandler, getQuery, getServerURL } from './utils/index.js';\n\nexport interface WalinePageviewCountOptions {\n /**\n * Waline 服务端地址\n *\n * Waline server url\n */\n serverURL: string;\n\n /**\n * 浏览量 CSS 选择器\n *\n * Pageview CSS selector\n *\n * @default '.waline-pageview-count'\n */\n selector?: string;\n\n /**\n * 需要更新和获取的路径\n *\n * Path to be fetched and updated\n *\n * @default window.location.pathname\n */\n path?: string;\n\n /**\n * 是否在查询时更新 path 的浏览量\n *\n * Whether update pageviews when fetching path result\n *\n * @default true\n */\n update?: boolean;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default navigator.language\n */\n lang?: string;\n}\n\nconst renderVisitorCount = (\n counts: GetArticleCounterResponse,\n countElements: HTMLElement[],\n): void => {\n countElements.forEach((element, index) => {\n const count = counts[index].time;\n\n if (typeof count !== 'number') {\n return;\n }\n\n element.innerText = count.toString();\n });\n};\n\nexport const pageviewCount = ({\n serverURL,\n path = window.location.pathname,\n selector = '.waline-pageview-count',\n update = true,\n lang = navigator.language,\n}: WalinePageviewCountOptions): WalineAbort => {\n const controller = new AbortController();\n\n const elements = Array.from(\n // pageview selectors\n document.querySelectorAll<HTMLElement>(selector),\n );\n\n const filter = (element: HTMLElement): boolean => {\n const query = getQuery(element);\n\n return query !== null && path !== query;\n };\n\n const fetch = (elements: HTMLElement[]): Promise<void> =>\n getPageview({\n serverURL: getServerURL(serverURL),\n paths: elements.map((element) => getQuery(element) ?? path),\n lang,\n signal: controller.signal,\n })\n .then((counts) => renderVisitorCount(counts, elements))\n .catch(errorHandler);\n\n // we should update pageviews\n if (update) {\n const normalElements = elements.filter((element) => !filter(element));\n const elementsNeedstoBeFetched = elements.filter(filter);\n\n void updatePageview({\n serverURL: getServerURL(serverURL),\n path,\n lang,\n }).then((counts) => renderVisitorCount(counts, normalElements));\n\n // if we should fetch count of other pages\n if (elementsNeedstoBeFetched.length) {\n void fetch(elementsNeedstoBeFetched);\n }\n }\n // we should not update pageviews\n else {\n void fetch(elements);\n }\n\n return controller.abort.bind(controller);\n};\n"],"names":["version","m","s","e","c","n","p","o","a","t","r","d","j","v","removeEndingSplash","content","isLinkHttp","link","getServerURL","serverURL","result","errorHandler","err","getQuery","element","path","renderVisitorCount","counts","countElements","index","count","pageviewCount","selector","update","lang","controller","elements","filter","query","fetch","getPageview","normalElements","elementsNeedstoBeFetched","updatePageview"],"mappings":"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"}