@waline/client 2.5.1 → 2.6.0

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.
Files changed (44) hide show
  1. package/dist/component.esm.js +1 -1
  2. package/dist/component.esm.js.map +1 -1
  3. package/dist/component.js +1 -1
  4. package/dist/component.js.map +1 -1
  5. package/dist/legacy.d.ts +40 -0
  6. package/dist/legacy.js +1 -1
  7. package/dist/legacy.js.map +1 -1
  8. package/dist/pageview.cjs.js +1 -1
  9. package/dist/pageview.cjs.js.map +1 -1
  10. package/dist/pageview.esm.js +1 -1
  11. package/dist/pageview.esm.js.map +1 -1
  12. package/dist/pageview.js +1 -1
  13. package/dist/pageview.js.map +1 -1
  14. package/dist/shim.d.ts +41 -1
  15. package/dist/shim.esm.d.ts +41 -1
  16. package/dist/shim.esm.js +1 -1
  17. package/dist/shim.esm.js.map +1 -1
  18. package/dist/shim.js +1 -1
  19. package/dist/shim.js.map +1 -1
  20. package/dist/waline.cjs.d.ts +41 -1
  21. package/dist/waline.cjs.js +1 -1
  22. package/dist/waline.cjs.js.map +1 -1
  23. package/dist/waline.css +1 -1
  24. package/dist/waline.css.map +1 -1
  25. package/dist/waline.d.ts +41 -1
  26. package/dist/waline.esm.d.ts +41 -1
  27. package/dist/waline.esm.js +1 -1
  28. package/dist/waline.esm.js.map +1 -1
  29. package/dist/waline.js +1 -1
  30. package/dist/waline.js.map +1 -1
  31. package/package.json +20 -21
  32. package/src/comment.ts +7 -2
  33. package/src/components/CommentBox.vue +40 -34
  34. package/src/components/ImageWall.vue +32 -18
  35. package/src/config/default.ts +91 -1
  36. package/src/init.ts +0 -3
  37. package/src/pageview.ts +2 -1
  38. package/src/styles/emoji.scss +20 -0
  39. package/src/typings/base.ts +40 -0
  40. package/src/typings/waline.ts +8 -0
  41. package/src/utils/config.ts +5 -2
  42. package/src/utils/index.ts +0 -2
  43. package/src/utils/fetchGif.ts +0 -63
  44. package/src/utils/throttle.ts +0 -15
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=e=>{"AbortError"!==e.name&&console.error(e.message)},t={"Content-Type":"application/json"},r=(e,t="")=>{if("object"==typeof e&&e.errno)throw new TypeError(`Fetch ${t} failed with ${e.errno}: ${e.errmsg}`);return e},n=({serverURL:e,lang:t,paths:n,signal:o})=>fetch(`${e}/article?path=${encodeURIComponent(n.join(","))}&lang=${t}`,{signal:o}).then((e=>e.json())).then((e=>r(e,"visit count"))).then((e=>Array.isArray(e)?e:[e])),o=({serverURL:e,lang:n,path:o})=>fetch(`${e}/article?lang=${n}`,{method:"POST",headers:t,body:JSON.stringify({path:o})}).then((e=>e.json())).then((e=>r(e,"visit count"))),a=e=>e.dataset.path||e.getAttribute("id"),s=(e,t)=>{t.forEach(((t,r)=>{t.innerText=e[r].toString()}))};exports.pageviewCount=({serverURL:t,path:r=window.location.pathname,selector:i=".waline-pageview-count",update:l=!0,lang:h="zh-CN"})=>{const c=new AbortController,p=Array.from(document.querySelectorAll(i)),g=e=>{const t=a(e);return null!==t&&r!==t},u=o=>n({serverURL:t,paths:o.map((e=>a(e)||r)),lang:h,signal:c.signal}).then((e=>s(e,o))).catch(e);if(l){const e=p.filter((e=>!g(e))),n=p.filter(g);o({serverURL:t,path:r,lang:h}).then((t=>s(new Array(e.length).fill(t),e))),n.length&&u(n)}else u(p);return c.abort.bind(c)},exports.version="2.5.1";
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=e=>{const t=((e="")=>e.replace(/\/$/u,""))(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},t=e=>{"AbortError"!==e.name&&console.error(e.message)},r={"Content-Type":"application/json"},n=(e,t="")=>{if("object"==typeof e&&e.errno)throw new TypeError(`Fetch ${t} failed with ${e.errno}: ${e.errmsg}`);return e},o=({serverURL:e,lang:t,paths:r,signal:o})=>fetch(`${e}/article?path=${encodeURIComponent(r.join(","))}&lang=${t}`,{signal:o}).then((e=>e.json())).then((e=>n(e,"visit count"))).then((e=>Array.isArray(e)?e:[e])),a=({serverURL:e,lang:t,path:o})=>fetch(`${e}/article?lang=${t}`,{method:"POST",headers:r,body:JSON.stringify({path:o})}).then((e=>e.json())).then((e=>n(e,"visit count"))),s=e=>e.dataset.path||e.getAttribute("id"),i=(e,t)=>{t.forEach(((t,r)=>{t.innerText=e[r].toString()}))};exports.pageviewCount=({serverURL:r,path:n=window.location.pathname,selector:l=".waline-pageview-count",update:h=!0,lang:c="zh-CN"})=>{const p=new AbortController,g=Array.from(document.querySelectorAll(l)),u=e=>{const t=s(e);return null!==t&&n!==t},d=a=>o({serverURL:e(r),paths:a.map((e=>s(e)||n)),lang:c,signal:p.signal}).then((e=>i(e,a))).catch(t);if(h){const e=g.filter((e=>!u(e))),t=g.filter(u);a({serverURL:r,path:n,lang:c}).then((t=>i(new Array(e.length).fill(t),e))),t.length&&d(t)}else d(g);return p.abort.bind(p)},exports.version="2.6.0";
2
2
  //# sourceMappingURL=pageview.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pageview.cjs.js","sources":["../src/version.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\n 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 updatePageviews({ serverURL, path, lang }).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":["errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","serverURL","lang","paths","signal","fetch","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"oEAEO,MCFMA,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,CAAcC,EAA0BN,EAAO,MAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACR,SAASR,iBAAqBM,EAAwBC,UACnDD,EAAwBG,UAI/B,OAAOH,GAgNII,EAAiB,EAC5BC,UAAAA,EACAC,KAAAA,EACAC,MAAAA,EACAC,OAAAA,KAEAC,MACE,GAAGJ,kBAA0BK,mBAC3BH,EAAMI,KAAK,cACHL,IACV,CAAEE,OAAAA,IAEDI,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,iBAEhCY,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAQ5CG,EAAkB,EAC7Bb,UAAAA,EACAC,KAAAA,EACAa,KAAAA,KAEAV,MAAM,GAAGJ,kBAA0BC,IAAQ,CACzCc,OAAQ,OACRC,QAASvB,EACTwB,KAAMC,KAAKC,UAAU,CAAEL,KAAAA,MAEtBP,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,iBCtQxByB,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCqDzCC,EAAqB,CACzBd,EACAe,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYlB,EAAOiB,GAAOE,qCAIT,EAC3B7B,UAAAA,EACAc,KAAAA,EAAOgB,OAAOC,SAASC,SACvBC,SAAAA,EAAW,yBACXC,OAAAA,GAAS,EACTjC,KAAAA,EAAO,YAEP,MAAMkC,EAAa,IAAIC,gBAEjBC,EAAW1B,MAAM2B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUpB,IACd,MAAMqB,EAAQtB,EAASC,GAEvB,OAAiB,OAAVqB,GAAkB5B,IAAS4B,GAG9BtC,EAASiC,GACbtC,EAAe,CACbC,UAAAA,EACAE,MAAOmC,EAASM,KAAKtB,GAAYD,EAASC,IAAYP,IACtDb,KAAAA,EACAE,OAAQgC,EAAWhC,SAElBI,MAAMG,GAAWc,EAAmBd,EAAQ2B,KAC5CO,MAAMzD,GAGX,GAAI+C,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQpB,IAAaoB,EAAOpB,KACtDyB,EAA2BT,EAASI,OAAOA,GAE5C5B,EAAgB,CAAEb,UAAAA,EAAWc,KAAAA,EAAMb,KAAAA,IAAQM,MAAMwC,GACpDvB,EACE,IAAIb,MAAckC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB5C,EAAM0C,QAKR1C,EAAMiC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,oBJjHR"}
1
+ {"version":3,"file":"pageview.cjs.js","sources":["../src/version.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","import {\n defaultLang,\n defaultLocales,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config';\n\nimport { decodePath, isLinkHttp, removeEndingSplash } from './path';\n\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\nexport interface WalineEmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface WalineConfig extends Required<Omit<WalineProps, 'wordLimit'>> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n // emoji: Promise<EmojiConfig>;\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 | false | 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 = defaultLang,\n locale,\n emoji = ['//unpkg.com/@waline/emojis@1.0.1/weibo'],\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 = getDefaultSearchOptions(),\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(defaultLocales[lang] || defaultLocales[defaultLang]),\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,\n dark,\n emoji,\n pageSize,\n login,\n copyright,\n search,\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","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n getServerURL,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\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 updatePageviews({ serverURL, path, lang }).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":["getServerURL","serverURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","lang","paths","signal","fetch","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"oEAEO,MC4BMA,EAAgBC,IAC3B,MAAMC,ECrB0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDoBTC,CAAmBJ,GAElC,MCnBA,kBAAkBK,KDmBAJ,GAAUA,EAAS,WAAWA,KEjCrCK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,CAAcC,EAA0BN,EAAO,MAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACR,SAASR,iBAAqBM,EAAwBC,UACnDD,EAAwBG,UAI/B,OAAOH,GAgNII,EAAiB,EAC5BlB,YACAmB,OACAC,QACAC,YAEAC,MACE,GAAGtB,kBAA0BuB,mBAC3BH,EAAMI,KAAK,cACHL,IACV,CAAEE,WAEDI,MAAMC,GAASA,EAAKC,SACpBF,MAAMX,GAASD,EAAWC,EAAM,iBAEhCW,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAQ5CG,EAAkB,EAC7B/B,YACAmB,OACAa,UAEAV,MAAM,GAAGtB,kBAA0BmB,IAAQ,CACzCc,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEL,WAEtBP,MAAMC,GAASA,EAAKC,SACpBF,MAAMX,GAASD,EAAWC,EAAM,iBCtQxBwB,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCsDzCC,EAAqB,CACzBd,EACAe,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYlB,EAAOiB,GAAOE,qCAIT,EAC3B/C,YACAgC,OAAOgB,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTjC,OAAO,YAEP,MAAMkC,EAAa,IAAIC,gBAEjBC,EAAW1B,MAAM2B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUpB,IACd,MAAMqB,EAAQtB,EAASC,GAEvB,OAAiB,OAAVqB,GAAkB5B,IAAS4B,GAG9BtC,EAASiC,GACbrC,EAAe,CACblB,UAAWD,EAAaC,GACxBoB,MAAOmC,EAASM,KAAKtB,GAAYD,EAASC,IAAYP,IACtDb,OACAE,OAAQgC,EAAWhC,SAElBI,MAAMG,GAAWc,EAAmBd,EAAQ2B,KAC5CO,MAAMxD,GAGX,GAAI8C,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQpB,IAAaoB,EAAOpB,KACtDyB,EAA2BT,EAASI,OAAOA,GAE5C5B,EAAgB,CAAE/B,YAAWgC,OAAMb,SAAQM,MAAMwC,GACpDvB,EACE,IAAIb,MAAckC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB5C,EAAM0C,QAKR1C,EAAMiC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB,oBNlHR"}
@@ -1,2 +1,2 @@
1
- const e="2.5.1",t=e=>{"AbortError"!==e.name&&console.error(e.message)},r={"Content-Type":"application/json"},n=(e,t="")=>{if("object"==typeof e&&e.errno)throw new TypeError(`Fetch ${t} failed with ${e.errno}: ${e.errmsg}`);return e},a=({serverURL:e,lang:t,paths:r,signal:a})=>fetch(`${e}/article?path=${encodeURIComponent(r.join(","))}&lang=${t}`,{signal:a}).then((e=>e.json())).then((e=>n(e,"visit count"))).then((e=>Array.isArray(e)?e:[e])),o=({serverURL:e,lang:t,path:a})=>fetch(`${e}/article?lang=${t}`,{method:"POST",headers:r,body:JSON.stringify({path:a})}).then((e=>e.json())).then((e=>n(e,"visit count"))),l=e=>e.dataset.path||e.getAttribute("id"),i=(e,t)=>{t.forEach(((t,r)=>{t.innerText=e[r].toString()}))},s=({serverURL:e,path:r=window.location.pathname,selector:n=".waline-pageview-count",update:s=!0,lang:h="zh-CN"})=>{const c=new AbortController,g=Array.from(document.querySelectorAll(n)),p=e=>{const t=l(e);return null!==t&&r!==t},f=n=>a({serverURL:e,paths:n.map((e=>l(e)||r)),lang:h,signal:c.signal}).then((e=>i(e,n))).catch(t);if(s){const t=g.filter((e=>!p(e))),n=g.filter(p);o({serverURL:e,path:r,lang:h}).then((e=>i(new Array(t.length).fill(e),t))),n.length&&f(n)}else f(g);return c.abort.bind(c)};export{s as pageviewCount,e as version};
1
+ const e="2.6.0",t=e=>{const t=((e="")=>e.replace(/\/$/u,""))(e);return/^(https?:)?\/\//.test(t)?t:`https://${t}`},r=e=>{"AbortError"!==e.name&&console.error(e.message)},n={"Content-Type":"application/json"},a=(e,t="")=>{if("object"==typeof e&&e.errno)throw new TypeError(`Fetch ${t} failed with ${e.errno}: ${e.errmsg}`);return e},o=({serverURL:e,lang:t,paths:r,signal:n})=>fetch(`${e}/article?path=${encodeURIComponent(r.join(","))}&lang=${t}`,{signal:n}).then((e=>e.json())).then((e=>a(e,"visit count"))).then((e=>Array.isArray(e)?e:[e])),l=({serverURL:e,lang:t,path:r})=>fetch(`${e}/article?lang=${t}`,{method:"POST",headers:n,body:JSON.stringify({path:r})}).then((e=>e.json())).then((e=>a(e,"visit count"))),s=e=>e.dataset.path||e.getAttribute("id"),i=(e,t)=>{t.forEach(((t,r)=>{t.innerText=e[r].toString()}))},h=({serverURL:e,path:n=window.location.pathname,selector:a=".waline-pageview-count",update:h=!0,lang:c="zh-CN"})=>{const p=new AbortController,g=Array.from(document.querySelectorAll(a)),u=e=>{const t=s(e);return null!==t&&n!==t},f=a=>o({serverURL:t(e),paths:a.map((e=>s(e)||n)),lang:c,signal:p.signal}).then((e=>i(e,a))).catch(r);if(h){const t=g.filter((e=>!u(e))),r=g.filter(u);l({serverURL:e,path:n,lang:c}).then((e=>i(new Array(t.length).fill(e),t))),r.length&&f(r)}else f(g);return p.abort.bind(p)};export{h as pageviewCount,e as version};
2
2
  //# sourceMappingURL=pageview.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pageview.esm.js","sources":["../src/version.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\n 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 updatePageviews({ serverURL, path, lang }).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","errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","serverURL","lang","paths","signal","fetch","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","pageviewCount","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"AAEO,MAAMA,EAAU,QCFVC,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,CAAcC,EAA0BN,EAAO,MAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACR,SAASR,iBAAqBM,EAAwBC,UACnDD,EAAwBG,UAI/B,OAAOH,GAgNII,EAAiB,EAC5BC,UAAAA,EACAC,KAAAA,EACAC,MAAAA,EACAC,OAAAA,KAEAC,MACE,GAAGJ,kBAA0BK,mBAC3BH,EAAMI,KAAK,cACHL,IACV,CAAEE,OAAAA,IAEDI,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,iBAEhCY,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAQ5CG,EAAkB,EAC7Bb,UAAAA,EACAC,KAAAA,EACAa,KAAAA,KAEAV,MAAM,GAAGJ,kBAA0BC,IAAQ,CACzCc,OAAQ,OACRC,QAASvB,EACTwB,KAAMC,KAAKC,UAAU,CAAEL,KAAAA,MAEtBP,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,iBCtQxByB,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCqDzCC,EAAqB,CACzBd,EACAe,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYlB,EAAOiB,GAAOE,eAIzBC,EAAgB,EAC3B9B,UAAAA,EACAc,KAAAA,EAAOiB,OAAOC,SAASC,SACvBC,SAAAA,EAAW,yBACXC,OAAAA,GAAS,EACTlC,KAAAA,EAAO,YAEP,MAAMmC,EAAa,IAAIC,gBAEjBC,EAAW3B,MAAM4B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUrB,IACd,MAAMsB,EAAQvB,EAASC,GAEvB,OAAiB,OAAVsB,GAAkB7B,IAAS6B,GAG9BvC,EAASkC,GACbvC,EAAe,CACbC,UAAAA,EACAE,MAAOoC,EAASM,KAAKvB,GAAYD,EAASC,IAAYP,IACtDb,KAAAA,EACAE,OAAQiC,EAAWjC,SAElBI,MAAMG,GAAWc,EAAmBd,EAAQ4B,KAC5CO,MAAM1D,GAGX,GAAIgD,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQrB,IAAaqB,EAAOrB,KACtD0B,EAA2BT,EAASI,OAAOA,GAE5C7B,EAAgB,CAAEb,UAAAA,EAAWc,KAAAA,EAAMb,KAAAA,IAAQM,MAAMyC,GACpDxB,EACE,IAAIb,MAAcmC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB7C,EAAM2C,QAKR3C,EAAMkC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB"}
1
+ {"version":3,"file":"pageview.esm.js","sources":["../src/version.ts","../src/utils/config.ts","../src/utils/path.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","import {\n defaultLang,\n defaultLocales,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config';\n\nimport { decodePath, isLinkHttp, removeEndingSplash } from './path';\n\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\nexport interface WalineEmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface WalineConfig extends Required<Omit<WalineProps, 'wordLimit'>> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n // emoji: Promise<EmojiConfig>;\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 | false | 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 = defaultLang,\n locale,\n emoji = ['//unpkg.com/@waline/emojis@1.0.1/weibo'],\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 = getDefaultSearchOptions(),\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(defaultLocales[lang] || defaultLocales[defaultLang]),\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,\n dark,\n emoji,\n pageSize,\n login,\n copyright,\n search,\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","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n getServerURL,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\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 updatePageviews({ serverURL, path, lang }).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","getServerURL","serverURL","result","content","replace","removeEndingSplash","test","errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","lang","paths","signal","fetch","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","pageviewCount","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"AAEO,MAAMA,EAAU,QC4BVC,EAAgBC,IAC3B,MAAMC,ECrB0B,EAACC,EAAU,KAC3CA,EAAQC,QAAQ,OAAQ,IDoBTC,CAAmBJ,GAElC,MCnBA,kBAAkBK,KDmBAJ,GAAUA,EAAS,WAAWA,KEjCrCK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,CAAcC,EAA0BN,EAAO,MAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACR,SAASR,iBAAqBM,EAAwBC,UACnDD,EAAwBG,UAI/B,OAAOH,GAgNII,EAAiB,EAC5BlB,YACAmB,OACAC,QACAC,YAEAC,MACE,GAAGtB,kBAA0BuB,mBAC3BH,EAAMI,KAAK,cACHL,IACV,CAAEE,WAEDI,MAAMC,GAASA,EAAKC,SACpBF,MAAMX,GAASD,EAAWC,EAAM,iBAEhCW,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,KAQ5CG,EAAkB,EAC7B/B,YACAmB,OACAa,UAEAV,MAAM,GAAGtB,kBAA0BmB,IAAQ,CACzCc,OAAQ,OACRC,QAAStB,EACTuB,KAAMC,KAAKC,UAAU,CAAEL,WAEtBP,MAAMC,GAASA,EAAKC,SACpBF,MAAMX,GAASD,EAAWC,EAAM,iBCtQxBwB,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCsDzCC,EAAqB,CACzBd,EACAe,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYlB,EAAOiB,GAAOE,eAIzBC,EAAgB,EAC3BhD,YACAgC,OAAOiB,OAAOC,SAASC,SACvBC,WAAW,yBACXC,UAAS,EACTlC,OAAO,YAEP,MAAMmC,EAAa,IAAIC,gBAEjBC,EAAW3B,MAAM4B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUrB,IACd,MAAMsB,EAAQvB,EAASC,GAEvB,OAAiB,OAAVsB,GAAkB7B,IAAS6B,GAG9BvC,EAASkC,GACbtC,EAAe,CACblB,UAAWD,EAAaC,GACxBoB,MAAOoC,EAASM,KAAKvB,GAAYD,EAASC,IAAYP,IACtDb,OACAE,OAAQiC,EAAWjC,SAElBI,MAAMG,GAAWc,EAAmBd,EAAQ4B,KAC5CO,MAAMzD,GAGX,GAAI+C,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQrB,IAAaqB,EAAOrB,KACtD0B,EAA2BT,EAASI,OAAOA,GAE5C7B,EAAgB,CAAE/B,YAAWgC,OAAMb,SAAQM,MAAMyC,GACpDxB,EACE,IAAIb,MAAcmC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB7C,EAAM2C,QAKR3C,EAAMkC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB"}
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;e.version="2.5.1";const t=e=>{"AbortError"!==e.name&&console.error(e.message)},n={"Content-Type":"application/json"},o=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if("object"==typeof e&&e.errno)throw new TypeError("Fetch ".concat(t," failed with ").concat(e.errno,": ").concat(e.errmsg));return e},r=e=>{let{serverURL:t,lang:n,paths:r,signal:a}=e;return fetch("".concat(t,"/article?path=").concat(encodeURIComponent(r.join(",")),"&lang=").concat(n),{signal:a}).then((e=>e.json())).then((e=>o(e,"visit count"))).then((e=>Array.isArray(e)?e:[e]))},a=e=>{let{serverURL:t,lang:r,path:a}=e;return fetch("".concat(t,"/article?lang=").concat(r),{method:"POST",headers:n,body:JSON.stringify({path:a})}).then((e=>e.json())).then((e=>o(e,"visit count")))},i=e=>e.dataset.path||e.getAttribute("id"),l=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};e.pageviewCount=e=>{let{serverURL:n,path:o=window.location.pathname,selector:s=".waline-pageview-count",update:c=!0,lang:h="zh-CN"}=e;const f=new AbortController,p=Array.from(document.querySelectorAll(s)),d=e=>{const t=i(e);return null!==t&&o!==t},g=e=>r({serverURL:n,paths:e.map((e=>i(e)||o)),lang:h,signal:f.signal}).then((t=>l(t,e))).catch(t);if(c){const e=p.filter((e=>!d(e))),t=p.filter(d);a({serverURL:n,path:o,lang:h}).then((t=>l(new Array(e.length).fill(t),e))),t.length&&g(t)}else g(p);return f.abort.bind(f)}}));
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;e.version="2.6.0";const t=e=>{const t=function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").replace(/\/$/u,"")}(e);return/^(https?:)?\/\//.test(t)?t:"https://".concat(t)},n=e=>{"AbortError"!==e.name&&console.error(e.message)},r={"Content-Type":"application/json"},o=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if("object"==typeof e&&e.errno)throw new TypeError("Fetch ".concat(t," failed with ").concat(e.errno,": ").concat(e.errmsg));return e},a=e=>{let{serverURL:t,lang:n,paths:r,signal:a}=e;return fetch("".concat(t,"/article?path=").concat(encodeURIComponent(r.join(",")),"&lang=").concat(n),{signal:a}).then((e=>e.json())).then((e=>o(e,"visit count"))).then((e=>Array.isArray(e)?e:[e]))},i=e=>{let{serverURL:t,lang:n,path:a}=e;return fetch("".concat(t,"/article?lang=").concat(n),{method:"POST",headers:r,body:JSON.stringify({path:a})}).then((e=>e.json())).then((e=>o(e,"visit count")))},l=e=>e.dataset.path||e.getAttribute("id"),s=(e,t)=>{t.forEach(((t,n)=>{t.innerText=e[n].toString()}))};e.pageviewCount=e=>{let{serverURL:r,path:o=window.location.pathname,selector:c=".waline-pageview-count",update:h=!0,lang:p="zh-CN"}=e;const f=new AbortController,u=Array.from(document.querySelectorAll(c)),d=e=>{const t=l(e);return null!==t&&o!==t},g=e=>a({serverURL:t(r),paths:e.map((e=>l(e)||o)),lang:p,signal:f.signal}).then((t=>s(t,e))).catch(n);if(h){const e=u.filter((e=>!d(e))),t=u.filter(d);i({serverURL:r,path:o,lang:p}).then((t=>s(new Array(e.length).fill(t),e))),t.length&&g(t)}else g(u);return f.abort.bind(f)}}));
2
2
  //# sourceMappingURL=pageview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pageview.js","sources":["../src/version.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\n 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 updatePageviews({ serverURL, path, lang }).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":["errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","_ref","serverURL","lang","paths","signal","fetch","concat","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","_ref2","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","_ref3","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"sXAEuB,QCFhB,MAAMA,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,SAAcC,GAA0C,IAAhBN,yDAAO,GAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACCR,SAAAA,OAAAA,0BAAqBM,EAAwBC,MACnDD,MAAAA,OAAAA,EAAwBG,SAI/B,OAAOH,GAgNII,EAAiBC,IAAA,IAACC,UAC7BA,EAD6BC,KAE7BA,EAF6BC,MAG7BA,EAH6BC,OAI7BA,GAJ4BJ,EAAA,OAM5BK,MAAK,GAAAC,OACAL,EADA,kBAAAK,OAC0BC,mBAC3BJ,EAAMK,KAAK,MAFV,UAAAF,OAGOJ,GACV,CAAEE,OAAAA,IAEDK,MAAMC,GAASA,EAAKC,SACpBF,MAAMd,GAASD,EAAWC,EAAM,iBAEhCc,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,MAQ5CG,EAAkBC,IAAA,IAACf,UAC9BA,EAD8BC,KAE9BA,EAF8Be,KAG9BA,GAH6BD,EAAA,OAK7BX,MAAK,GAAAC,OAAIL,EAAJ,kBAAAK,OAA8BJ,GAAQ,CACzCgB,OAAQ,OACRC,QAAS1B,EACT2B,KAAMC,KAAKC,UAAU,CAAEL,KAAAA,MAEtBR,MAAMC,GAASA,EAAKC,SACpBF,MAAMd,GAASD,EAAWC,EAAM,kBCtQxB4B,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCqDzCC,EAAqB,CACzBf,EACAgB,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYnB,EAAOkB,GAAOE,+BAITC,IAMiB,IANhBhC,UAC5BA,EAD4BgB,KAE5BA,EAAOiB,OAAOC,SAASC,SAFKC,SAG5BA,EAAW,yBAHiBC,OAI5BA,GAAS,EAJmBpC,KAK5BA,EAAO,SACqC+B,EAC5C,MAAMM,EAAa,IAAIC,gBAEjBC,EAAW5B,MAAM6B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUrB,IACd,MAAMsB,EAAQvB,EAASC,GAEvB,OAAiB,OAAVsB,GAAkB7B,IAAS6B,GAG9BzC,EAASoC,GACb1C,EAAe,CACbE,UAAAA,EACAE,MAAOsC,EAASM,KAAKvB,GAAYD,EAASC,IAAYP,IACtDf,KAAAA,EACAE,OAAQmC,EAAWnC,SAElBK,MAAMG,GAAWe,EAAmBf,EAAQ6B,KAC5CO,MAAM7D,GAGX,GAAImD,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQrB,IAAaqB,EAAOrB,KACtD0B,EAA2BT,EAASI,OAAOA,GAE5C9B,EAAgB,CAAEd,UAAAA,EAAWgB,KAAAA,EAAMf,KAAAA,IAAQO,MAAM0C,GACpDxB,EACE,IAAId,MAAcoC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB/C,EAAM6C,QAKR7C,EAAMoC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB"}
1
+ {"version":3,"file":"pageview.js","sources":["../src/version.ts","../src/utils/path.ts","../src/utils/config.ts","../src/utils/error.ts","../src/utils/fetch.ts","../src/utils/query.ts","../src/pageview.ts"],"sourcesContent":["declare const VERSION: string;\n\nexport const version = VERSION;\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","import {\n defaultLang,\n defaultLocales,\n defaultUploadImage,\n defaultHighlighter,\n defaultTexRenderer,\n getDefaultSearchOptions,\n getMeta,\n} from '../config';\n\nimport { decodePath, isLinkHttp, removeEndingSplash } from './path';\n\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\nexport interface WalineEmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface WalineConfig extends Required<Omit<WalineProps, 'wordLimit'>> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n // emoji: Promise<EmojiConfig>;\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 | false | 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 = defaultLang,\n locale,\n emoji = ['//unpkg.com/@waline/emojis@1.0.1/weibo'],\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 = getDefaultSearchOptions(),\n ...more\n}: WalineProps): WalineConfig => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n locale: {\n ...(defaultLocales[lang] || defaultLocales[defaultLang]),\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,\n dark,\n emoji,\n pageSize,\n login,\n copyright,\n search,\n ...more,\n});\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","import type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n lang: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n lang,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}&lang=${lang}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface DeleteCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: string | number;\n}\n\nexport const deleteComment = ({\n serverURL,\n lang,\n token,\n objectId,\n}: DeleteCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers,\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface LikeCommentOptions {\n serverURL: string;\n lang: string;\n objectId: number | string;\n like: boolean;\n}\n\nexport const likeComment = ({\n serverURL,\n lang,\n objectId,\n like,\n}: LikeCommentOptions): Promise<void> =>\n fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: JSON_HEADERS,\n body: JSON.stringify({ like }),\n }).then((resp) => resp.json() as Promise<void>);\n\nexport interface UpdateCommentOptions {\n serverURL: string;\n lang: string;\n token: string;\n objectId: number | string;\n status?: 'approved' | 'waiting' | 'spam';\n sticky?: number;\n}\n\nexport const updateComment = ({\n serverURL,\n lang,\n token,\n objectId,\n ...data\n}: UpdateCommentOptions): Promise<void> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&lang=${lang}`,\n { signal }\n )\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n lang: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n lang,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import {\n errorHandler,\n fetchPageviews,\n getQuery,\n getServerURL,\n updatePageviews,\n} from './utils';\n\nimport type { WalineAbort } from './typings';\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 'zh-CN'\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 = 'zh-CN',\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 fetchPageviews({\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 updatePageviews({ serverURL, path, lang }).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":["getServerURL","serverURL","result","replace","removeEndingSplash","test","concat","errorHandler","err","name","console","error","message","JSON_HEADERS","errorCheck","data","errno","TypeError","errmsg","fetchPageviews","_ref","lang","paths","signal","fetch","encodeURIComponent","join","then","resp","json","counts","Array","isArray","updatePageviews","_ref2","path","method","headers","body","JSON","stringify","getQuery","element","dataset","getAttribute","renderVisitorCount","countElements","forEach","index","innerText","toString","_ref3","window","location","pathname","selector","update","controller","AbortController","elements","from","document","querySelectorAll","filter","query","map","catch","normalElements","elementsNeedstoBeFetched","count","length","fill","abort","bind"],"mappings":"sXAEuB,QCQhB,MCoBMA,EAAgBC,IAC3B,MAAMC,EDrB0B,WAAA,8DAAW,IACnCC,QAAQ,OAAQ,ICoBTC,CAAmBH,GAElC,MDnBA,kBAAkBI,KCmBAH,GAAUA,EAArB,WAAAI,OAAyCJ,ICjCrCK,EAAgBC,IACV,eAAbA,EAAIC,MAAuBC,QAAQC,MAAMH,EAAII,UCM7CC,EAAuC,CAE3C,eAAgB,oBAGZC,EAAa,SAAcC,GAA0C,IAAhBN,yDAAO,GAChE,GAAoB,iBAATM,GAAsBA,EAAwBC,MACvD,MAAM,IAAIC,UACCR,SAAAA,OAAAA,0BAAqBM,EAAwBC,MACnDD,MAAAA,OAAAA,EAAwBG,SAI/B,OAAOH,GAgNII,EAAiBC,IAAA,IAACnB,UAC7BA,EAD6BoB,KAE7BA,EAF6BC,MAG7BA,EAH6BC,OAI7BA,GAJ4BH,EAAA,OAM5BI,MAAK,GAAAlB,OACAL,EADA,kBAAAK,OAC0BmB,mBAC3BH,EAAMI,KAAK,MAFV,UAAApB,OAGOe,GACV,CAAEE,WAEDI,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,iBAEhCY,MAAMG,GAAYC,MAAMC,QAAQF,GAAUA,EAAS,CAACA,MAQ5CG,EAAkBC,IAAA,IAACjC,UAC9BA,EAD8BoB,KAE9BA,EAF8Bc,KAG9BA,GAH6BD,EAAA,OAK7BV,MAAK,GAAAlB,OAAIL,EAAJ,kBAAAK,OAA8Be,GAAQ,CACzCe,OAAQ,OACRC,QAASxB,EACTyB,KAAMC,KAAKC,UAAU,CAAEL,WAEtBR,MAAMC,GAASA,EAAKC,SACpBF,MAAMZ,GAASD,EAAWC,EAAM,kBCtQxB0B,EAAYC,GACvBA,EAAQC,QAAQR,MAAQO,EAAQE,aAAa,MCsDzCC,EAAqB,CACzBf,EACAgB,KAEAA,EAAcC,SAAQ,CAACL,EAASM,KAC9BN,EAAQO,UAAYnB,EAAOkB,GAAOE,+BAITC,IAMiB,IANhBlD,UAC5BA,EAD4BkC,KAE5BA,EAAOiB,OAAOC,SAASC,SAFKC,SAG5BA,EAAW,yBAHiBC,OAI5BA,GAAS,EAJmBnC,KAK5BA,EAAO,SACqC8B,EAC5C,MAAMM,EAAa,IAAIC,gBAEjBC,EAAW5B,MAAM6B,KAErBC,SAASC,iBAA8BP,IAGnCQ,EAAUrB,IACd,MAAMsB,EAAQvB,EAASC,GAEvB,OAAiB,OAAVsB,GAAkB7B,IAAS6B,GAG9BxC,EAASmC,GACbxC,EAAe,CACblB,UAAWD,EAAaC,GACxBqB,MAAOqC,EAASM,KAAKvB,GAAYD,EAASC,IAAYP,IACtDd,OACAE,OAAQkC,EAAWlC,SAElBI,MAAMG,GAAWe,EAAmBf,EAAQ6B,KAC5CO,MAAM3D,GAGX,GAAIiD,EAAQ,CACV,MAAMW,EAAiBR,EAASI,QAAQrB,IAAaqB,EAAOrB,KACtD0B,EAA2BT,EAASI,OAAOA,GAE5C9B,EAAgB,CAAEhC,YAAWkC,OAAMd,SAAQM,MAAM0C,GACpDxB,EACE,IAAId,MAAcoC,EAAeG,QAAQC,KAAKF,GAC9CF,KAKAC,EAAyBE,QACtB9C,EAAM4C,QAKR5C,EAAMmC,GAGb,OAAOF,EAAWe,MAAMC,KAAKhB"}
package/dist/shim.d.ts CHANGED
@@ -37,6 +37,40 @@ interface WalineEmojiInfo {
37
37
  items: string[];
38
38
  }
39
39
  declare type WalineEmojiMaps = Record<string, string>;
40
+ interface WalineSearchResult extends Record<string, unknown> {
41
+ /**
42
+ * Image link
43
+ */
44
+ src: string;
45
+ /**
46
+ * Image title, optional
47
+ */
48
+ title?: string;
49
+ /**
50
+ * Image preview link, optional
51
+ *
52
+ * @default src
53
+ */
54
+ preview?: string;
55
+ }
56
+ interface WalineSearchOptions {
57
+ /**
58
+ * Search action
59
+ */
60
+ search: (word: string) => Promise<WalineSearchResult[]>;
61
+ /**
62
+ * Default search action
63
+ *
64
+ * @default () => search('')
65
+ */
66
+ default?: () => Promise<WalineSearchResult[]>;
67
+ /**
68
+ * Fetch more action
69
+ *
70
+ * @default (word) => search(word)
71
+ */
72
+ more?: (word: string, currectCount: number) => Promise<WalineSearchResult[]>;
73
+ }
40
74
  declare type WalineMeta = 'nick' | 'mail' | 'link';
41
75
  declare type WalineImageUploader = (image: File) => Promise<string>;
42
76
  declare type WalineHighlighter = (code: string, lang: string) => string;
@@ -280,6 +314,12 @@ interface WalineProps {
280
314
  * @default ['//unpkg.com/@waline/emojis@1.0.1/weibo']
281
315
  */
282
316
  emoji?: (string | WalineEmojiInfo)[] | false;
317
+ /**
318
+ * 设置搜索功能
319
+ *
320
+ * Customize Search feature
321
+ */
322
+ search?: WalineSearchOptions | false;
283
323
  /**
284
324
  * 代码高亮
285
325
  *
@@ -526,4 +566,4 @@ interface WalineRecentCommentsResult {
526
566
  }
527
567
  declare const RecentComments: ({ el, serverURL, count, lang, }: WalineRecentCommentsOptions) => Promise<WalineRecentCommentsResult>;
528
568
 
529
- export { RecentComments, WalineAbort, WalineComment, WalineCommentCountOptions, WalineCommentData, WalineCommentStatus, WalineDateLocale, WalineEmojiInfo, WalineEmojiMaps, WalineHighlighter, WalineImageUploader, WalineInitOptions, WalineInstance, WalineLevelLocale, WalineLocale, WalineMeta, WalinePageviewCountOptions, WalineProps, WalineRecentCommentsOptions, WalineRecentCommentsResult, WalineTexRenderer, commentCount, defaultLocales, init, pageviewCount, version };
569
+ export { RecentComments, WalineAbort, WalineComment, WalineCommentCountOptions, WalineCommentData, WalineCommentStatus, WalineDateLocale, WalineEmojiInfo, WalineEmojiMaps, WalineHighlighter, WalineImageUploader, WalineInitOptions, WalineInstance, WalineLevelLocale, WalineLocale, WalineMeta, WalinePageviewCountOptions, WalineProps, WalineRecentCommentsOptions, WalineRecentCommentsResult, WalineSearchOptions, WalineSearchResult, WalineTexRenderer, commentCount, defaultLocales, init, pageviewCount, version };
@@ -37,6 +37,40 @@ interface WalineEmojiInfo {
37
37
  items: string[];
38
38
  }
39
39
  declare type WalineEmojiMaps = Record<string, string>;
40
+ interface WalineSearchResult extends Record<string, unknown> {
41
+ /**
42
+ * Image link
43
+ */
44
+ src: string;
45
+ /**
46
+ * Image title, optional
47
+ */
48
+ title?: string;
49
+ /**
50
+ * Image preview link, optional
51
+ *
52
+ * @default src
53
+ */
54
+ preview?: string;
55
+ }
56
+ interface WalineSearchOptions {
57
+ /**
58
+ * Search action
59
+ */
60
+ search: (word: string) => Promise<WalineSearchResult[]>;
61
+ /**
62
+ * Default search action
63
+ *
64
+ * @default () => search('')
65
+ */
66
+ default?: () => Promise<WalineSearchResult[]>;
67
+ /**
68
+ * Fetch more action
69
+ *
70
+ * @default (word) => search(word)
71
+ */
72
+ more?: (word: string, currectCount: number) => Promise<WalineSearchResult[]>;
73
+ }
40
74
  declare type WalineMeta = 'nick' | 'mail' | 'link';
41
75
  declare type WalineImageUploader = (image: File) => Promise<string>;
42
76
  declare type WalineHighlighter = (code: string, lang: string) => string;
@@ -280,6 +314,12 @@ interface WalineProps {
280
314
  * @default ['//unpkg.com/@waline/emojis@1.0.1/weibo']
281
315
  */
282
316
  emoji?: (string | WalineEmojiInfo)[] | false;
317
+ /**
318
+ * 设置搜索功能
319
+ *
320
+ * Customize Search feature
321
+ */
322
+ search?: WalineSearchOptions | false;
283
323
  /**
284
324
  * 代码高亮
285
325
  *
@@ -526,4 +566,4 @@ interface WalineRecentCommentsResult {
526
566
  }
527
567
  declare const RecentComments: ({ el, serverURL, count, lang, }: WalineRecentCommentsOptions) => Promise<WalineRecentCommentsResult>;
528
568
 
529
- export { RecentComments, WalineAbort, WalineComment, WalineCommentCountOptions, WalineCommentData, WalineCommentStatus, WalineDateLocale, WalineEmojiInfo, WalineEmojiMaps, WalineHighlighter, WalineImageUploader, WalineInitOptions, WalineInstance, WalineLevelLocale, WalineLocale, WalineMeta, WalinePageviewCountOptions, WalineProps, WalineRecentCommentsOptions, WalineRecentCommentsResult, WalineTexRenderer, commentCount, defaultLocales, init, pageviewCount, version };
569
+ export { RecentComments, WalineAbort, WalineComment, WalineCommentCountOptions, WalineCommentData, WalineCommentStatus, WalineDateLocale, WalineEmojiInfo, WalineEmojiMaps, WalineHighlighter, WalineImageUploader, WalineInitOptions, WalineInstance, WalineLevelLocale, WalineLocale, WalineMeta, WalinePageviewCountOptions, WalineProps, WalineRecentCommentsOptions, WalineRecentCommentsResult, WalineSearchOptions, WalineSearchResult, WalineTexRenderer, commentCount, defaultLocales, init, pageviewCount, version };