@waline/client 2.15.6 → 2.15.7
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.
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.mts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.mjs.map +1 -1
- package/dist/comment.cjs +1 -1
- package/dist/comment.cjs.map +1 -1
- package/dist/comment.d.cts +1 -1
- package/dist/comment.d.mts +1 -1
- package/dist/comment.d.ts +1 -1
- package/dist/comment.js +1 -1
- package/dist/comment.js.map +1 -1
- package/dist/comment.mjs +1 -1
- package/dist/comment.mjs.map +1 -1
- package/dist/component.mjs +1 -1
- package/dist/component.mjs.map +1 -1
- package/dist/legacy.umd.d.ts +5 -5
- package/dist/legacy.umd.js +1 -1
- package/dist/legacy.umd.js.map +1 -1
- package/dist/pageview.cjs +1 -1
- package/dist/pageview.cjs.map +1 -1
- package/dist/pageview.d.cts +1 -1
- package/dist/pageview.d.mts +1 -1
- package/dist/pageview.d.ts +1 -1
- package/dist/pageview.js +1 -1
- package/dist/pageview.js.map +1 -1
- package/dist/pageview.mjs +1 -1
- package/dist/pageview.mjs.map +1 -1
- package/dist/shim.cjs +1 -1
- package/dist/shim.cjs.map +1 -1
- package/dist/shim.d.cts +3 -3
- package/dist/shim.d.mts +3 -3
- package/dist/shim.mjs +1 -1
- package/dist/shim.mjs.map +1 -1
- package/dist/waline.cjs +1 -1
- package/dist/waline.cjs.map +1 -1
- package/dist/waline.css +1 -1
- package/dist/waline.css.map +1 -1
- package/dist/waline.d.cts +3 -3
- package/dist/waline.d.mts +3 -3
- package/dist/waline.d.ts +3 -3
- package/dist/waline.js +1 -1
- package/dist/waline.js.map +1 -1
- package/dist/waline.mjs +1 -1
- package/dist/waline.mjs.map +1 -1
- package/package.json +11 -9
- package/src/api/articleCounter.ts +2 -2
- package/src/api/comment.ts +2 -2
- package/src/api/commentCount.ts +2 -2
- package/src/api/login.ts +1 -1
- package/src/api/pageview.ts +1 -1
- package/src/api/utils.ts +1 -1
- package/src/comment.ts +1 -1
- package/src/compact/convert.ts +9 -8
- package/src/compact/logger.ts +1 -1
- package/src/compact/v1.ts +3 -3
- package/src/compact/valine.ts +1 -1
- package/src/components/ArticleReaction.vue +12 -5
- package/src/components/CommentBox.vue +10 -11
- package/src/components/CommentCard.vue +6 -6
- package/src/components/Icons.ts +10 -10
- package/src/components/ImageWall.vue +5 -5
- package/src/components/WalineComment.vue +3 -3
- package/src/composables/turnstile.ts +1 -1
- package/src/composables/userInfo.ts +1 -1
- package/src/config/default.ts +6 -6
- package/src/config/highlighter.ts +1 -1
- package/src/config/i18n/generate.ts +1 -1
- package/src/entries/legacy.ts +4 -2
- package/src/pageview.ts +4 -4
- package/src/styles/card.scss +1 -1
- package/src/styles/emoji.scss +3 -1
- package/src/styles/gif.scss +3 -1
- package/src/styles/panel.scss +5 -5
- package/src/styles/reaction.scss +2 -2
- package/src/typings/base.ts +1 -1
- package/src/typings/waline.ts +2 -2
- package/src/utils/config.ts +4 -4
- package/src/utils/date.ts +1 -1
- package/src/utils/emoji.ts +4 -4
- package/src/utils/getRoot.ts +1 -1
- package/src/utils/image.ts +1 -1
- package/src/utils/markdown.ts +6 -6
- package/src/utils/markedMathExtension.ts +3 -3
- package/src/utils/wordCount.ts +1 -1
- package/src/widgets/recentComments.ts +1 -1
- package/src/widgets/userList.ts +1 -1
package/dist/pageview.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e={"Content-Type":"application/json"},t=({serverURL:e,lang:t,paths:n,signal:r})=>(({serverURL:e,lang:t,paths:n,type:r,signal:a})=>fetch(`${e}/article?path=${encodeURIComponent(n.join(","))}&type=${encodeURIComponent(r.join(","))}&lang=${t}`,{signal:a}).then((e=>e.json())))({serverURL:e,lang:t,paths:n,type:["time"],signal:r}).then((e=>Array.isArray(e)?e:[e])),n=t=>(({serverURL:t,lang:n,path:r,type:a,action:o})=>fetch(`${t}/article?lang=${n}`,{method:"POST",headers:e,body:JSON.stringify({path:r,type:a,action:o})}).then((e=>e.json())))({...t,type:"time",action:"inc"}),r=e=>{const t=((e="")=>e.replace(/\/$/u,""))(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},a=e=>{"AbortError"!==e.name&&console.error(e.message)},o=e=>e.dataset.path||e.getAttribute("id"),s=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};exports.pageviewCount=({serverURL:e,path:i=window.location.pathname,selector:l=".waline-pageview-count",update:p=!0,lang:c=navigator.language})=>{const g=new AbortController,h=Array.from(document.querySelectorAll(l)),y=e=>{const t=o(e);return null!==t&&i!==t},u=n=>t({serverURL:r(e),paths:n.map((e=>o(e)||i)),lang:c,signal:g.signal}).then((e=>s(e,n))).catch(a);if(p){const t=h.filter((e=>!y(e))),a=h.filter(y);n({serverURL:r(e),path:i,lang:c}).then((e=>s(new Array(t.length).fill(e),t))),a.length&&u(a)}else u(h);return g.abort.bind(g)},exports.version="2.15.
|
|
1
|
+
"use strict";const e={"Content-Type":"application/json"},t=({serverURL:e,lang:t,paths:n,signal:r})=>(({serverURL:e,lang:t,paths:n,type:r,signal:a})=>fetch(`${e}/article?path=${encodeURIComponent(n.join(","))}&type=${encodeURIComponent(r.join(","))}&lang=${t}`,{signal:a}).then((e=>e.json())))({serverURL:e,lang:t,paths:n,type:["time"],signal:r}).then((e=>Array.isArray(e)?e:[e])),n=t=>(({serverURL:t,lang:n,path:r,type:a,action:o})=>fetch(`${t}/article?lang=${n}`,{method:"POST",headers:e,body:JSON.stringify({path:r,type:a,action:o})}).then((e=>e.json())))({...t,type:"time",action:"inc"}),r=e=>{const t=((e="")=>e.replace(/\/$/u,""))(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},a=e=>{"AbortError"!==e.name&&console.error(e.message)},o=e=>e.dataset.path||e.getAttribute("id"),s=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};exports.pageviewCount=({serverURL:e,path:i=window.location.pathname,selector:l=".waline-pageview-count",update:p=!0,lang:c=navigator.language})=>{const g=new AbortController,h=Array.from(document.querySelectorAll(l)),y=e=>{const t=o(e);return null!==t&&i!==t},u=n=>t({serverURL:r(e),paths:n.map((e=>o(e)||i)),lang:c,signal:g.signal}).then((e=>s(e,n))).catch(a);if(p){const t=h.filter((e=>!y(e))),a=h.filter(y);n({serverURL:r(e),path:i,lang:c}).then((e=>s(new Array(t.length).fill(e),t))),a.length&&u(a)}else u(h);return g.abort.bind(g)},exports.version="2.15.7";
|
|
2
2
|
//# sourceMappingURL=pageview.cjs.map
|
package/dist/pageview.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageview.cjs","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = ''\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal }\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTexRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[]\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements\n )\n );\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":["JSON_HEADERS","getPageview","serverURL","lang","paths","signal","type","fetch","encodeURIComponent","join","then","resp","json","getArticleCounter","counts","Array","isArray","updatePageview","options","path","action","method","headers","body","JSON","stringify","updateArticleCounter","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","window","location","pathname","selector","update","navigator","language","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"aAEO,MC8BMA,EAAuC,CAElD,eAAgB,oBCfLC,EAAc,EACzBC,YACAC,OACAC,QACAC,YCQ+B,GAC/BH,YACAC,OACAC,QACAE,OACAD,YAEAE,MACE,GAAGL,kBAA0BM,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmBF,EAAKG,KAAK,cAAcN,IACrD,CAAEE,WACFK,MAAMC,GAA6CA,EAAKC,SDlB1DC,CAAkB,CAChBX,YACAC,OACAC,QACAE,KAAM,CAAC,QACPD,WAGCK,MAAMI,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAa5CG,EACXC,GCuBkC,GAClChB,YACAC,OACAgB,OACAb,OACAc,YAEAb,MAAM,GAAGL,kBAA0BC,IAAQ,CACzCkB,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEN,OAAMb,OAAMc,aAClCV,MAAMC,GAA0BA,EAAKC,SDhCxCc,CAAqB,IAChBR,EACHZ,KAAM,OACNc,OAAQ,QELCO,EAAgBzB,IAC3B,MAAM0B,ECtC0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDqCTC,CAAmB7B,GAElC,MCpCA,kBAAkB8B,KDoCAJ,GAAUA,EAAS,WAAWA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQtB,MAAQqB,EAAQE,aAAa,MCgDzCC,EAAqB,CACzB7B,EACA8B,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYjC,EAAOgC,GAAOE,UAAU,GAC5C,wBAGyB,EAC3B9C,YACAiB,OAAO8B,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTlD,OAAOmD,UAAUC,aAEjB,MAAMC,EAAa,IAAIC,gBAEjBC,EAAW3C,MAAM4C,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAUtB,IACd,MAAMuB,EAAQxB,EAASC,GAEvB,OAAiB,OAAVuB,GAAkB5C,IAAS4C,CAAK,EAGnCxD,EAASmD,GACbzD,EAAY,CACVC,UAAWyB,EAAazB,GACxBE,MAAOsD,EAASM,KAAKxB,GAAYD,EAASC,IAAYrB,IACtDhB,OACAE,OAAQmD,EAAWnD,SAElBK,MAAMI,GAAW6B,EAAmB7B,EAAQ4C,KAC5CO,MAAMhC,GAGX,GAAIoB,EAAQ,CACV,MAAMa,EAAiBR,EAASI,QAAQtB,IAAasB,EAAOtB,KACtD2B,EAA2BT,EAASI,OAAOA,GAE5C7C,EAAe,CAClBf,UAAWyB,EAAazB,GACxBiB,OACAhB,SACCO,MAAM0D,GACPzB,EACE,IAAI5B,MAAcmD,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB9D,EAAM4D,EAEd,MAGM5D,EAAMmD,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,EAAW,kBRhHnB"}
|
|
1
|
+
{"version":3,"file":"pageview.cjs","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = '',\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions,\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(','),\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal },\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTeXRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTeXRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[],\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements,\n ),\n );\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":["JSON_HEADERS","getPageview","serverURL","lang","paths","signal","type","fetch","encodeURIComponent","join","then","resp","json","getArticleCounter","counts","Array","isArray","updatePageview","options","path","action","method","headers","body","JSON","stringify","updateArticleCounter","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","window","location","pathname","selector","update","navigator","language","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"aAEO,MC8BMA,EAAuC,CAElD,eAAgB,oBCfLC,EAAc,EACzBC,YACAC,OACAC,QACAC,YCQ+B,GAC/BH,YACAC,OACAC,QACAE,OACAD,YAEAE,MACE,GAAGL,kBAA0BM,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmBF,EAAKG,KAAK,cAAcN,IACrD,CAAEE,WACFK,MAAMC,GAA6CA,EAAKC,SDlB1DC,CAAkB,CAChBX,YACAC,OACAC,QACAE,KAAM,CAAC,QACPD,WAGCK,MAAMI,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAa5CG,EACXC,GCuBkC,GAClChB,YACAC,OACAgB,OACAb,OACAc,YAEAb,MAAM,GAAGL,kBAA0BC,IAAQ,CACzCkB,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEN,OAAMb,OAAMc,aAClCV,MAAMC,GAA0BA,EAAKC,SDhCxCc,CAAqB,IAChBR,EACHZ,KAAM,OACNc,OAAQ,QELCO,EAAgBzB,IAC3B,MAAM0B,ECtC0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDqCTC,CAAmB7B,GAElC,MCpCA,kBAAkB8B,KDoCAJ,GAAUA,EAAS,WAAWA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQtB,MAAQqB,EAAQE,aAAa,MCgDzCC,EAAqB,CACzB7B,EACA8B,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYjC,EAAOgC,GAAOE,UAAU,GAC5C,wBAGyB,EAC3B9C,YACAiB,OAAO8B,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTlD,OAAOmD,UAAUC,aAEjB,MAAMC,EAAa,IAAIC,gBAEjBC,EAAW3C,MAAM4C,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAUtB,IACd,MAAMuB,EAAQxB,EAASC,GAEvB,OAAiB,OAAVuB,GAAkB5C,IAAS4C,CAAK,EAGnCxD,EAASmD,GACbzD,EAAY,CACVC,UAAWyB,EAAazB,GACxBE,MAAOsD,EAASM,KAAKxB,GAAYD,EAASC,IAAYrB,IACtDhB,OACAE,OAAQmD,EAAWnD,SAElBK,MAAMI,GAAW6B,EAAmB7B,EAAQ4C,KAC5CO,MAAMhC,GAGX,GAAIoB,EAAQ,CACV,MAAMa,EAAiBR,EAASI,QAAQtB,IAAasB,EAAOtB,KACtD2B,EAA2BT,EAASI,OAAOA,GAE5C7C,EAAe,CAClBf,UAAWyB,EAAazB,GACxBiB,OACAhB,SACCO,MAAM0D,GACPzB,EACE,IAAI5B,MAAcmD,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB9D,EAAM4D,EAEd,MAGM5D,EAAMmD,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,EAAW,kBRhHnB"}
|
package/dist/pageview.d.cts
CHANGED
|
@@ -44,4 +44,4 @@ interface WalinePageviewCountOptions {
|
|
|
44
44
|
}
|
|
45
45
|
declare const pageviewCount: ({ serverURL, path, selector, update, lang, }: WalinePageviewCountOptions) => WalineAbort;
|
|
46
46
|
|
|
47
|
-
export { WalinePageviewCountOptions, pageviewCount, version };
|
|
47
|
+
export { type WalinePageviewCountOptions, pageviewCount, version };
|
package/dist/pageview.d.mts
CHANGED
|
@@ -44,4 +44,4 @@ interface WalinePageviewCountOptions {
|
|
|
44
44
|
}
|
|
45
45
|
declare const pageviewCount: ({ serverURL, path, selector, update, lang, }: WalinePageviewCountOptions) => WalineAbort;
|
|
46
46
|
|
|
47
|
-
export { WalinePageviewCountOptions, pageviewCount, version };
|
|
47
|
+
export { type WalinePageviewCountOptions, pageviewCount, version };
|
package/dist/pageview.d.ts
CHANGED
|
@@ -44,4 +44,4 @@ interface WalinePageviewCountOptions {
|
|
|
44
44
|
}
|
|
45
45
|
declare const pageviewCount: ({ serverURL, path, selector, update, lang, }: WalinePageviewCountOptions) => WalineAbort;
|
|
46
46
|
|
|
47
|
-
export { WalinePageviewCountOptions, pageviewCount, version };
|
|
47
|
+
export { type WalinePageviewCountOptions, pageviewCount, version };
|
package/dist/pageview.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){if("function"==typeof define&&define.amd)define("Waline",["exports"],t);else if("undefined"!=typeof exports)t(exports);else{var n={exports:{}};t(n.exports),e.Waline=n.exports}}("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:this,(function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.pageviewCount=void 0;const t={"Content-Type":"application/json"},n=e=>(e=>{let{serverURL:n,lang:r,path:o,type:a,action:i}=e;return fetch(`${n}/article?lang=${r}`,{method:"POST",headers:t,body:JSON.stringify({path:o,type:a,action:i})}).then((e=>e.json()))})({...e,type:"time",action:"inc"}),r=e=>{const t=function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").replace(/\/$/u,"")}(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},o=e=>{"AbortError"!==e.name&&console.error(e.message)},a=e=>e.dataset.path||e.getAttribute("id"),i=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};e.pageviewCount=e=>{let{serverURL:t,path:l=window.location.pathname,selector:s=".waline-pageview-count",update:p=!0,lang:c=navigator.language}=e;const g=new AbortController,h=Array.from(document.querySelectorAll(s)),f=e=>{const t=a(e);return null!==t&&l!==t},u=e=>(e=>{let{serverURL:t,lang:n,paths:r,signal:o}=e;return(e=>{let{serverURL:t,lang:n,paths:r,type:o,signal:a}=e;return fetch(`${t}/article?path=${encodeURIComponent(r.join(","))}&type=${encodeURIComponent(o.join(","))}&lang=${n}`,{signal:a}).then((e=>e.json()))})({serverURL:t,lang:n,paths:r,type:["time"],signal:o}).then((e=>Array.isArray(e)?e:[e]))})({serverURL:r(t),paths:e.map((e=>a(e)||l)),lang:c,signal:g.signal}).then((t=>i(t,e))).catch(o);if(p){const e=h.filter((e=>!f(e))),o=h.filter(f);n({serverURL:r(t),path:l,lang:c}).then((t=>i(new Array(e.length).fill(t),e))),o.length&&u(o)}else u(h);return g.abort.bind(g)},e.version="2.15.
|
|
1
|
+
!function(e,t){if("function"==typeof define&&define.amd)define("Waline",["exports"],t);else if("undefined"!=typeof exports)t(exports);else{var n={exports:{}};t(n.exports),e.Waline=n.exports}}("undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:this,(function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.pageviewCount=void 0;const t={"Content-Type":"application/json"},n=e=>(e=>{let{serverURL:n,lang:r,path:o,type:a,action:i}=e;return fetch(`${n}/article?lang=${r}`,{method:"POST",headers:t,body:JSON.stringify({path:o,type:a,action:i})}).then((e=>e.json()))})({...e,type:"time",action:"inc"}),r=e=>{const t=function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").replace(/\/$/u,"")}(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},o=e=>{"AbortError"!==e.name&&console.error(e.message)},a=e=>e.dataset.path||e.getAttribute("id"),i=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};e.pageviewCount=e=>{let{serverURL:t,path:l=window.location.pathname,selector:s=".waline-pageview-count",update:p=!0,lang:c=navigator.language}=e;const g=new AbortController,h=Array.from(document.querySelectorAll(s)),f=e=>{const t=a(e);return null!==t&&l!==t},u=e=>(e=>{let{serverURL:t,lang:n,paths:r,signal:o}=e;return(e=>{let{serverURL:t,lang:n,paths:r,type:o,signal:a}=e;return fetch(`${t}/article?path=${encodeURIComponent(r.join(","))}&type=${encodeURIComponent(o.join(","))}&lang=${n}`,{signal:a}).then((e=>e.json()))})({serverURL:t,lang:n,paths:r,type:["time"],signal:o}).then((e=>Array.isArray(e)?e:[e]))})({serverURL:r(t),paths:e.map((e=>a(e)||l)),lang:c,signal:g.signal}).then((t=>i(t,e))).catch(o);if(p){const e=h.filter((e=>!f(e))),o=h.filter(f);n({serverURL:r(t),path:l,lang:c}).then((t=>i(new Array(e.length).fill(t),e))),o.length&&u(o)}else u(h);return g.abort.bind(g)},e.version="2.15.7"}));
|
|
2
2
|
//# sourceMappingURL=pageview.js.map
|
package/dist/pageview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageview.js","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = ''\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal }\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTexRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[]\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements\n )\n );\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":["JSON_HEADERS","updatePageview","options","serverURL","lang","path","type","action","fetch","method","headers","body","JSON","stringify","then","resp","json","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","s","counts","countElements","forEach","index","innerText","toString","_exports","pageviewCount","_ref4","language","window","location","pathname","selector","update","navigator","controller","AbortController","elements","Array","from","document","querySelectorAll","filter","query","_ref","paths","signal","a","_ref2","encodeURIComponent","join","isArray","getPageview","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind","version"],"mappings":"4WAEO,MC8BMA,EAAuC,CAElD,eAAgB,oBCYLC,EACXC,GCuBkC,CAClCC,IAAAA,IAAAA,UAAAA,EACAC,KACAC,EAAAA,KAAAA,EACAC,KACAC,EAAAA,OAAAA,GAAAA,EAAAA,OAEAC,MAASL,GAAAA,kBAA0BC,IAAQ,CACzCK,OAAQ,OACRC,QAASV,EACTW,KAAMC,KAAKC,UAAU,CAAER,KAAMC,EAAAA,KAAAA,EAAMC,OAClCO,MAAAA,MAAMC,GAA0BA,EAAKC,QDhCnB,ECqBa,CDrBb,IAChBd,EACHI,KAAM,OACNC,OAAQ,QELCU,EAAgBd,IAC3B,MAAMe,ECtC2BC,WACjCA,OADiCA,UAAAA,OAAAA,QAAAA,IAAAA,UAAAA,GAAAA,UAAAA,GAAU,IACnCC,QAAQ,OAAQ,GDqCTC,CCtCkBF,CDsCChB,GAElC,MCpCA,kBAAkBmB,KDoCAJ,GAAUA,EAAoBA,WAAAA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQ1B,MAAQyB,EAAQE,aAAa,MCgDzCC,EAAqBC,CACzBC,EACAC,KAEAA,EAAcC,SAAQ,CAACP,EAASQ,KAC9BR,EAAQS,UAAYJ,EAAOG,GAAOE,UAAU,GAC5C,EA2DsCC,EAAAC,cAxDbC,IAKVC,IAJjBzC,UACAE,EAAAA,KAAAA,EAAOwC,OAAOC,SAASC,SACvBC,SAAAA,EAAW,yBACXC,OAAAA,GAAAA,EACA7C,KAAAA,EAAO8C,UAAUN,UAAAA,EAEjB,MAAMO,EAAa,IAAIC,gBAEjBC,EAAWC,MAAMC,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAU5B,IACd,MAAM6B,EAAQ9B,EAASC,GAEvB,OAAiB,OAAV6B,GAAkBtD,IAASsD,CAAK,EAGnCnD,EAAS6C,GN3DUO,KAAA,IACzBzD,UAAAA,EACAC,KACAyD,EAAAA,MAAAA,EACAC,OCQ+BC,GAAAH,EAAA,MAAA,CAAAI,IAAA,IAC/B7D,UACAC,EAAAA,KAAAA,EACAyD,MACAvD,EAAAA,KAAAA,EACAwD,OAEAtD,GAAAA,EAAAA,OAAAA,MACKL,GAAAA,kBAA0B8D,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmB3D,EAAK4D,KAAK,cAAc9D,IACrD,CAAE0D,OACFhD,IAAAA,MAAMC,GAA6CA,EAAKC,QDlBxC,ECMa,CDNb,CAChBb,UAAAA,EACAC,KACAyD,EAAAA,MAAAA,EACAvD,KAAM,CAAC,QACPwD,OAAAA,IAGChD,MAAMqB,GAAYmB,MAAMa,QAAQhC,GAAUA,EAAS,CAACA,IAAAA,EM8CrDiC,CAAY,CACVjE,UAAWc,EAAad,GACxB0D,MAAOR,EAASgB,KAAKvC,GAAYD,EAASC,IAAYzB,IACtDD,KAAAA,EACA0D,OAAQX,EAAWW,SAElBhD,MAAMqB,GAAWF,EAAmBE,EAAQkB,KAC5CiB,MAAM/C,GAGX,GAAI0B,EAAQ,CACV,MAAMsB,EAAiBlB,EAASK,QAAQ5B,IAAa4B,EAAO5B,KACtD0C,EAA2BnB,EAASK,OAAOA,GAE5CzD,EAAe,CAClBE,UAAWc,EAAad,GACxBE,KAAAA,EACAD,KACCU,IAAAA,MAAM2D,GACPxC,EACE,IAAIqB,MAAciB,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtBlE,EAAMgE,EAEd,MAGMhE,EAAM6C,GAGb,OAAOF,EAAWyB,MAAMC,KAAK1B,EAAW,EAAAV,EAAAqC,QRhHnB,QQgHmB"}
|
|
1
|
+
{"version":3,"file":"pageview.js","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = '',\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions,\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(','),\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal },\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTeXRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTeXRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[],\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements,\n ),\n );\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":["JSON_HEADERS","updatePageview","options","serverURL","lang","path","type","action","fetch","method","headers","body","JSON","stringify","then","resp","json","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","s","counts","countElements","forEach","index","innerText","toString","_exports","pageviewCount","_ref4","language","window","location","pathname","selector","update","navigator","controller","AbortController","elements","Array","from","document","querySelectorAll","filter","query","_ref","paths","signal","a","_ref2","encodeURIComponent","join","isArray","getPageview","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind","version"],"mappings":"4WAEO,MC8BMA,EAAuC,CAElD,eAAgB,oBCYLC,EACXC,GCuBkC,CAClCC,IAAAA,IAAAA,UAAAA,EACAC,KACAC,EAAAA,KAAAA,EACAC,KACAC,EAAAA,OAAAA,GAAAA,EAAAA,OAEAC,MAASL,GAAAA,kBAA0BC,IAAQ,CACzCK,OAAQ,OACRC,QAASV,EACTW,KAAMC,KAAKC,UAAU,CAAER,KAAMC,EAAAA,KAAAA,EAAMC,OAClCO,MAAAA,MAAMC,GAA0BA,EAAKC,QDhCnB,ECqBa,CDrBb,IAChBd,EACHI,KAAM,OACNC,OAAQ,QELCU,EAAgBd,IAC3B,MAAMe,ECtC2BC,WACjCA,OADiCA,UAAAA,OAAAA,QAAAA,IAAAA,UAAAA,GAAAA,UAAAA,GAAU,IACnCC,QAAQ,OAAQ,GDqCTC,CCtCkBF,CDsCChB,GAElC,MCpCA,kBAAkBmB,KDoCAJ,GAAUA,EAAoBA,WAAAA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQ1B,MAAQyB,EAAQE,aAAa,MCgDzCC,EAAqBC,CACzBC,EACAC,KAEAA,EAAcC,SAAQ,CAACP,EAASQ,KAC9BR,EAAQS,UAAYJ,EAAOG,GAAOE,UAAU,GAC5C,EA2DsCC,EAAAC,cAxDbC,IAKVC,IAJjBzC,UACAE,EAAAA,KAAAA,EAAOwC,OAAOC,SAASC,SACvBC,SAAAA,EAAW,yBACXC,OAAAA,GAAAA,EACA7C,KAAAA,EAAO8C,UAAUN,UAAAA,EAEjB,MAAMO,EAAa,IAAIC,gBAEjBC,EAAWC,MAAMC,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAU5B,IACd,MAAM6B,EAAQ9B,EAASC,GAEvB,OAAiB,OAAV6B,GAAkBtD,IAASsD,CAAK,EAGnCnD,EAAS6C,GN3DUO,KAAA,IACzBzD,UAAAA,EACAC,KACAyD,EAAAA,MAAAA,EACAC,OCQ+BC,GAAAH,EAAA,MAAA,CAAAI,IAAA,IAC/B7D,UACAC,EAAAA,KAAAA,EACAyD,MACAvD,EAAAA,KAAAA,EACAwD,OAEAtD,GAAAA,EAAAA,OAAAA,MACKL,GAAAA,kBAA0B8D,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmB3D,EAAK4D,KAAK,cAAc9D,IACrD,CAAE0D,OACFhD,IAAAA,MAAMC,GAA6CA,EAAKC,QDlBxC,ECMa,CDNb,CAChBb,UAAAA,EACAC,KACAyD,EAAAA,MAAAA,EACAvD,KAAM,CAAC,QACPwD,OAAAA,IAGChD,MAAMqB,GAAYmB,MAAMa,QAAQhC,GAAUA,EAAS,CAACA,IAAAA,EM8CrDiC,CAAY,CACVjE,UAAWc,EAAad,GACxB0D,MAAOR,EAASgB,KAAKvC,GAAYD,EAASC,IAAYzB,IACtDD,KAAAA,EACA0D,OAAQX,EAAWW,SAElBhD,MAAMqB,GAAWF,EAAmBE,EAAQkB,KAC5CiB,MAAM/C,GAGX,GAAI0B,EAAQ,CACV,MAAMsB,EAAiBlB,EAASK,QAAQ5B,IAAa4B,EAAO5B,KACtD0C,EAA2BnB,EAASK,OAAOA,GAE5CzD,EAAe,CAClBE,UAAWc,EAAad,GACxBE,KAAAA,EACAD,KACCU,IAAAA,MAAM2D,GACPxC,EACE,IAAIqB,MAAciB,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtBlE,EAAMgE,EAEd,MAGMhE,EAAM6C,GAGb,OAAOF,EAAWyB,MAAMC,KAAK1B,EAAW,EAAAV,EAAAqC,QRhHnB,QQgHmB"}
|
package/dist/pageview.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e="2.15.
|
|
1
|
+
const e="2.15.7",t={"Content-Type":"application/json"},n=({serverURL:e,lang:t,paths:n,signal:a})=>(({serverURL:e,lang:t,paths:n,type:a,signal:r})=>fetch(`${e}/article?path=${encodeURIComponent(n.join(","))}&type=${encodeURIComponent(a.join(","))}&lang=${t}`,{signal:r}).then((e=>e.json())))({serverURL:e,lang:t,paths:n,type:["time"],signal:a}).then((e=>Array.isArray(e)?e:[e])),a=e=>(({serverURL:e,lang:n,path:a,type:r,action:o})=>fetch(`${e}/article?lang=${n}`,{method:"POST",headers:t,body:JSON.stringify({path:a,type:r,action:o})}).then((e=>e.json())))({...e,type:"time",action:"inc"}),r=e=>{const t=((e="")=>e.replace(/\/$/u,""))(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},o=e=>{"AbortError"!==e.name&&console.error(e.message)},l=e=>e.dataset.path||e.getAttribute("id"),s=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))},i=({serverURL:e,path:t=window.location.pathname,selector:i=".waline-pageview-count",update:p=!0,lang:c=navigator.language})=>{const h=new AbortController,g=Array.from(document.querySelectorAll(i)),y=e=>{const n=l(e);return null!==n&&t!==n},d=a=>n({serverURL:r(e),paths:a.map((e=>l(e)||t)),lang:c,signal:h.signal}).then((e=>s(e,a))).catch(o);if(p){const n=g.filter((e=>!y(e))),o=g.filter(y);a({serverURL:r(e),path:t,lang:c}).then((e=>s(new Array(n.length).fill(e),n))),o.length&&d(o)}else d(g);return h.abort.bind(h)};export{i as pageviewCount,e as version};
|
|
2
2
|
//# sourceMappingURL=pageview.mjs.map
|
package/dist/pageview.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageview.mjs","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = ''\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal }\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTexRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[]\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements\n )\n );\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","JSON_HEADERS","getPageview","serverURL","lang","paths","signal","type","fetch","encodeURIComponent","join","then","resp","json","getArticleCounter","counts","Array","isArray","updatePageview","options","path","action","method","headers","body","JSON","stringify","updateArticleCounter","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","pageviewCount","window","location","pathname","selector","update","navigator","language","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"AAEO,MAAMA,EAAU,SC8BVC,EAAuC,CAElD,eAAgB,oBCfLC,EAAc,EACzBC,YACAC,OACAC,QACAC,YCQ+B,GAC/BH,YACAC,OACAC,QACAE,OACAD,YAEAE,MACE,GAAGL,kBAA0BM,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmBF,EAAKG,KAAK,cAAcN,IACrD,CAAEE,WACFK,MAAMC,GAA6CA,EAAKC,SDlB1DC,CAAkB,CAChBX,YACAC,OACAC,QACAE,KAAM,CAAC,QACPD,WAGCK,MAAMI,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAa5CG,EACXC,GCuBkC,GAClChB,YACAC,OACAgB,OACAb,OACAc,YAEAb,MAAM,GAAGL,kBAA0BC,IAAQ,CACzCkB,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEN,OAAMb,OAAMc,aAClCV,MAAMC,GAA0BA,EAAKC,SDhCxCc,CAAqB,IAChBR,EACHZ,KAAM,OACNc,OAAQ,QELCO,EAAgBzB,IAC3B,MAAM0B,ECtC0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDqCTC,CAAmB7B,GAElC,MCpCA,kBAAkB8B,KDoCAJ,GAAUA,EAAS,WAAWA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQtB,MAAQqB,EAAQE,aAAa,MCgDzCC,EAAqB,CACzB7B,EACA8B,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYjC,EAAOgC,GAAOE,UAAU,GAC5C,EAGSC,EAAgB,EAC3B/C,YACAiB,OAAO+B,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTnD,OAAOoD,UAAUC,aAEjB,MAAMC,EAAa,IAAIC,gBAEjBC,EAAW5C,MAAM6C,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAUvB,IACd,MAAMwB,EAAQzB,EAASC,GAEvB,OAAiB,OAAVwB,GAAkB7C,IAAS6C,CAAK,EAGnCzD,EAASoD,GACb1D,EAAY,CACVC,UAAWyB,EAAazB,GACxBE,MAAOuD,EAASM,KAAKzB,GAAYD,EAASC,IAAYrB,IACtDhB,OACAE,OAAQoD,EAAWpD,SAElBK,MAAMI,GAAW6B,EAAmB7B,EAAQ6C,KAC5CO,MAAMjC,GAGX,GAAIqB,EAAQ,CACV,MAAMa,EAAiBR,EAASI,QAAQvB,IAAauB,EAAOvB,KACtD4B,EAA2BT,EAASI,OAAOA,GAE5C9C,EAAe,CAClBf,UAAWyB,EAAazB,GACxBiB,OACAhB,SACCO,MAAM2D,GACP1B,EACE,IAAI5B,MAAcoD,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB/D,EAAM6D,EAEd,MAGM7D,EAAMoD,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,EAAW"}
|
|
1
|
+
{"version":3,"file":"pageview.mjs","sources":["../src/version.ts","../src/api/utils.ts","../src/api/pageview.ts","../src/api/articleCounter.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export interface BaseAPIOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 错误信息所使用的语言\n *\n * Language used in error text\n */\n lang: string;\n}\n\nexport interface ErrorStatusResponse {\n /**\n * 错误代码\n *\n * Error number\n */\n errno: number;\n\n /**\n * 错误消息\n *\n * Error msg\n */\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T extends ErrorStatusResponse>(\n data: T,\n name = '',\n): T => {\n if (typeof data === 'object' && data.errno)\n throw new TypeError(`${name} failed with ${data.errno}: ${data.errmsg}`);\n\n return data;\n};\n","import { getArticleCounter, updateArticleCounter } from './articleCounter.js';\nimport { type BaseAPIOptions } from './utils.js';\n\ninterface GetPageviewOptions extends BaseAPIOptions {\n /**\n * 待获取页面的 path\n *\n * Path of pages\n */\n paths: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport const getPageview = ({\n serverURL,\n lang,\n paths,\n signal,\n}: GetPageviewOptions): Promise<number[]> =>\n getArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions extends BaseAPIOptions {\n /**\n * 待更新页面的 path\n *\n * Path of pages\n */\n path: string;\n}\n\nexport const updatePageview = (\n options: UpdatePageviewOptions,\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n action: 'inc',\n });\n","import { type BaseAPIOptions, JSON_HEADERS } from './utils.js';\n\nexport interface GetArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待获取计数器的 path\n *\n * Path of counters\n */\n paths: string[];\n\n /**\n * 待获取计数器的类型\n *\n * Counter type to be fetched\n */\n type: string[];\n\n /**\n * 取消请求的信号\n *\n * AbortSignal to cancel request\n */\n signal?: AbortSignal;\n}\n\nexport type GetArticleCounterResponse =\n | Record<string, number>[]\n | Record<string, number>\n | number[]\n | number;\n\nexport const getArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: GetArticleCounterOptions): Promise<GetArticleCounterResponse> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(','),\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal },\n ).then((resp) => <Promise<GetArticleCounterResponse>>resp.json());\n\nexport interface UpdateArticleCounterOptions extends BaseAPIOptions {\n /**\n * 待更新计数器的 path\n *\n * Path of counter to be updated\n */\n path: string;\n\n /**\n * 待更新计数器的类型\n *\n * Counter type to be updated\n */\n type: string;\n\n /**\n * 更新操作\n *\n * Update operation\n *\n * @default 'inc'\n */\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n }).then((resp) => <Promise<number>>resp.json());\n","import { decodePath, isLinkHttp, removeEndingSplash } from './path.js';\nimport {\n DEFAULT_EMOJI,\n DEFAULT_LANG,\n DEFAULT_LOCALES,\n DEFAULT_REACTION,\n defaultUploadImage,\n defaultHighlighter,\n defaultTeXRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config/index.js';\nimport {\n type WalineEmojiInfo,\n type WalineEmojiMaps,\n type WalineLocale,\n type WalineProps,\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 reaction: string[];\n emoji: Exclude<WalineProps['emoji'], boolean | undefined>;\n highlighter: Exclude<WalineProps['highlighter'], true | undefined>;\n imageUploader: Exclude<WalineProps['imageUploader'], true | undefined>;\n texRenderer: Exclude<WalineProps['texRenderer'], true | undefined>;\n search: Exclude<WalineProps['search'], true | undefined>;\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 | false =>\n typeof value === 'function' ? value : value === false ? false : fallback;\n\nexport const getConfig = ({\n serverURL,\n\n path = location.pathname,\n lang = typeof navigator === 'undefined' ? 'en-US' : navigator.language,\n locale,\n emoji = DEFAULT_EMOJI,\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n dark = false,\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n search,\n reaction,\n recaptchaV3Key = '',\n turnstileKey = '',\n commentSorting = 'latest',\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(DEFAULT_LOCALES[lang] || DEFAULT_LOCALES[DEFAULT_LANG]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale,\n wordLimit: getWordLimit(wordLimit),\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, defaultHighlighter),\n texRenderer: fallback(texRenderer, defaultTeXRenderer),\n lang: Object.keys(DEFAULT_LOCALES).includes(lang) ? lang : 'en-US',\n dark,\n emoji: typeof emoji === 'boolean' ? (emoji ? DEFAULT_EMOJI : []) : emoji,\n pageSize,\n login,\n copyright,\n search:\n search === false\n ? false\n : typeof search === 'object'\n ? search\n : getDefaultSearchOptions(lang),\n recaptchaV3Key,\n turnstileKey,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? DEFAULT_REACTION\n : [],\n commentSorting,\n ...more,\n});\n","export const decodePath = (path: string): string => {\n try {\n path = decodeURI(path);\n } catch (err) {\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","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 element.dataset.path || element.getAttribute('id');\n","import { getPageview, updatePageview } from './api/index.js';\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: number[],\n countElements: HTMLElement[],\n): void => {\n countElements.forEach((element, index) => {\n element.innerText = counts[index].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((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements,\n ),\n );\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","JSON_HEADERS","getPageview","serverURL","lang","paths","signal","type","fetch","encodeURIComponent","join","then","resp","json","getArticleCounter","counts","Array","isArray","updatePageview","options","path","action","method","headers","body","JSON","stringify","updateArticleCounter","getServerURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","pageviewCount","window","location","pathname","selector","update","navigator","language","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"AAEO,MAAMA,EAAU,SC8BVC,EAAuC,CAElD,eAAgB,oBCfLC,EAAc,EACzBC,YACAC,OACAC,QACAC,YCQ+B,GAC/BH,YACAC,OACAC,QACAE,OACAD,YAEAE,MACE,GAAGL,kBAA0BM,mBAC3BJ,EAAMK,KAAK,cACHD,mBAAmBF,EAAKG,KAAK,cAAcN,IACrD,CAAEE,WACFK,MAAMC,GAA6CA,EAAKC,SDlB1DC,CAAkB,CAChBX,YACAC,OACAC,QACAE,KAAM,CAAC,QACPD,WAGCK,MAAMI,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAa5CG,EACXC,GCuBkC,GAClChB,YACAC,OACAgB,OACAb,OACAc,YAEAb,MAAM,GAAGL,kBAA0BC,IAAQ,CACzCkB,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEN,OAAMb,OAAMc,aAClCV,MAAMC,GAA0BA,EAAKC,SDhCxCc,CAAqB,IAChBR,EACHZ,KAAM,OACNc,OAAQ,QELCO,EAAgBzB,IAC3B,MAAM0B,ECtC0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDqCTC,CAAmB7B,GAElC,MCpCA,kBAAkB8B,KDoCAJ,GAAUA,EAAS,WAAWA,GAAQ,EElD7CK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,QAAQ,ECD9CC,EAAYC,GACvBA,EAAQC,QAAQtB,MAAQqB,EAAQE,aAAa,MCgDzCC,EAAqB,CACzB7B,EACA8B,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYjC,EAAOgC,GAAOE,UAAU,GAC5C,EAGSC,EAAgB,EAC3B/C,YACAiB,OAAO+B,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTnD,OAAOoD,UAAUC,aAEjB,MAAMC,EAAa,IAAIC,gBAEjBC,EAAW5C,MAAM6C,KAErBC,SAASC,iBAA8BT,IAGnCU,EAAUvB,IACd,MAAMwB,EAAQzB,EAASC,GAEvB,OAAiB,OAAVwB,GAAkB7C,IAAS6C,CAAK,EAGnCzD,EAASoD,GACb1D,EAAY,CACVC,UAAWyB,EAAazB,GACxBE,MAAOuD,EAASM,KAAKzB,GAAYD,EAASC,IAAYrB,IACtDhB,OACAE,OAAQoD,EAAWpD,SAElBK,MAAMI,GAAW6B,EAAmB7B,EAAQ6C,KAC5CO,MAAMjC,GAGX,GAAIqB,EAAQ,CACV,MAAMa,EAAiBR,EAASI,QAAQvB,IAAauB,EAAOvB,KACtD4B,EAA2BT,EAASI,OAAOA,GAE5C9C,EAAe,CAClBf,UAAWyB,EAAazB,GACxBiB,OACAhB,SACCO,MAAM2D,GACP1B,EACE,IAAI5B,MAAcoD,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB/D,EAAM6D,EAEd,MAGM7D,EAAMoD,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,EAAW"}
|