@waline/client 2.12.0 → 2.13.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.
@@ -1 +1 @@
1
- {"version":3,"file":"waline.js","sources":["../src/config/default.ts","../src/config/highlighter.ts","../src/config/i18n/generate.ts","../src/config/i18n/en.ts","../src/config/i18n/jp.ts","../src/config/i18n/zh-CN.ts","../src/config/i18n/zh-TW.ts","../src/config/i18n/pt-BR.ts","../src/config/i18n/ru.ts","../src/config/i18n/index.ts","../src/api/utils.ts","../src/api/articleCounter.ts","../src/api/comment.ts","../src/utils/path.ts","../src/utils/config.ts","../src/utils/darkmode.ts","../src/utils/date.ts","../src/utils/emoji.ts","../src/utils/error.ts","../src/utils/getRoot.ts","../src/utils/image.ts","../src/utils/markedMathExtension.ts","../src/utils/markdown.ts","../src/utils/query.ts","../src/comment.ts","../src/api/commentCount.ts","../src/composables/like.ts","../src/composables/recaptchaV3.ts","../src/composables/timeAgo.ts","../src/composables/vote.ts","../src/composables/userInfo.ts","../src/components/ArticleReaction.vue","../src/components/Icons.ts","../src/components/ImageWall.vue","../src/components/CommentBox.vue","../src/composables/inputs.ts","../src/utils/wordCount.ts","../src/api/login.ts","../src/components/CommentCard.vue","../src/components/Waline.vue","../src/pageview.ts","../src/api/pageview.ts","../src/init.ts","../src/version.ts","../src/widgets/recentComments.ts","../src/api/recentComment.ts"],"sourcesContent":["import type { IGif } from '@giphy/js-types';\nimport type {\n WalineMeta,\n WalineSearchOptions,\n WalineSearchResult,\n} from '../typings';\n\nconst availableMeta: WalineMeta[] = ['nick', 'mail', 'link'];\n\nexport const getMeta = (meta: WalineMeta[]): WalineMeta[] =>\n meta.filter((item) => availableMeta.includes(item));\n\nexport const defaultLang = 'zh-CN';\n\nexport const defaultUploadImage = (file: File): Promise<string> =>\n new Promise((resolve, reject) => {\n if (file.size > 128 * 1000) {\n return reject(new Error('File too large! File size limit 128KB'));\n }\n\n const reader = new FileReader();\n\n reader.readAsDataURL(file);\n reader.onload = (): void => resolve(reader.result?.toString() || '');\n reader.onerror = reject;\n });\n\nexport const defaultTexRenderer = (blockMode: boolean): string =>\n blockMode === true\n ? '<p class=\"wl-tex\">Tex is not available in preview</p>'\n : '<span class=\"wl-tex\">Tex is not available in preview</span>';\n\nexport const getDefaultSearchOptions = (lang: string): WalineSearchOptions => {\n interface Result {\n meta: {\n msg: string;\n response_id: string;\n status: number;\n };\n pagination: {\n count: number;\n total_count: number;\n offset: number;\n };\n }\n interface GifsResult extends Result {\n data: IGif[];\n }\n\n const fetchGiphy = async (\n url: string,\n params: Record<string, string> = {}\n ): Promise<WalineSearchResult> => {\n const querystring = new URLSearchParams({\n lang,\n limit: '20',\n rating: 'g',\n api_key: '6CIMLkNMMOhRcXPoMCPkFy4Ybk2XUiMp',\n ...params,\n }).toString();\n\n const resp = await fetch(\n `https://api.giphy.com/v1/gifs/${url}?${querystring}`\n ).then((resp) => resp.json() as Promise<GifsResult>);\n\n return resp.data.map((gif) => ({\n title: gif.title,\n src: gif.images.downsized_medium.url,\n }));\n };\n\n return {\n search: (word: string): Promise<WalineSearchResult> =>\n fetchGiphy('search', { q: word, offset: '0' }),\n default: (): Promise<WalineSearchResult> => fetchGiphy('trending', {}),\n more: (word: string, offset = 0): Promise<WalineSearchResult> =>\n fetchGiphy('search', { q: word, offset: offset.toString() }),\n };\n};\n\nexport const defaultReaction = [\n '//unpkg.com/@waline/emojis/tieba/tieba_agree.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_look_down.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_sunglasses.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_pick_nose.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_awkward.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_sleep.png',\n];\n","/**\n * The MIT License (MIT)\n *\n * Copyright (c) egoist <0x142857@gmail.com> (https://egoistian.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\nconst WORD_REGEXP =\n /[\\u4E00-\\u9FFF\\u3400-\\u4dbf\\uf900-\\ufaff\\u3040-\\u309f\\uac00-\\ud7af\\u0400-\\u04FF]+|\\w+/;\nconst LEFT_ANGLE_REGEXP = /</;\nconst LINE_COMMENT_REGEXP = /(?:^|\\s)\\/\\/(.+?)$/gm;\nconst BLOCK_COMMENT_REGEXP = /\\/\\*([\\S\\s]*?)\\*\\//gm;\nconst REGEXP = new RegExp(\n `(${WORD_REGEXP.source}|${LEFT_ANGLE_REGEXP.source})|((?:${LINE_COMMENT_REGEXP.source})|(?:${BLOCK_COMMENT_REGEXP.source}))`,\n 'gmi'\n);\n\nconst COLORS = [\n '23AC69',\n '91C132',\n 'F19726',\n 'E8552D',\n '1AAB8E',\n 'E1147F',\n '2980C1',\n '1BA1E6',\n '9FA0A0',\n 'F19726',\n 'E30B20',\n 'E30B20',\n 'A3338B',\n];\nconst cache: Record<string, string> = {};\n\nexport const defaultHighlighter = (input: string): string => {\n let index = 0;\n\n return input.replace(REGEXP, (_match, word: string, comment: string) => {\n if (comment) return `<span style=\"color: slategray\">${comment}</span>`;\n if (word === '<') return '&lt;';\n\n let color: string;\n\n if (cache[word]) color = cache[word];\n else {\n color = COLORS[index];\n cache[word] = color;\n }\n\n const out = `<span style=\"color: #${color}\">${word}</span>`;\n\n index = ++index % COLORS.length;\n\n return out;\n });\n};\n","import type { WalineLocale } from '../../typings';\n\nconst localeKeys = [\n 'nick',\n 'nickError',\n 'mail',\n 'mailError',\n 'link',\n 'optional',\n 'placeholder',\n 'sofa',\n 'submit',\n 'like',\n 'cancelLike',\n 'reply',\n 'cancelReply',\n 'comment',\n 'refresh',\n 'more',\n 'preview',\n 'emoji',\n 'uploadImage',\n 'seconds',\n 'minutes',\n 'hours',\n 'days',\n 'now',\n 'uploading',\n 'login',\n 'logout',\n 'admin',\n 'sticky',\n 'word',\n 'wordHint',\n 'anonymous',\n 'level0',\n 'level1',\n 'level2',\n 'level3',\n 'level4',\n 'level5',\n 'gif',\n 'gifSearchPlaceholder',\n 'profile',\n 'approved',\n 'waiting',\n 'spam',\n 'unsticky',\n 'oldest',\n 'latest',\n 'hottest',\n 'reactionTitle',\n];\n\nexport const generateLocale = (locale: string[]): WalineLocale =>\n Object.fromEntries(\n locale.map((item, index) => [localeKeys[index], item])\n ) as unknown as WalineLocale;\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'NickName',\n 'NickName cannot be less than 3 bytes.',\n 'E-Mail',\n 'Please confirm your email address.',\n 'Website',\n 'Optional',\n 'Comment here...',\n 'No comment yet.',\n 'Submit',\n 'Like',\n 'Cancel like',\n 'Reply',\n 'Cancel reply',\n 'Comments',\n 'Refresh',\n 'Load More...',\n 'Preview',\n 'Emoji',\n 'Upload Image',\n 'seconds ago',\n 'minutes ago',\n 'hours ago',\n 'days ago',\n 'just now',\n 'Uploading',\n 'Login',\n 'logout',\n 'Admin',\n 'Sticky',\n 'Words',\n 'Please input comments between $0 and $1 words!\\n Current word number: $2',\n 'Anonymous',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Search GIF',\n 'Profile',\n 'Approved',\n 'Waiting',\n 'Spam',\n 'Unsticky',\n 'Oldest',\n 'Latest',\n 'Hottest',\n 'What do you think?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'ニックネーム',\n '3バイト以上のニックネームをご入力ください.',\n 'メールアドレス',\n 'メールアドレスをご確認ください.',\n 'サイト',\n 'オプション',\n 'ここにコメント',\n 'コメントしましょう~',\n '提出する',\n 'Like',\n 'Cancel like',\n '返信する',\n 'キャンセル',\n 'コメント',\n '更新',\n 'さらに読み込む',\n 'プレビュー',\n '絵文字',\n '画像をアップロード',\n '秒前',\n '分前',\n '時間前',\n '日前',\n 'たっだ今',\n 'アップロード',\n 'ログインする',\n 'ログアウト',\n '管理者',\n 'トップに置く',\n 'ワード',\n 'コメントは $0 から $1 ワードの間でなければなりません!\\n 現在の単語番号: $2',\n '匿名',\n 'うえにん',\n 'なかにん',\n 'しもおし',\n '特にしもおし',\n 'かげ',\n 'なぬし',\n 'GIF',\n '探す GIF',\n '個人情報',\n '承認済み',\n '待っている',\n 'スパム',\n 'べたつかない',\n '逆順',\n '正順',\n '人気順',\n 'どう思いますか?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '昵称',\n '昵称不能少于3个字符',\n '邮箱',\n '请填写正确的邮件地址',\n '网址',\n '可选',\n '欢迎评论',\n '来发评论吧~',\n '提交',\n '喜欢',\n '取消喜欢',\n '回复',\n '取消回复',\n '评论',\n '刷新',\n '加载更多...',\n '预览',\n '表情',\n '上传图片',\n '秒前',\n '分钟前',\n '小时前',\n '天前',\n '刚刚',\n '正在上传',\n '登录',\n '退出',\n '博主',\n '置顶',\n '字',\n '评论字数应在 $0 到 $1 字之间!\\n当前字数:$2',\n '匿名',\n '潜水',\n '冒泡',\n '吐槽',\n '活跃',\n '话痨',\n '传说',\n '表情包',\n '搜索表情包',\n '个人资料',\n '通过',\n '待审核',\n '垃圾',\n '取消置顶',\n '按倒序',\n '按正序',\n '按热度',\n '你认为这篇文章怎么样?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '暱稱',\n '暱稱不能少於3個字元',\n '郵箱',\n '請填寫正確的郵件地址',\n '網址',\n '可選',\n '歡迎評論',\n '來發評論吧~',\n '提交',\n '喜歡',\n '取消喜歡',\n '回覆',\n '取消回覆',\n '評論',\n '刷新',\n '載入更多...',\n '預覽',\n '表情',\n '上傳圖片',\n '秒前',\n '分鐘前',\n '小時前',\n '天前',\n '剛剛',\n '正在上傳',\n '登錄',\n '退出',\n '博主',\n '置頂',\n '字',\n '評論字數應在 $0 到 $1 字之間!\\n當前字數:$2',\n '匿名',\n '潛水',\n '冒泡',\n '吐槽',\n '活躍',\n '話癆',\n '傳說',\n '表情包',\n '搜索表情包',\n '個人資料',\n '通過',\n '待審核',\n '垃圾',\n '取消置頂',\n '按倒序',\n '按正序',\n '按熱度',\n '你認為這篇文章怎麼樣?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'Apelido',\n 'Apelido não pode ser menor que 3 bytes.',\n 'E-Mail',\n 'Por favor, confirme seu endereço de e-mail.',\n 'Website',\n 'Opcional',\n 'Comente aqui...',\n 'Nenhum comentário, ainda.',\n 'Enviar',\n 'Like',\n 'Cancel like',\n 'Responder',\n 'Cancelar resposta',\n 'Comentários',\n 'Refrescar',\n 'Carregar Mais...',\n 'Visualizar',\n 'Emoji',\n 'Enviar Imagem',\n 'segundos atrás',\n 'minutos atrás',\n 'horas atrás',\n 'dias atrás',\n 'agora mesmo',\n 'Enviando',\n 'Entrar',\n 'Sair',\n 'Admin',\n 'Sticky',\n 'Palavras',\n 'Favor enviar comentário com $0 a $1 palavras!\\n Número de palavras atuais: $2',\n 'Anônimo',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Pesquisar GIF',\n 'informação pessoal',\n 'Aprovado',\n 'Espera',\n 'Spam',\n 'Unsticky',\n 'Mais velho',\n 'Mais recentes',\n 'Mais quente',\n 'O que você acha?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'Псевдоним',\n 'Никнейм не может быть меньше 3 байт.',\n 'Эл. адрес',\n 'Пожалуйста, подтвердите адрес вашей электронной почты.',\n 'Веб-сайт',\n 'Необязательный',\n 'Комментарий здесь...',\n 'Пока нет комментариев.',\n 'Отправить',\n 'Like',\n 'Cancel like',\n 'Отвечать',\n 'Отменить ответ',\n 'Комментарии',\n 'Обновить',\n 'Загрузи больше...',\n 'Превью',\n 'эмодзи',\n 'Загрузить изображение',\n 'секунд назад',\n 'несколько минут назад',\n 'несколько часов назад',\n 'дней назад',\n 'прямо сейчас',\n 'Загрузка',\n 'Авторизоваться',\n 'Выход из системы',\n 'Админ',\n 'Липкий',\n 'Слова',\n 'Пожалуйста, введите комментарии от $0 до $1 слов!\\nНомер текущего слова: $2',\n 'Анонимный',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Поиск GIF',\n 'Персональные данные',\n 'Одобренный',\n 'Ожидающий',\n 'Спам',\n 'Нелипкий',\n 'самый старый',\n 'последний',\n 'самый горячий',\n 'Что вы думаете?',\n]);\n","/* eslint-disable @typescript-eslint/naming-convention */\nimport en from './en';\nimport jp from './jp';\nimport zhCN from './zh-CN';\nimport zhTW from './zh-TW';\nimport ptBR from './pt-BR';\nimport ru from './ru';\n\nimport type { WalineLocale } from '../../typings';\n\nexport type Locales = Record<string, WalineLocale>;\n\nexport const defaultLocales: Locales = {\n zh: zhCN,\n 'zh-cn': zhCN,\n 'zh-CN': zhCN,\n 'zh-tw': zhTW,\n 'zh-TW': zhTW,\n en: en,\n 'en-US': en,\n 'en-us': en,\n jp: jp,\n 'jp-jp': jp,\n 'jp-JP': jp,\n 'pt-br': ptBR,\n 'pt-BR': ptBR,\n ru: ru,\n 'ru-ru': ru,\n 'ru-RU': ru,\n};\n","export interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T = unknown>(\n data: T | FetchErrorData,\n name = ''\n): 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","import { JSON_HEADERS, errorCheck } from './utils';\n\nexport interface FetchArticleCounterOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n type: string[];\n}\n\nexport const fetchArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: FetchArticleCounterOptions): Promise<\n Record<string, number>[] | Record<string, number> | number[] | number\n> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal }\n )\n .then(\n (resp) =>\n resp.json() as Promise<Record<string, number>[] | number[] | number>\n )\n .then((data) => errorCheck(data, 'article count'));\n\nexport interface UpdateArticleCounterOptions {\n serverURL: string;\n lang: string;\n path: string;\n type: string;\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'article count'));\n","import { JSON_HEADERS, errorCheck } from './utils';\nimport type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchCommentOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n sortBy: string;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface CommentData {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchComment = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n sortBy,\n signal,\n token,\n}: FetchCommentOptions): Promise<CommentData> => {\n const headers: Record<string, string> = {};\n\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}&sortBy=${sortBy}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<CommentData>)\n .then((data) => errorCheck(data, 'comment data'));\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 if (comment.eid) {\n return fetch(`${serverURL}/comment/${comment.eid}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n }\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 fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n }).then((resp) => resp.json() as Promise<void>);\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 fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: {\n ...JSON_HEADERS,\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\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 defaultReaction,\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\n extends Required<Omit<WalineProps, 'wordLimit' | 'reaction'>> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n reaction: string[];\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.1.0/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,\n reaction,\n recaptchaV3Key = '',\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: search || getDefaultSearchOptions(lang),\n recaptchaV3Key,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? defaultReaction\n : [],\n ...more,\n});\n","const style = `{--waline-white:#000;--waline-light-grey:#666;--waline-dark-grey:#999;--waline-color:#888;--waline-bgcolor:#1e1e1e;--waline-bgcolor-light:#272727;--waline-bgcolor-hover: #444;--waline-border-color:#333;--waline-disable-bgcolor:#444;--waline-disable-color:#272727;--waline-bq-color:#272727;--waline-info-bgcolor:#272727;--waline-info-color:#666}`;\n\nexport const getDarkStyle = (selector?: string | boolean): string => {\n if (typeof selector === 'string') {\n return selector === 'auto'\n ? `@media(prefers-color-scheme:dark){body${style}}`\n : `${selector}${style}`;\n }\n\n return selector === true ? `:root${style}` : '';\n};\n","import { WalineDateLocale } from '../typings';\n\nconst padWithZeros = (vNumber: number, width: number): string => {\n let numAsString = vNumber.toString();\n\n while (numAsString.length < width) {\n numAsString = '0' + numAsString;\n }\n\n return numAsString;\n};\n\nexport const dateFormat = (date: Date): string => {\n const vDay = padWithZeros(date.getDate(), 2);\n const vMonth = padWithZeros(date.getMonth() + 1, 2);\n const vYear = padWithZeros(date.getFullYear(), 2);\n\n return `${vYear}-${vMonth}-${vDay}`;\n};\n\nexport const getTimeAgo = (\n date: Date | string,\n now: Date,\n locale: WalineDateLocale\n): string => {\n if (!date) return '';\n\n const time =\n typeof date === 'string'\n ? new Date(date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date)\n : date;\n\n const timepassed = now.getTime() - time.getTime();\n\n const days = Math.floor(timepassed / (24 * 3600 * 1000));\n\n if (days === 0) {\n // 计算相差小时数\n\n // 计算天数后剩余的毫秒数\n const leave1 = timepassed % (24 * 3600 * 1000);\n const hours = Math.floor(leave1 / (3600 * 1000));\n\n if (hours === 0) {\n //计算相差分钟数\n\n // 计算小时数后剩余的毫秒数\n const leave2 = leave1 % (3600 * 1000);\n const minutes = Math.floor(leave2 / (60 * 1000));\n\n // 计算相差秒数\n if (minutes === 0) {\n // 计算分钟数后剩余的毫秒数\n const leave3 = leave2 % (60 * 1000);\n const seconds = Math.round(leave3 / 1000);\n\n return `${seconds} ${locale.seconds}`;\n }\n\n return `${minutes} ${locale.minutes}`;\n }\n\n return `${hours} ${locale.hours}`;\n }\n\n if (days < 0) return locale.now;\n\n if (days < 8) return `${days} ${locale.days}`;\n\n return dateFormat(time);\n};\n","import { useStorage } from '@vueuse/core';\nimport { removeEndingSplash } from './path';\n\nimport type { WalineEmojiConfig } from './config';\nimport type { WalineEmojiInfo } from '../typings';\n\nconst hasVersion = (url: string): boolean =>\n Boolean(/@[0-9]+\\.[0-9]+\\.[0-9]+/.test(url));\n\nconst fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {\n const emojiStore = useStorage<Record<string, WalineEmojiInfo>>(\n 'WALINE_EMOJI',\n {}\n );\n\n const result = hasVersion(link);\n\n if (result) {\n const info = emojiStore.value[link];\n\n if (info) return Promise.resolve(info);\n }\n\n return fetch(`${link}/info.json`)\n .then((resp) => resp.json() as Promise<Omit<WalineEmojiInfo, 'folder'>>)\n .then((emojiInfo) => {\n const info = {\n folder: link,\n ...emojiInfo,\n };\n\n if (result) emojiStore.value[link] = info;\n\n return info;\n });\n};\n\nconst getLink = (name: string, folder = '', prefix = '', type = ''): string =>\n `${folder ? `${folder}/` : ''}${prefix}${name}${type ? `.${type}` : ''}`;\n\nexport const getEmojis = (\n emojis: (string | WalineEmojiInfo)[]\n): Promise<WalineEmojiConfig> =>\n Promise.all(\n emojis.map((emoji) =>\n typeof emoji === 'string'\n ? fetchEmoji(removeEndingSplash(emoji))\n : Promise.resolve(emoji)\n )\n ).then((emojiInfos) => {\n const emojiConfig: WalineEmojiConfig = {\n tabs: [],\n map: {},\n };\n\n emojiInfos.forEach((emojiInfo) => {\n const { name, folder, icon, prefix, type, items } = emojiInfo;\n\n emojiConfig.tabs.push({\n name,\n icon: getLink(icon, folder, prefix, type),\n items: items.map((item) => {\n const key = `${prefix || ''}${item}`;\n\n emojiConfig.map[key] = getLink(item, folder, prefix, type);\n\n return key;\n }),\n });\n });\n\n return emojiConfig;\n });\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","export const getRoot = (\n el: string | HTMLElement | undefined\n): HTMLElement | null =>\n el instanceof HTMLElement\n ? el\n : typeof el === 'string'\n ? document.querySelector(el)\n : null;\n","const isImage = (item: DataTransferItem): boolean =>\n item.type.includes('image');\n\nexport const getImagefromDataTransfer = (\n items: DataTransferItemList\n): File | null => {\n const image = Array.from(items).find(isImage);\n\n return image ? (image.getAsFile() as File) : null;\n};\n","import type { marked } from 'marked';\nimport type { WalineTexRenderer } from '../typings';\n\nconst inlineMathStart = /\\$.*?\\$/;\nconst inlineMathReg = /^\\$(.*?)\\$/;\nconst blockMathReg = /^(?:\\s{0,3})\\$\\$((?:[^\\n]|\\n[^\\n])+?)\\n{0,1}\\$\\$/;\n\nexport const markedTexExtensions = (\n texRenderer: WalineTexRenderer\n): marked.TokenizerExtension[] => {\n const blockMathExtension: marked.TokenizerExtension = {\n name: 'blockMath',\n level: 'block',\n tokenizer(src: string) {\n const cap = blockMathReg.exec(src);\n\n if (cap !== null) {\n return {\n type: 'html',\n raw: cap[0],\n text: texRenderer(true, cap[1]),\n };\n }\n\n return undefined;\n },\n };\n\n const inlineMathExtension: marked.TokenizerExtension = {\n name: 'inlineMath',\n level: 'inline',\n start(src: string) {\n const idx = src.search(inlineMathStart);\n\n return idx !== -1 ? idx : src.length;\n },\n tokenizer(src: string) {\n const cap = inlineMathReg.exec(src);\n\n if (cap !== null) {\n return {\n type: 'html',\n raw: cap[0],\n text: texRenderer(false, cap[1]),\n };\n }\n\n return undefined;\n },\n };\n\n return [blockMathExtension, inlineMathExtension];\n};\n","import { marked } from 'marked';\nimport { markedTexExtensions } from './markedMathExtension';\n\nimport type {\n WalineEmojiMaps,\n WalineHighlighter,\n WalineTexRenderer,\n} from '../typings';\n\nexport const parseEmoji = (text = '', emojiMap: WalineEmojiMaps = {}): string =>\n text.replace(/:(.+?):/g, (placeholder, key: string) =>\n emojiMap[key]\n ? `<img class=\"wl-emoji\" src=\"${emojiMap[key]}\" alt=\"${key}\">`\n : placeholder\n );\n\nexport interface ParseMarkdownOptions {\n emojiMap: WalineEmojiMaps;\n highlighter: WalineHighlighter | false;\n texRenderer: WalineTexRenderer | false;\n}\n\nexport const parseMarkdown = (\n content: string,\n { emojiMap, highlighter, texRenderer }: ParseMarkdownOptions\n): string => {\n marked.setOptions({\n highlight: highlighter || undefined,\n breaks: true,\n smartLists: true,\n smartypants: true,\n });\n\n if (texRenderer) {\n const extensions = markedTexExtensions(texRenderer);\n\n marked.use({ extensions });\n }\n\n return marked.parse(parseEmoji(content, emojiMap));\n};\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import { fetchCommentCount } from './api';\nimport { decodePath, errorHandler, getServerURL } from './utils';\nimport type { WalineAbort } from './typings';\n\nexport interface WalineCommentCountOptions {\n /**\n * Waline 服务端地址\n *\n * Waline server url\n */\n serverURL: string;\n\n /**\n * 评论数 CSS 选择器\n *\n * Commment count CSS selector\n *\n * @default '.waline-comment-count'\n */\n selector?: string;\n\n /**\n * 需要获取的默认路径\n *\n * Path to be fetched by default\n *\n * @default window.location.pathname\n */\n path?: string;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default 'zh-CN'\n */\n lang?: string;\n}\n\nexport const commentCount = ({\n serverURL,\n path = window.location.pathname,\n selector = '.waline-comment-count',\n lang = 'zh-CN',\n}: // eslint-disable-next-line @typescript-eslint/no-explicit-any\nWalineCommentCountOptions): WalineAbort => {\n const controller = new AbortController();\n\n // comment count\n const elements = document.querySelectorAll<HTMLElement>(selector);\n\n if (elements.length)\n void fetchCommentCount({\n serverURL: getServerURL(serverURL),\n paths: Array.from(elements).map((element) =>\n decodePath(element.dataset.path || element.getAttribute('id') || path)\n ),\n lang,\n signal: controller.signal,\n })\n .then((counts) => {\n elements.forEach((element, index) => {\n element.innerText = counts[index].toString();\n });\n })\n .catch(errorHandler);\n\n return controller.abort.bind(controller);\n};\n","import { errorCheck } from './utils';\n\nexport interface FetchCommentCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchCommentCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\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};\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\n\nconst LIKE_KEY = 'WALINE_LIKE';\n\nexport type LikeID = number | string;\n\nexport type LikeRef = Ref<LikeID[]>;\n\nlet likeStorage: LikeRef | null = null;\n\nexport const useLikeStorage = (): LikeRef =>\n likeStorage || (likeStorage = useStorage<LikeID[]>(LIKE_KEY, []));\n","import { load } from 'recaptcha-v3';\n\nimport type { ReCaptchaInstance } from 'recaptcha-v3';\n\nconst recaptchaStore: Record<string, Promise<ReCaptchaInstance>> = {};\n\ninterface ReCaptcha {\n execute: (action: string) => Promise<string>;\n}\n\nexport const useReCaptcha = (key: string): ReCaptcha => {\n const init =\n recaptchaStore[key] ??\n (recaptchaStore[key] = load(key, {\n useRecaptchaNet: true,\n autoHideBadge: true,\n }));\n\n return {\n execute: (action: string) =>\n init.then((instance) => instance.execute(action)),\n };\n};\n","import { useNow } from '@vueuse/core';\nimport { computed } from 'vue';\nimport { getTimeAgo } from '../utils';\n\nimport type { ComputedRef } from 'vue';\nimport type { WalineLocale } from '../typings';\n\nexport const useTimeAgo = (\n date: Date | string,\n locale: WalineLocale\n): ComputedRef<string> => {\n const now = useNow();\n\n return computed(() => getTimeAgo(date, now.value, locale));\n};\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\n\nconst VOTE_KEY = 'WALINE_VOTE';\n\nexport const VOTE_IDENTIFIER = 'id';\nexport const VOTE_INDEX = 'i';\n\nexport interface VoteLogItem {\n [VOTE_IDENTIFIER]: string;\n [VOTE_INDEX]: number;\n}\n\nexport type VoteRef = Ref<VoteLogItem[]>;\n\nlet voteStorage: VoteRef | null = null;\n\nexport const useVoteStorage = (): VoteRef =>\n voteStorage || (voteStorage = useStorage<VoteLogItem[]>(VOTE_KEY, []));\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\nimport type { UserInfo } from '../api';\n\nexport const USER_KEY = 'WALINE_USER';\n\nexport type UserInfoRef = Ref<UserInfo | Record<string, never>>;\n\nlet userInfoStorage: UserInfoRef | null = null;\n\nexport const useUserInfo = (): UserInfoRef =>\n userInfoStorage ||\n (userInfoStorage = useStorage<UserInfo | Record<string, never>>(\n USER_KEY,\n {}\n ));\n","<template>\n <div v-if=\"reaction.length\" class=\"wl-reaction\">\n <h4 v-text=\"locale.reactionTitle\" />\n <ul>\n <li\n v-for=\"(item, index) in reaction\"\n :key=\"index\"\n :class=\"{ active: item.active }\"\n @click=\"vote(index)\"\n >\n <div class=\"wl-reaction-img\">\n <img :src=\"item.icon\" :alt=\"item.desc\" />\n <div class=\"wl-reaction-votes\">{{ item.vote }}</div>\n </div>\n <div class=\"wl-reaction-text\">{{ item.desc }}</div>\n </li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n defineComponent,\n inject,\n ComputedRef,\n computed,\n onMounted,\n onUnmounted,\n ref,\n} from 'vue';\nimport { fetchArticleCounter, updateArticleCounter } from '../api';\nimport { VOTE_IDENTIFIER, VOTE_INDEX, useVoteStorage } from '../composables';\nimport type { WalineConfig } from '../utils';\nimport type { WalineLocale } from '../typings';\n\ninterface ReactionItem {\n icon: string;\n vote: number;\n desc: string;\n active?: boolean;\n}\n\nexport default defineComponent({\n setup() {\n const votes = ref<ReactionItem['vote'][]>([]);\n const voteStorage = useVoteStorage();\n const config = inject<ComputedRef<WalineConfig>>('config')!;\n const locale = computed(() => config.value.locale);\n const reaction = computed((): ReactionItem[] => {\n const { reaction, path } = config.value;\n\n return reaction.map((icon, index) => ({\n icon,\n vote: votes.value[index] || 0,\n desc: locale.value[`reaction${index}` as keyof WalineLocale],\n active: Boolean(\n voteStorage.value.find(\n ({ [VOTE_IDENTIFIER]: voteIdentifier, [VOTE_INDEX]: voteIndex }) =>\n voteIdentifier === path && voteIndex === index\n )\n ),\n }));\n });\n\n let abort: () => void;\n\n const fetchCounter = (): void => {\n const { serverURL, lang, path, reaction } = config.value;\n\n if (reaction.length) {\n const controller = new AbortController();\n\n fetchArticleCounter({\n serverURL,\n lang,\n paths: [path],\n type: reaction.map((_, k) => `reaction${k}`),\n signal: controller.signal,\n }).then((resp) => {\n if (Array.isArray(resp) || typeof resp === 'number') return;\n votes.value = reaction.map((_, k) => resp[`reaction${k}`]);\n });\n\n abort = controller.abort.bind(controller);\n }\n };\n\n const vote = async (index: number): Promise<void> => {\n const { serverURL, lang, path } = config.value;\n const hasVoted = voteStorage.value.find(\n ({ [VOTE_IDENTIFIER]: voteIdentifier }) => voteIdentifier === path\n );\n const hasVotedTheReaction = hasVoted && hasVoted[VOTE_INDEX] === index;\n\n if (hasVotedTheReaction) return;\n\n await updateArticleCounter({\n serverURL,\n lang,\n path,\n type: `reaction${index}`,\n });\n\n votes.value[index] = (votes.value[index] || 0) + 1;\n if (hasVoted) {\n votes.value[hasVoted[VOTE_INDEX]] = Math.max(\n votes.value[hasVoted[VOTE_INDEX]] - 1,\n 0\n );\n updateArticleCounter({\n serverURL,\n lang,\n path,\n type: `reaction${hasVoted.i}`,\n action: 'desc',\n });\n\n hasVoted.i = index;\n voteStorage.value = Array.from(voteStorage.value);\n } else {\n voteStorage.value = [\n ...voteStorage.value,\n { [VOTE_IDENTIFIER]: path, [VOTE_INDEX]: index },\n ];\n }\n\n if (voteStorage.value.length > 50)\n voteStorage.value = voteStorage.value.slice(-50);\n };\n\n onMounted(() => fetchCounter());\n onUnmounted(() => abort?.());\n\n return {\n reaction,\n locale,\n vote,\n };\n },\n});\n</script>\n","import { h } from 'vue';\nimport type { FunctionalComponent } from 'vue';\n\nexport const CloseIcon: FunctionalComponent<{ size: number }> = ({ size }) =>\n h(\n 'svg',\n {\n class: 'wl-close-icon',\n viewBox: '0 0 1024 1024',\n width: size,\n height: size,\n },\n [\n h('path', {\n d: 'M697.173 85.333h-369.92c-144.64 0-241.92 101.547-241.92 252.587v348.587c0 150.613 97.28 252.16 241.92 252.16h369.92c144.64 0 241.494-101.547 241.494-252.16V337.92c0-151.04-96.854-252.587-241.494-252.587z',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'm640.683 587.52-75.947-75.861 75.904-75.862a37.29 37.29 0 0 0 0-52.778 37.205 37.205 0 0 0-52.779 0l-75.946 75.818-75.862-75.946a37.419 37.419 0 0 0-52.821 0 37.419 37.419 0 0 0 0 52.821l75.947 75.947-75.776 75.733a37.29 37.29 0 1 0 52.778 52.821l75.776-75.776 75.947 75.947a37.376 37.376 0 0 0 52.779-52.821z',\n fill: '#888',\n }),\n ]\n );\n\nexport const DeleteIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'm341.013 394.667 27.755 393.45h271.83l27.733-393.45h64.106l-28.01 397.952a64 64 0 0 1-63.83 59.498H368.768a64 64 0 0 1-63.83-59.52l-28.053-397.93h64.128zm139.307 19.818v298.667h-64V414.485h64zm117.013 0v298.667h-64V414.485h64zM181.333 288h640v64h-640v-64zm453.483-106.667v64h-256v-64h256z',\n fill: 'red',\n })\n );\n\nexport const EmojiIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M563.2 463.3 677 540c1.7 1.2 3.7 1.8 5.8 1.8.7 0 1.4-.1 2-.2 2.7-.5 5.1-2.1 6.6-4.4l25.3-37.8c1.5-2.3 2.1-5.1 1.6-7.8s-2.1-5.1-4.4-6.6l-73.6-49.1 73.6-49.1c2.3-1.5 3.9-3.9 4.4-6.6.5-2.7 0-5.5-1.6-7.8l-25.3-37.8a10.1 10.1 0 0 0-6.6-4.4c-.7-.1-1.3-.2-2-.2-2.1 0-4.1.6-5.8 1.8l-113.8 76.6c-9.2 6.2-14.7 16.4-14.7 27.5.1 11 5.5 21.3 14.7 27.4zM387 348.8h-45.5c-5.7 0-10.4 4.7-10.4 10.4v153.3c0 5.7 4.7 10.4 10.4 10.4H387c5.7 0 10.4-4.7 10.4-10.4V359.2c0-5.7-4.7-10.4-10.4-10.4zm333.8 241.3-41-20a10.3 10.3 0 0 0-8.1-.5c-2.6.9-4.8 2.9-5.9 5.4-30.1 64.9-93.1 109.1-164.4 115.2-5.7.5-9.9 5.5-9.5 11.2l3.9 45.5c.5 5.3 5 9.5 10.3 9.5h.9c94.8-8 178.5-66.5 218.6-152.7 2.4-5 .3-11.2-4.8-13.6zm186-186.1c-11.9-42-30.5-81.4-55.2-117.1-24.1-34.9-53.5-65.6-87.5-91.2-33.9-25.6-71.5-45.5-111.6-59.2-41.2-14-84.1-21.1-127.8-21.1h-1.2c-75.4 0-148.8 21.4-212.5 61.7-63.7 40.3-114.3 97.6-146.5 165.8-32.2 68.1-44.3 143.6-35.1 218.4 9.3 74.8 39.4 145 87.3 203.3.1.2.3.3.4.5l36.2 38.4c1.1 1.2 2.5 2.1 3.9 2.6 73.3 66.7 168.2 103.5 267.5 103.5 73.3 0 145.2-20.3 207.7-58.7 37.3-22.9 70.3-51.5 98.1-85 27.1-32.7 48.7-69.5 64.2-109.1 15.5-39.7 24.4-81.3 26.6-123.8 2.4-43.6-2.5-87-14.5-129zm-60.5 181.1c-8.3 37-22.8 72-43 104-19.7 31.1-44.3 58.6-73.1 81.7-28.8 23.1-61 41-95.7 53.4-35.6 12.7-72.9 19.1-110.9 19.1-82.6 0-161.7-30.6-222.8-86.2l-34.1-35.8c-23.9-29.3-42.4-62.2-55.1-97.7-12.4-34.7-18.8-71-19.2-107.9-.4-36.9 5.4-73.3 17.1-108.2 12-35.8 30-69.2 53.4-99.1 31.7-40.4 71.1-72 117.2-94.1 44.5-21.3 94-32.6 143.4-32.6 49.3 0 97 10.8 141.8 32 34.3 16.3 65.3 38.1 92 64.8 26.1 26 47.5 56 63.6 89.2 16.2 33.2 26.6 68.5 31 105.1 4.6 37.5 2.7 75.3-5.6 112.3z',\n fill: 'currentColor',\n })\n );\n\nexport const ImageIcon: FunctionalComponent = () =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: 'M784 112H240c-88 0-160 72-160 160v480c0 88 72 160 160 160h544c88 0 160-72 160-160V272c0-88-72-160-160-160zm96 640c0 52.8-43.2 96-96 96H240c-52.8 0-96-43.2-96-96V272c0-52.8 43.2-96 96-96h544c52.8 0 96 43.2 96 96v480z',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'M352 480c52.8 0 96-43.2 96-96s-43.2-96-96-96-96 43.2-96 96 43.2 96 96 96zm0-128c17.6 0 32 14.4 32 32s-14.4 32-32 32-32-14.4-32-32 14.4-32 32-32zm462.4 379.2-3.2-3.2-177.6-177.6c-25.6-25.6-65.6-25.6-91.2 0l-80 80-36.8-36.8c-25.6-25.6-65.6-25.6-91.2 0L200 728c-4.8 6.4-8 14.4-8 24 0 17.6 14.4 32 32 32 9.6 0 16-3.2 22.4-9.6L380.8 640l134.4 134.4c6.4 6.4 14.4 9.6 24 9.6 17.6 0 32-14.4 32-32 0-9.6-4.8-17.6-9.6-24l-52.8-52.8 80-80L769.6 776c6.4 4.8 12.8 8 20.8 8 17.6 0 32-14.4 32-32 0-8-3.2-16-8-20.8z',\n fill: 'currentColor',\n }),\n ]);\n\nexport const LikeIcon: FunctionalComponent<{ active: boolean }> = ({\n active = false,\n}: {\n active?: boolean;\n}) =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: `M850.654 323.804c-11.042-25.625-26.862-48.532-46.885-68.225-20.022-19.61-43.258-34.936-69.213-45.73-26.78-11.124-55.124-16.727-84.375-16.727-40.622 0-80.256 11.123-114.698 32.135A214.79 214.79 0 0 0 512 241.819a214.79 214.79 0 0 0-23.483-16.562c-34.442-21.012-74.076-32.135-114.698-32.135-29.25 0-57.595 5.603-84.375 16.727-25.872 10.711-49.19 26.12-69.213 45.73-20.105 19.693-35.843 42.6-46.885 68.225-11.453 26.615-17.303 54.877-17.303 83.963 0 27.439 5.603 56.03 16.727 85.117 9.31 24.307 22.659 49.52 39.715 74.981 27.027 40.293 64.188 82.316 110.33 124.915 76.465 70.615 152.189 119.394 155.402 121.371l19.528 12.525c8.652 5.52 19.776 5.52 28.427 0l19.529-12.525c3.213-2.06 78.854-50.756 155.401-121.371 46.143-42.6 83.304-84.622 110.33-124.915 17.057-25.46 30.487-50.674 39.716-74.981 11.124-29.087 16.727-57.678 16.727-85.117.082-29.086-5.768-57.348-17.221-83.963z${\n active\n ? ''\n : 'M512 761.5S218.665 573.55 218.665 407.767c0-83.963 69.461-152.023 155.154-152.023 60.233 0 112.473 33.618 138.181 82.727 25.708-49.109 77.948-82.727 138.18-82.727 85.694 0 155.155 68.06 155.155 152.023C805.335 573.551 512 761.5 512 761.5z'\n }`,\n fill: active ? 'red' : 'currentColor',\n }),\n ]);\n\nexport const PreviewIcon: FunctionalComponent = () =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: 'M710.816 654.301c70.323-96.639 61.084-230.578-23.705-314.843-46.098-46.098-107.183-71.109-172.28-71.109-65.008 0-126.092 25.444-172.28 71.109-45.227 46.098-70.756 107.183-70.756 172.106 0 64.923 25.444 126.007 71.194 172.106 46.099 46.098 107.184 71.109 172.28 71.109 51.414 0 100.648-16.212 142.824-47.404l126.53 126.006c7.058 7.06 16.297 10.979 26.406 10.979 10.105 0 19.343-3.919 26.402-10.979 14.467-14.467 14.467-38.172 0-52.723L710.816 654.301zm-315.107-23.265c-65.88-65.88-65.88-172.54 0-238.42 32.069-32.07 74.245-49.149 119.471-49.149 45.227 0 87.407 17.603 119.472 49.149 65.88 65.879 65.88 172.539 0 238.42-63.612 63.178-175.242 63.178-238.943 0zm0 0',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'M703.319 121.603H321.03c-109.8 0-199.469 89.146-199.469 199.38v382.034c0 109.796 89.236 199.38 199.469 199.38h207.397c20.653 0 37.384-16.645 37.384-37.299 0-20.649-16.731-37.296-37.384-37.296H321.03c-68.582 0-124.352-55.77-124.352-124.267V321.421c0-68.496 55.77-124.267 124.352-124.267h382.289c68.582 0 124.352 55.771 124.352 124.267V524.72c0 20.654 16.736 37.299 37.385 37.299 20.654 0 37.384-16.645 37.384-37.299V320.549c-.085-109.8-89.321-198.946-199.121-198.946zm0 0',\n fill: 'currentColor',\n }),\n ]);\n\nexport const MarkdownIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { width: '16', height: '16', ariaHidden: 'true' },\n h('path', {\n d: 'M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z',\n fill: 'currentColor',\n })\n );\n\nexport const ReplyIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M810.667 213.333a64 64 0 0 1 64 64V704a64 64 0 0 1-64 64H478.336l-146.645 96.107a21.333 21.333 0 0 1-33.024-17.856V768h-85.334a64 64 0 0 1-64-64V277.333a64 64 0 0 1 64-64h597.334zm0 64H213.333V704h149.334v63.296L459.243 704h351.424V277.333zm-271.36 213.334v64h-176.64v-64h176.64zm122.026-128v64H362.667v-64h298.666z',\n fill: 'currentColor',\n })\n );\n\nexport const EditIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M813.039 318.772L480.53 651.278H360.718V531.463L693.227 198.961C697.904 194.284 704.027 192 710.157 192C716.302 192 722.436 194.284 727.114 198.961L813.039 284.88C817.72 289.561 820 295.684 820 301.825C820 307.95 817.72 314.093 813.039 318.772ZM710.172 261.888L420.624 551.431V591.376H460.561L750.109 301.825L710.172 261.888ZM490.517 291.845H240.906V771.09H720.156V521.479C720.156 504.947 733.559 491.529 750.109 491.529C766.653 491.529 780.063 504.947 780.063 521.479V791.059C780.063 813.118 762.18 831 740.125 831H220.937C198.882 831 181 813.118 181 791.059V271.872C181 249.817 198.882 231.935 220.937 231.935H490.517C507.06 231.935 520.47 245.352 520.47 261.888C520.47 278.424 507.06 291.845 490.517 291.845Z',\n fill: 'currentColor',\n })\n );\n\nexport const VerifiedIcon: FunctionalComponent = () =>\n h(\n 'svg',\n {\n class: 'verified-icon',\n viewBox: '0 0 1024 1024',\n width: '14',\n height: '14',\n },\n h('path', {\n d: 'm894.4 461.56-54.4-63.2c-10.4-12-18.8-34.4-18.8-50.4v-68c0-42.4-34.8-77.2-77.2-77.2h-68c-15.6 0-38.4-8.4-50.4-18.8l-63.2-54.4c-27.6-23.6-72.8-23.6-100.8 0l-62.8 54.8c-12 10-34.8 18.4-50.4 18.4h-69.2c-42.4 0-77.2 34.8-77.2 77.2v68.4c0 15.6-8.4 38-18.4 50l-54 63.6c-23.2 27.6-23.2 72.4 0 100l54 63.6c10 12 18.4 34.4 18.4 50v68.4c0 42.4 34.8 77.2 77.2 77.2h69.2c15.6 0 38.4 8.4 50.4 18.8l63.2 54.4c27.6 23.6 72.8 23.6 100.8 0l63.2-54.4c12-10.4 34.4-18.8 50.4-18.8h68c42.4 0 77.2-34.8 77.2-77.2v-68c0-15.6 8.4-38.4 18.8-50.4l54.4-63.2c23.2-27.6 23.2-73.2-.4-100.8zm-216-25.2-193.2 193.2a30 30 0 0 1-42.4 0l-96.8-96.8a30.16 30.16 0 0 1 0-42.4c11.6-11.6 30.8-11.6 42.4 0l75.6 75.6 172-172c11.6-11.6 30.8-11.6 42.4 0 11.6 11.6 11.6 30.8 0 42.4z',\n fill: '#27ae60',\n })\n );\n\nexport const LoadingIcon: FunctionalComponent<{ size: number }> = ({ size }) =>\n h(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 100 100',\n preserveAspectRatio: 'xMidYMid',\n },\n h(\n 'circle',\n {\n cx: 50,\n cy: 50,\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: '4',\n r: '40',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'stroke-dasharray': '85 30',\n },\n h('animateTransform', {\n attributeName: 'transform',\n type: 'rotate',\n repeatCount: 'indefinite',\n dur: '1s',\n values: '0 50 50;360 50 50',\n keyTimes: '0;1',\n })\n )\n );\n\nexport const GifIcon: FunctionalComponent = () =>\n h(\n 'svg',\n {\n width: 24,\n height: 24,\n fill: 'currentcolor',\n viewBox: '0 0 24 24',\n },\n [\n h('path', {\n style: 'transform: translateY(0.5px)',\n d: 'M18.968 10.5H15.968V11.484H17.984V12.984H15.968V15H14.468V9H18.968V10.5V10.5ZM8.984 9C9.26533 9 9.49967 9.09367 9.687 9.281C9.87433 9.46833 9.968 9.70267 9.968 9.984V10.5H6.499V13.5H8.468V12H9.968V14.016C9.968 14.2973 9.87433 14.5317 9.687 14.719C9.49967 14.9063 9.26533 15 8.984 15H5.984C5.70267 15 5.46833 14.9063 5.281 14.719C5.09367 14.5317 5 14.2973 5 14.016V9.985C5 9.70367 5.09367 9.46933 5.281 9.282C5.46833 9.09467 5.70267 9.001 5.984 9.001H8.984V9ZM11.468 9H12.968V15H11.468V9V9Z',\n }),\n h('path', {\n d: 'M18.5 3H5.75C3.6875 3 2 4.6875 2 6.75V18C2 20.0625 3.6875 21.75 5.75 21.75H18.5C20.5625 21.75 22.25 20.0625 22.25 18V6.75C22.25 4.6875 20.5625 3 18.5 3ZM20.75 18C20.75 19.2375 19.7375 20.25 18.5 20.25H5.75C4.5125 20.25 3.5 19.2375 3.5 18V6.75C3.5 5.5125 4.5125 4.5 5.75 4.5H18.5C19.7375 4.5 20.75 5.5125 20.75 6.75V18Z',\n }),\n ]\n );\n","<!-- forked from https://github.com/DerYeger/vue-masonry-wall/blob/master/src/masonry-wall.vue -->\n\n<!-- MIT License\n\nCopyright (c) 2021 Fuxing Loh, Jan Müller\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE. -->\n\n<template>\n <div ref=\"wall\" class=\"wl-gallery\" :style=\"{ gap: `${gap}px` }\">\n <div\n v-for=\"(column, columnIndex) in columns\"\n :key=\"columnIndex\"\n class=\"wl-gallery-column\"\n :data-index=\"columnIndex\"\n :style=\"{ gap: `${gap}px` }\"\n >\n <template v-for=\"itemIndex in column\" :key=\"itemIndex\">\n <LoadingIcon\n v-if=\"!state[items[itemIndex].src]\"\n :size=\"36\"\n style=\"margin: 20px auto\"\n />\n <img\n class=\"wl-gallery-item\"\n :src=\"items[itemIndex].src\"\n :title=\"items[itemIndex].title\"\n loading=\"lazy\"\n @load=\"imageLoad\"\n @click=\"$emit('insert', `![](${items[itemIndex].src})`)\"\n />\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n defineComponent,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n watch,\n} from 'vue';\n\nimport { LoadingIcon } from './Icons';\n\nimport type { PropType } from 'vue';\nimport type { WalineSearchResult } from '../typings';\n\ntype Column = number[];\n\nexport default defineComponent({\n name: 'ImageWall',\n\n components: {\n LoadingIcon,\n },\n\n props: {\n items: { type: Array as PropType<WalineSearchResult>, default: () => [] },\n columnWidth: { type: Number, default: 300 },\n gap: { type: Number, default: 0 },\n },\n\n emits: ['insert'],\n\n setup(props) {\n let resizeObserver: ResizeObserver | null = null;\n const wall = ref<HTMLDivElement | null>(null);\n const state = ref<Record<string, boolean>>({});\n const columns = ref<Column[]>([]);\n\n const getColumnCount = (): number => {\n const count = Math.floor(\n (wall.value!.getBoundingClientRect().width + props.gap) /\n (props.columnWidth + props.gap)\n );\n\n return count > 0 ? count : 1;\n };\n\n const createColumns = (count: number): Column[] =>\n new Array(count).fill(null).map(() => []);\n\n const fillColumns = async (itemIndex: number): Promise<void> => {\n if (itemIndex >= props.items.length) return;\n\n await nextTick();\n\n const columnDivs = Array.from(\n wall.value?.children || []\n ) as HTMLDivElement[];\n\n const target = columnDivs.reduce((prev, curr) =>\n curr.getBoundingClientRect().height <\n prev.getBoundingClientRect().height\n ? curr\n : prev\n );\n\n columns.value[Number(target.dataset.index)].push(itemIndex);\n\n await fillColumns(itemIndex + 1);\n };\n\n const redraw = async (force = false): Promise<void> => {\n if (columns.value.length === getColumnCount() && !force) return;\n\n columns.value = createColumns(getColumnCount());\n\n const scrollY = window.scrollY;\n\n await fillColumns(0);\n\n window.scrollTo({ top: scrollY });\n };\n\n const imageLoad = (e: Event) => {\n state.value[(e.target as HTMLImageElement).src] = true;\n };\n\n watch(\n () => [props.items],\n () => {\n state.value = {};\n redraw(true);\n }\n );\n watch(\n () => [props.columnWidth, props.gap],\n () => redraw()\n );\n\n onMounted(() => {\n redraw(true);\n resizeObserver = new ResizeObserver(() => redraw());\n\n resizeObserver.observe(wall.value!);\n });\n\n onBeforeUnmount(() => resizeObserver!.unobserve(wall.value!));\n\n return {\n columns,\n state,\n wall,\n imageLoad,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-comment\">\n <div\n v-if=\"config.login !== 'disable' && isLogin && !edit?.objectId\"\n class=\"wl-login-info\"\n >\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"Profile\"\n :title=\"locale.profile\"\n @click=\"onProfile\"\n >\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </a>\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"Profile\"\n :title=\"locale.profile\"\n @click=\"onProfile\"\n v-text=\"userInfo.display_name\"\n />\n </div>\n\n <div class=\"wl-panel\">\n <div\n v-if=\"config.login !== 'force' && config.meta.length && !isLogin\"\n :class=\"['wl-header', `item${config.meta.length}`]\"\n >\n <div v-for=\"kind in config.meta\" :key=\"kind\" class=\"wl-header-item\">\n <label\n :for=\"kind\"\n v-text=\"\n locale[kind] +\n (config.requiredMeta.includes(kind) || !config.requiredMeta.length\n ? ''\n : `(${locale.optional})`)\n \"\n />\n <input\n :id=\"`wl-${kind}`\"\n :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element as HTMLInputElement;\n }\n \"\n v-model=\"userMeta[kind]\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n />\n </div>\n </div>\n\n <textarea\n id=\"wl-edit\"\n ref=\"editorRef\"\n v-model=\"editor\"\n class=\"wl-editor\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div v-show=\"showPreview\" class=\"wl-preview\">\n <hr />\n <h4>{{ locale.preview }}:</h4>\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div class=\"wl-content\" v-html=\"previewText\" />\n </div>\n\n <div class=\"wl-footer\">\n <div class=\"wl-actions\">\n <a\n href=\"https://guides.github.com/features/mastering-markdown/\"\n title=\"Markdown Guide\"\n aria-label=\"Markdown is supported\"\n class=\"wl-action\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <MarkdownIcon />\n </a>\n\n <button\n v-show=\"emoji.tabs.length\"\n ref=\"emojiButtonRef\"\n class=\"wl-action\"\n :class=\"{ actived: showEmoji }\"\n :title=\"locale.emoji\"\n @click=\"showEmoji = !showEmoji\"\n >\n <EmojiIcon />\n </button>\n\n <button\n v-if=\"config.search\"\n ref=\"gifButtonRef\"\n class=\"wl-action\"\n :class=\"{ actived: showGif }\"\n :title=\"locale.gif\"\n @click=\"showGif = !showGif\"\n >\n <GifIcon />\n </button>\n\n <input\n id=\"wl-image-upload\"\n ref=\"imageUploadRef\"\n class=\"upload\"\n type=\"file\"\n accept=\".png,.jpg,.jpeg,.webp,.bmp,.gif\"\n @change=\"onChange\"\n />\n\n <label\n v-if=\"canUploadImage\"\n for=\"wl-image-upload\"\n class=\"wl-action\"\n :title=\"locale.uploadImage\"\n >\n <ImageIcon />\n </label>\n\n <button\n class=\"wl-action\"\n :class=\"{ actived: showPreview }\"\n :title=\"locale.preview\"\n @click=\"showPreview = !showPreview\"\n >\n <PreviewIcon />\n </button>\n </div>\n\n <div class=\"wl-info\">\n <div class=\"wl-text-number\">\n {{ wordNumber }}\n\n <span v-if=\"config.wordLimit\">\n &nbsp;/&nbsp;\n <span\n :class=\"{ illegal: !isWordNumberLegal }\"\n v-text=\"wordLimit\"\n />\n </span>\n\n &nbsp;{{ locale.word }}\n </div>\n\n <button\n v-if=\"config.login !== 'disable' && !isLogin\"\n class=\"wl-btn\"\n @click=\"onLogin\"\n v-text=\"locale.login\"\n />\n\n <button\n v-if=\"config.login !== 'force' || isLogin\"\n class=\"wl-btn primary\"\n title=\"Cmd|Ctrl + Enter\"\n :disabled=\"isSubmitting\"\n @click=\"submitComment\"\n >\n <LoadingIcon v-if=\"isSubmitting\" :size=\"16\" />\n <template v-else>\n {{ locale.submit }}\n </template>\n </button>\n </div>\n\n <div\n ref=\"gifPopupRef\"\n class=\"wl-gif-popup\"\n :class=\"{ display: showGif }\"\n >\n <input\n ref=\"gifSearchInputRef\"\n type=\"text\"\n :placeholder=\"locale.gifSearchPlaceholder\"\n @input=\"onGifSearch\"\n />\n\n <ImageWall\n :items=\"gifData.list\"\n :column-width=\"200\"\n :gap=\"6\"\n @insert=\"insert($event)\"\n @scroll=\"onImageWallScroll\"\n >\n </ImageWall>\n\n <div v-if=\"gifData.loading\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n </div>\n <div\n ref=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template\n v-for=\"(emojiItem, index) in emoji.tabs\"\n :key=\"emojiItem.name\"\n >\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in emojiItem.items\"\n :key=\"key\"\n :title=\"key\"\n @click=\"insert(`:${key}:`)\"\n >\n <img\n v-if=\"showEmoji\"\n class=\"wl-emoji\"\n :src=\"emoji.map[key]\"\n :alt=\"key\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n />\n </button>\n </div>\n </template>\n <div v-if=\"emoji.tabs.length > 1\" class=\"wl-tabs\">\n <button\n v-for=\"(emojiItem, index) in emoji.tabs\"\n :key=\"emojiItem.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"emojiItem.icon\"\n :alt=\"emojiItem.name\"\n :title=\"emojiItem.name\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n />\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <button\n v-if=\"replyId || edit?.objectId\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit(replyId ? 'cancel-reply' : 'cancel-edit')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { useDebounceFn } from '@vueuse/core';\nimport { useReCaptcha } from '../composables';\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n PropType,\n reactive,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n GifIcon,\n} from './Icons';\nimport ImageWall from './ImageWall.vue';\nimport { login, postComment } from '../api';\nimport { useEditor, useUserMeta, useUserInfo } from '../composables';\nimport {\n getEmojis,\n getImagefromDataTransfer,\n getWordNumber,\n parseEmoji,\n parseMarkdown,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type {\n WalineComment,\n WalineCommentData,\n WalineImageUploader,\n WalineSearchOptions,\n WalineSearchResult,\n} from '../typings';\nimport type { WalineConfig, WalineEmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n ImageWall,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n GifIcon,\n },\n\n props: {\n rootId: {\n type: String,\n default: '',\n },\n replyId: {\n type: String,\n default: '',\n },\n replyUser: {\n type: String,\n default: '',\n },\n edit: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n },\n\n emits: ['submit', 'cancel-reply', 'cancel-edit'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<WalineConfig>>('config')!;\n\n const editor = useEditor();\n const userMeta = useUserMeta();\n const userInfo = useUserInfo();\n\n const inputRefs = ref<Record<string, HTMLInputElement>>({});\n const editorRef = ref<HTMLTextAreaElement | null>(null);\n const imageUploadRef = ref<HTMLInputElement | null>(null);\n const emojiButtonRef = ref<HTMLDivElement | null>(null);\n const emojiPopupRef = ref<HTMLDivElement | null>(null);\n const gifButtonRef = ref<HTMLDivElement | null>(null);\n const gifPopupRef = ref<HTMLDivElement | null>(null);\n const gifSearchInputRef = ref<HTMLInputElement | null>(null);\n\n const emoji = ref<DeepReadonly<WalineEmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showGif = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\n\n const searchResults = reactive({\n loading: true,\n list: [] as WalineSearchResult,\n });\n\n const wordLimit = ref(0);\n const isWordNumberLegal = ref(false);\n\n const content = ref('');\n\n const isSubmitting = ref(false);\n\n const locale = computed(() => config.value.locale);\n\n const isLogin = computed(() => Boolean(userInfo.value?.token));\n\n const canUploadImage = computed(() => config.value.imageUploader !== false);\n\n const insert = (content: string): void => {\n const textArea = editorRef.value!;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n editor.value =\n textArea.value.substring(0, startPosition) +\n content +\n textArea.value.substring(endPosition, textArea.value.length);\n textArea.focus();\n textArea.selectionStart = startPosition + content.length;\n textArea.selectionEnd = startPosition + content.length;\n textArea.scrollTop = scrollTop;\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const key = event.key;\n\n // Shortcut key\n if ((event.ctrlKey || event.metaKey) && key === 'Enter') submitComment();\n };\n\n const uploadImage = (file: File): Promise<void> => {\n const uploadText = `![${config.value.locale.uploading} ${file.name}]()`;\n\n insert(uploadText);\n\n return Promise.resolve()\n .then(() => (config.value.imageUploader as WalineImageUploader)(file))\n .then((url) => {\n editor.value = editor.value.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\n })\n .catch((e) => {\n alert(e.message);\n editor.value = editor.value.replace(uploadText, '');\n });\n };\n\n const onDrop = (event: DragEvent): void => {\n if (event.dataTransfer?.items) {\n const file = getImagefromDataTransfer(event.dataTransfer.items);\n\n if (file && canUploadImage.value) {\n uploadImage(file);\n event.preventDefault();\n }\n }\n };\n\n const onPaste = (event: ClipboardEvent): void => {\n if (event.clipboardData) {\n const file = getImagefromDataTransfer(event.clipboardData.items);\n\n if (file && canUploadImage.value) uploadImage(file);\n }\n };\n\n const onChange = (): void => {\n const inputElement = imageUploadRef.value!;\n\n if (inputElement.files && canUploadImage.value)\n uploadImage(inputElement.files[0]).then(() => {\n // clear input so a same image can be uploaded later\n inputElement.value = '';\n });\n };\n\n const submitComment = async (): Promise<void> => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n let token = '';\n\n if (config.value.recaptchaV3Key)\n token = await useReCaptcha(config.value.recaptchaV3Key).execute(\n 'social'\n );\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: userMeta.value.nick,\n mail: userMeta.value.mail,\n link: userMeta.value.link,\n ua: navigator.userAgent,\n url: config.value.path,\n recaptchaV3: token,\n };\n\n if (userInfo.value?.token) {\n // login user\n\n comment.nick = userInfo.value.display_name;\n comment.mail = userInfo.value.email;\n comment.link = userInfo.value.url;\n } else {\n if (login === 'force') return;\n\n // check nick\n if (requiredMeta.indexOf('nick') > -1 && !comment.nick) {\n inputRefs.value.nick?.focus();\n\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (\n (requiredMeta.indexOf('mail') > -1 && !comment.mail) ||\n (comment.mail &&\n !/^\\w(?:[\\w._-]*\\w)?@(?:\\w(?:[\\w-]*\\w)?\\.)*\\w+$/.exec(comment.mail))\n ) {\n inputRefs.value.mail?.focus();\n\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\n\n return;\n }\n\n if (!comment.nick) comment.nick = locale.value.anonymous;\n }\n\n if (!isWordNumberLegal.value)\n return alert(\n locale.value.wordHint\n .replace('$0', (wordLimit as [number, number])[0].toString())\n .replace('$1', (wordLimit as [number, number])[1].toString())\n .replace('$2', wordNumber.value.toString())\n );\n\n comment.comment = parseEmoji(comment.comment, emoji.value.map);\n\n if (props.replyId && props.rootId) {\n comment.pid = props.replyId;\n comment.rid = props.rootId;\n comment.at = props.replyUser;\n } else if (props.edit) {\n comment.eid = props.edit.objectId;\n }\n\n isSubmitting.value = true;\n\n postComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n comment,\n })\n .then((resp) => {\n isSubmitting.value = false;\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n emit('submit', resp.data!);\n\n editor.value = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\n if (props.edit?.objectId) emit('cancel-edit');\n })\n .catch((err: TypeError) => {\n isSubmitting.value = false;\n\n alert(err.message);\n });\n };\n\n const onLogin = (event: Event): void => {\n event.preventDefault();\n const { lang, serverURL } = config.value;\n\n login({\n serverURL,\n lang,\n }).then((data) => {\n userInfo.value = data;\n (data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data)\n );\n });\n };\n\n const onLogout = (): void => {\n userInfo.value = {};\n localStorage.setItem('WALINE_USER', 'null');\n sessionStorage.setItem('WALINE_USER', 'null');\n };\n\n const onProfile = (event: Event): void => {\n event.preventDefault();\n\n const { lang, serverURL } = config.value;\n\n const width = 800;\n const height = 800;\n const left = (window.innerWidth - width) / 2;\n const top = (window.innerHeight - height) / 2;\n const handler = window.open(\n `${serverURL}/ui/profile?lng=${encodeURIComponent(lang)}`,\n '_blank',\n `width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`\n );\n\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !emojiButtonRef.value!.contains(event.target as Node) &&\n !emojiPopupRef.value!.contains(event.target as Node)\n )\n showEmoji.value = false;\n\n if (\n !gifButtonRef.value!.contains(event.target as Node) &&\n !gifPopupRef.value!.contains(event.target as Node)\n )\n showGif.value = false;\n };\n\n const onImageWallScroll = async (event: Event): Promise<void> => {\n const { scrollTop, clientHeight, scrollHeight } =\n event.target as HTMLDivElement;\n const percent = (clientHeight + scrollTop) / scrollHeight;\n const searchOptions = config.value.search as WalineSearchOptions;\n const keyword = gifSearchInputRef.value?.value || '';\n\n if (percent < 0.9 || searchResults.loading) return;\n\n searchResults.loading = true;\n\n searchResults.list = [\n ...searchResults.list,\n ...(searchOptions.more && searchResults.list.length\n ? await searchOptions.more(keyword, searchResults.list.length)\n : await searchOptions.search(keyword)),\n ];\n\n searchResults.loading = false;\n\n setTimeout(() => {\n (event.target as HTMLDivElement).scrollTop = scrollTop;\n }, 50);\n };\n\n const onGifSearch = useDebounceFn((event: Event) => {\n searchResults.list = [];\n onImageWallScroll(event);\n }, 300);\n\n // update wordNumber\n watch(\n [config, wordNumber],\n ([config, wordNumber]) => {\n const { wordLimit: limit } = config;\n\n if (limit) {\n if (wordNumber < limit[0] && limit[0] !== 0) {\n wordLimit.value = limit[0];\n isWordNumberLegal.value = false;\n } else if (wordNumber > limit[1]) {\n wordLimit.value = limit[1];\n isWordNumberLegal.value = false;\n } else {\n wordLimit.value = limit[1];\n isWordNumberLegal.value = true;\n }\n } else {\n wordLimit.value = 0;\n isWordNumberLegal.value = true;\n }\n },\n { immediate: true }\n );\n\n watch(showGif, async (showGif) => {\n if (!showGif) return;\n\n const searchOptions = config.value.search as WalineSearchOptions;\n\n // clear input\n if (gifSearchInputRef.value) gifSearchInputRef.value.value = '';\n\n searchResults.loading = true;\n\n searchResults.list = searchOptions.default\n ? await searchOptions.default()\n : await searchOptions.search('');\n\n searchResults.loading = false;\n });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onMessageRecive = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n userInfo.value = { ...userInfo.value, ...data.data };\n\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n };\n\n onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n window.addEventListener('message', onMessageRecive);\n if (props.edit?.objectId) {\n editor.value = props.edit.orig;\n }\n\n // watch editor\n watch(\n () => editor.value,\n (value) => {\n const { highlighter, texRenderer } = config.value;\n\n content.value = value;\n previewText.value = parseMarkdown(value, {\n emojiMap: emoji.value.map,\n highlighter,\n texRenderer,\n });\n wordNumber.value = getWordNumber(value);\n\n if (value) autosize(editorRef.value!);\n else autosize.destroy(editorRef.value!);\n },\n { immediate: true }\n );\n\n // watch emoji value change\n watch(\n () => config.value.emoji,\n (emojiConfig) =>\n getEmojis(Array.isArray(emojiConfig) ? emojiConfig : []).then(\n (config) => {\n emoji.value = config;\n }\n ),\n { immediate: true }\n );\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\n window.removeEventListener('message', onMessageRecive);\n });\n\n return {\n // config\n config,\n locale,\n\n // events\n insert,\n onChange,\n onDrop,\n onKeyDown,\n onPaste,\n onLogin,\n onLogout,\n onProfile,\n submitComment,\n onImageWallScroll,\n onGifSearch,\n\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n editor,\n userMeta,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // gif\n gifData: searchResults,\n showGif,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n gifButtonRef,\n gifPopupRef,\n imageUploadRef,\n gifSearchInputRef,\n };\n },\n});\n</script>\n","import { useStorage } from '@vueuse/core';\nimport type { RemovableRef } from '@vueuse/core';\n\nexport interface UserMeta {\n nick: string;\n mail: string;\n link: string;\n}\n\nexport const useUserMeta = (): RemovableRef<UserMeta> =>\n useStorage<UserMeta>('WALINE_USER_META', {\n nick: '',\n mail: '',\n link: '',\n });\n\nexport const useEditor = (): RemovableRef<string> =>\n useStorage<string>('WALINE_COMMENT_BOX_EDITOR', '');\n","/**\n * The wordCount module should be lightweight as it's packed into client.\n *\n * So We just make a simple implement here\n *\n * Forked from https://github.com/vuepress-theme-hope/vuepress-theme-hope/blob/main/packages/reading-time2/src/node/reading-time.ts\n */\n\nexport const getWords = (content: string): string[] =>\n content.match(/[\\w\\d\\s\\u00C0-\\u024F]+/giu) || [];\n\nexport const getChinese = (content: string): string[] =>\n content.match(/[\\u4E00-\\u9FA5]/gu) || [];\n\nexport const getWordNumber = (content: string): number =>\n getWords(content).reduce(\n (accumulator, word) =>\n accumulator + (word.trim() === '' ? 0 : word.trim().split(/\\s+/u).length),\n 0\n ) + getChinese(content).length;\n","/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nexport interface LoginOptions {\n lang: string;\n serverURL: string;\n}\n\nexport interface UserInfo {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n display_name: string;\n email: string;\n url: string;\n token: string;\n avatar: string;\n mailMd5: string;\n objectId: string | number;\n type: 'administrator' | 'guest';\n}\n\nexport const login = ({\n lang,\n serverURL,\n}: LoginOptions): Promise<UserInfo & { remember: boolean }> => {\n const width = 450;\n const height = 450;\n const left = (window.innerWidth - width) / 2;\n const top = (window.innerHeight - height) / 2;\n\n const handler = window.open(\n `${serverURL}/ui/login?lng=${encodeURIComponent(lang)}`,\n '_blank',\n `width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`\n );\n\n handler?.postMessage({ type: 'TOKEN', data: null }, '*');\n\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || typeof data !== 'object' || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n\n window.removeEventListener('message', receiver);\n\n resolve(data.data as UserInfo & { remember: boolean });\n }\n };\n\n window.addEventListener('message', receiver);\n });\n};\n","<template>\n <div :id=\"comment.objectId\" class=\"wl-item\">\n <div class=\"wl-user\" aria-hidden=\"true\">\n <img v-if=\"comment.avatar\" :src=\"comment.avatar\" />\n <VerifiedIcon v-if=\"comment.type\" />\n </div>\n\n <div class=\"wl-card\">\n <div class=\"wl-head\">\n <a\n v-if=\"link\"\n class=\"wl-nick\"\n :href=\"link\"\n target=\"_blank\"\n rel=\"nofollow noreferrer\"\n >{{ comment.nick }}</a\n >\n <span v-else class=\"wl-nick\">{{ comment.nick }}</span>\n\n <span\n v-if=\"comment.type === 'administrator'\"\n class=\"wl-badge\"\n v-text=\"locale.admin\"\n />\n <span v-if=\"comment.label\" class=\"wl-badge\" v-text=\"comment.label\" />\n <span v-if=\"comment.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n <span\n v-if=\"comment.level !== undefined && comment.level >= 0\"\n :class=\"`wl-badge level${comment.level}`\"\n v-text=\"locale[`level${comment.level}`] || `Level ${comment.level}`\"\n />\n <span class=\"wl-time\" v-text=\"time\" />\n\n <div class=\"wl-comment-actions\">\n <button\n v-if=\"isAdmin || isOwner\"\n class=\"wl-edit\"\n @click=\"$emit('edit', comment)\"\n >\n <EditIcon />\n </button>\n\n <button\n v-if=\"isAdmin || isOwner\"\n class=\"wl-delete\"\n @click=\"$emit('delete', comment)\"\n >\n <DeleteIcon />\n </button>\n\n <button\n class=\"wl-like\"\n :title=\"like ? locale.cancelLike : locale.like\"\n @click=\"$emit('like', comment)\"\n >\n <LikeIcon :active=\"like\" />\n <span v-if=\"'like' in comment\" v-text=\"comment.like\" />\n </button>\n\n <button\n class=\"wl-reply\"\n :class=\"{ active: isReplyingCurrent }\"\n :title=\"isReplyingCurrent ? locale.cancelReply : locale.reply\"\n @click=\"$emit('reply', isReplyingCurrent ? null : comment)\"\n >\n <ReplyIcon />\n </button>\n </div>\n </div>\n <div class=\"wl-meta\" aria-hidden=\"true\">\n <span\n v-if=\"comment.addr\"\n class=\"wl-addr\"\n :data-value=\"comment.addr\"\n v-text=\"comment.addr\"\n />\n <span\n v-if=\"comment.browser\"\n class=\"wl-browser\"\n :data-value=\"comment.browser\"\n v-text=\"comment.browser\"\n />\n <span\n v-if=\"comment.os\"\n class=\"wl-os\"\n :data-value=\"comment.os\"\n v-text=\"comment.os\"\n />\n </div>\n <!-- eslint-disable vue/no-v-html -->\n <div\n v-if=\"!isEditingCurrent\"\n class=\"wl-content\"\n v-html=\"comment.comment\"\n />\n <!-- eslint-enable vue/no-v-html -->\n\n <div v-if=\"isAdmin && !isEditingCurrent\" class=\"wl-admin-actions\">\n <span class=\"wl-comment-status\">\n <button\n v-for=\"status in commentStatus\"\n :key=\"status\"\n :class=\"`wl-btn wl-${status}`\"\n :disabled=\"comment.status === status\"\n @click=\"$emit('status', { status, comment })\"\n v-text=\"locale[status]\"\n />\n </span>\n\n <button\n v-if=\"isAdmin && !comment.rid\"\n class=\"wl-btn wl-sticky\"\n @click=\"$emit('sticky', comment)\"\n >\n {{ comment.sticky ? locale.unsticky : locale.sticky }}\n </button>\n </div>\n\n <div\n v-if=\"isReplyingCurrent || isEditingCurrent\"\n :class=\"{\n 'wl-reply-wrapper': isReplyingCurrent,\n 'wl-edit-wrapper': isEditingCurrent,\n }\"\n >\n <CommentBox\n :edit=\"edit\"\n :reply-id=\"reply?.objectId\"\n :reply-user=\"comment.nick\"\n :root-id=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', null)\"\n @cancel-edit=\"$emit('edit', null)\"\n />\n </div>\n <div v-if=\"comment.children\" class=\"wl-quote\">\n <CommentCard\n v-for=\"child in comment.children\"\n :key=\"child.objectId\"\n :comment=\"child\"\n :reply=\"reply\"\n :edit=\"edit\"\n :root-id=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $event)\"\n @like=\"$emit('like', $event)\"\n @edit=\"$emit('edit', $event)\"\n @delete=\"$emit('delete', $event)\"\n @status=\"$emit('status', $event)\"\n @sticky=\"$emit('sticky', $event)\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, inject } from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport {\n DeleteIcon,\n LikeIcon,\n ReplyIcon,\n EditIcon,\n VerifiedIcon,\n} from './Icons';\nimport { isLinkHttp } from '../utils';\nimport { useTimeAgo, useLikeStorage, useUserInfo } from '../composables';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { WalineConfig } from '../utils';\nimport type { WalineComment, WalineCommentStatus } from '../typings';\n\nconst commentStatus: WalineCommentStatus[] = ['approved', 'waiting', 'spam'];\n\nexport default defineComponent({\n components: {\n CommentBox,\n DeleteIcon,\n LikeIcon,\n ReplyIcon,\n EditIcon,\n VerifiedIcon,\n },\n\n props: {\n comment: {\n type: Object as PropType<WalineComment>,\n required: true,\n },\n rootId: {\n type: String,\n required: true,\n },\n reply: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n edit: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n },\n\n emits: ['submit', 'reply', 'like', 'delete', 'status', 'sticky', 'edit'],\n\n setup(props) {\n const config = inject<ComputedRef<WalineConfig>>(\n 'config'\n ) as ComputedRef<WalineConfig>;\n const likes = useLikeStorage();\n const userInfo = useUserInfo();\n\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n const { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const like = computed(() => likes.value.includes(props.comment.objectId));\n\n const time = useTimeAgo(props.comment.insertedAt, locale.value);\n\n const isAdmin = computed(() => userInfo.value.type === 'administrator');\n\n const isOwner = computed(\n () =>\n props.comment.user_id &&\n userInfo.value.objectId === props.comment.user_id\n );\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n const isEditingCurrent = computed(\n () => props.comment.objectId === props.edit?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n isEditingCurrent,\n link,\n like,\n time,\n\n isAdmin,\n isOwner,\n\n commentStatus,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <Reaction />\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-meta-head\">\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\n </div>\n <ul class=\"wl-sort\">\n <li\n v-for=\"item in sortByItems\"\n :key=\"item.key\"\n :class=\"[item.key === sortBy ? 'active' : '']\"\n @click=\"onSortByChange(item.key)\"\n >\n {{ i18n[item.name] }}\n </li>\n </ul>\n </div>\n\n <div class=\"wl-cards\">\n <CommentCard\n v-for=\"comment in data\"\n :key=\"comment.objectId\"\n :root-id=\"comment.objectId\"\n :comment=\"comment\"\n :reply=\"reply\"\n :edit=\"edit\"\n @reply=\"onReply\"\n @edit=\"onEdit\"\n @submit=\"onSubmit\"\n @status=\"onStatusChange\"\n @delete=\"onDelete\"\n @sticky=\"onSticky\"\n @like=\"onLike\"\n />\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-operation\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"refresh\"\n v-text=\"i18n.refresh\"\n />\n </div>\n\n <template v-else>\n <div v-if=\"status === 'loading'\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n\n <div v-else-if=\"!data.length\" class=\"wl-empty\" v-text=\"i18n.sofa\" />\n\n <!-- Load more button -->\n <div v-else-if=\"page < totalPages\" class=\"wl-operation\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"loadMore\"\n v-text=\"i18n.more\"\n />\n </div>\n </template>\n\n <!-- Copyright Information -->\n <div v-if=\"config.copyright\" class=\"wl-power\">\n Powered by\n <a\n href=\"https://github.com/walinejs/waline\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Waline\n </a>\n v{{ version }}\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { useStyleTag } from '@vueuse/core';\nimport { computed, defineComponent, onMounted, provide, ref, watch } from 'vue';\nimport Reaction from './ArticleReaction.vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo, useLikeStorage } from '../composables';\nimport { defaultLocales } from '../config';\nimport {\n deleteComment,\n fetchComment,\n likeComment,\n updateComment,\n} from '../api';\nimport { getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineCommentStatus,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineSearchOptions,\n WalineLocale,\n WalineProps,\n WalineMeta,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nconst props = [\n 'serverURL',\n 'path',\n 'meta',\n 'requiredMeta',\n 'dark',\n 'lang',\n 'locale',\n 'pageSize',\n 'wordLimit',\n 'emoji',\n 'login',\n 'highlighter',\n 'texRenderer',\n 'imageUploader',\n 'search',\n 'copyright',\n 'recaptchaV3Key',\n 'reaction',\n];\n\ntype SortKeyItems = 'insertedAt_desc' | 'insertedAt_asc' | 'like_desc';\ntype SortNameItems = 'latest' | 'oldest' | 'hottest';\ntype SortByItems = { key: SortKeyItems; name: SortNameItems }[];\nconst sortByItems: SortByItems = [\n {\n key: 'insertedAt_desc',\n name: 'latest',\n },\n {\n key: 'insertedAt_asc',\n name: 'oldest',\n },\n {\n key: 'like_desc',\n name: 'hottest',\n },\n];\n\nconst propsWithValidate = {\n serverURL: {\n type: String,\n required: true,\n },\n\n path: {\n type: String,\n required: true,\n },\n\n meta: {\n type: Array as PropType<WalineMeta[]>,\n default: (): WalineMeta[] => ['nick', 'mail', 'link'],\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n },\n\n requiredMeta: {\n type: Array,\n default: (): WalineMeta[] => [],\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n },\n\n dark: [String, Boolean],\n\n lang: {\n type: String,\n default: 'zh-CN',\n validator: (value: unknown): boolean =>\n Object.keys(defaultLocales).includes(value as string),\n },\n\n locale: Object as PropType<Partial<WalineLocale>>,\n\n pageSize: { type: Number, default: 10 },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n validator: (value: unknown): boolean =>\n typeof value === 'number' ||\n (Array.isArray(value) &&\n value.length === 2 &&\n value.every((item) => typeof item === 'number')),\n },\n\n emoji: {\n type: [Array, Boolean] as PropType<(string | WalineEmojiInfo)[] | false>,\n validator: (value: unknown): boolean =>\n value === false ||\n (Array.isArray(value) &&\n value.every(\n (item) =>\n typeof item === 'string' ||\n (typeof item === 'object' &&\n typeof item.name === 'string' &&\n typeof item.folder === 'string' &&\n typeof item.icon === 'string' &&\n Array.isArray(item.items) &&\n (item.items as unknown[]).every(\n (icon) => typeof icon === 'string'\n ))\n )),\n },\n\n login: String as PropType<'enable' | 'disable' | 'force'>,\n\n highlighter: Function as PropType<WalineHighlighter>,\n\n imageUploader: {\n type: [Function, Boolean] as PropType<WalineImageUploader | false>,\n default: undefined,\n },\n\n texRenderer: {\n type: [Function, Boolean] as PropType<WalineTexRenderer | false>,\n default: undefined,\n },\n\n search: {\n type: [Object, Boolean] as PropType<WalineSearchOptions | false>,\n default: undefined,\n },\n\n copyright: { type: Boolean, default: true },\n\n recaptchaV3Key: {\n type: String,\n default: '',\n },\n\n reaction: {\n type: [Array, Boolean] as PropType<string[] | false>,\n },\n};\n\nexport default defineComponent({\n name: 'WalineRoot',\n\n components: {\n Reaction,\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: SHOULD_VALIDATE ? propsWithValidate : props,\n\n setup(props) {\n const config = computed(() => getConfig(props as unknown as WalineProps));\n\n const userInfo = useUserInfo();\n const likeStorage = useLikeStorage();\n\n const status = ref<'loading' | 'success' | 'error'>('loading');\n\n const count = ref(0);\n const page = ref(1);\n const totalPages = ref(0);\n const sortBy = ref<SortKeyItems>(sortByItems[0].key);\n\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n const edit = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n useStyleTag(darkmodeStyle);\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n\n const fetchCommentData = (pageNumber: number): void => {\n const { serverURL, path, pageSize } = config.value;\n const controller = new AbortController();\n\n status.value = 'loading';\n\n abort?.();\n\n fetchComment({\n serverURL,\n lang: config.value.lang,\n path,\n pageSize,\n sortBy: sortBy.value,\n page: pageNumber,\n signal: controller.signal,\n token: userInfo.value?.token,\n })\n .then((resp) => {\n status.value = 'success';\n count.value = resp.count;\n data.value.push(...resp.data);\n page.value = pageNumber;\n totalPages.value = resp.totalPages;\n })\n .catch((err) => {\n if (err.name !== 'AbortError') {\n console.error(err.message);\n status.value = 'error';\n }\n });\n\n abort = controller.abort.bind(controller);\n };\n\n const loadMore = (): void => fetchCommentData(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchCommentData(1);\n };\n\n const onSortByChange = (item: SortKeyItems): void => {\n if (sortBy.value === item) {\n return;\n }\n sortBy.value = item;\n refresh();\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onEdit = (comment: WalineComment | null): void => {\n edit.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n if (edit.value) {\n edit.value.comment = comment.comment;\n edit.value.orig = comment.orig;\n } else if (comment.rid) {\n const repliedComment = data.value.find(\n ({ objectId }) => objectId === comment.rid\n );\n\n if (!repliedComment) return;\n\n if (!Array.isArray(repliedComment.children))\n repliedComment.children = [];\n\n repliedComment.children.push(comment);\n } else data.value.unshift(comment);\n };\n\n const onStatusChange = async ({\n comment,\n status,\n }: {\n comment: WalineComment;\n status: WalineCommentStatus;\n }): Promise<void> => {\n if (comment.status === status) return;\n\n const { serverURL, lang } = config.value;\n\n await updateComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: comment.objectId,\n status,\n });\n\n comment.status = status;\n };\n\n const onSticky = async (comment: WalineComment): Promise<void> => {\n if (comment.rid) return;\n\n const { serverURL, lang } = config.value;\n\n await updateComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: comment.objectId,\n sticky: comment.sticky ? 0 : 1,\n });\n\n comment.sticky = !comment.sticky;\n };\n\n const onDelete = async ({ objectId }: WalineComment): Promise<void> => {\n if (!confirm('Are you sure you want to delete this comment?')) return;\n\n const { serverURL, lang } = config.value;\n\n await deleteComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: objectId,\n });\n\n // delete comment from data\n data.value.some((item, index) => {\n if (item.objectId === objectId) {\n data.value = data.value.filter((_item, i) => i !== index);\n\n return true;\n }\n\n return item.children.some((child, childIndex) => {\n if (child.objectId === objectId) {\n data.value[index].children = item.children.filter(\n (_item, i) => i !== childIndex\n );\n\n return true;\n }\n\n return false;\n });\n });\n };\n\n const onLike = async (comment: WalineComment): Promise<void> => {\n const { serverURL, lang } = config.value;\n const { objectId } = comment;\n const hasLiked = likeStorage.value.includes(objectId);\n\n await likeComment({\n serverURL,\n lang,\n objectId,\n like: !hasLiked,\n });\n\n if (hasLiked)\n likeStorage.value = likeStorage.value.filter((id) => id !== objectId);\n else {\n likeStorage.value = [...likeStorage.value, objectId];\n\n if (likeStorage.value.length > 50)\n likeStorage.value = likeStorage.value.slice(-50);\n }\n\n comment.like = (comment.like || 0) + (hasLiked ? -1 : 1);\n };\n\n provide('config', config);\n\n watch(() => (props as unknown as WalineProps).path, refresh);\n\n onMounted(() => refresh());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n sortBy,\n sortByItems,\n data,\n reply,\n edit,\n\n loadMore,\n refresh,\n onSortByChange,\n onReply,\n onSubmit,\n onStatusChange,\n onDelete,\n onSticky,\n onLike,\n onEdit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","import { fetchPageviews, updatePageviews } from './api';\nimport { errorHandler, getQuery, getServerURL } 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({\n serverURL: getServerURL(serverURL),\n path,\n lang,\n }).then((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements\n )\n );\n\n // if we should fetch count of other pages\n if (elementsNeedstoBeFetched.length) {\n void fetch(elementsNeedstoBeFetched);\n }\n }\n // we should not update pageviews\n else {\n void fetch(elements);\n }\n\n return controller.abort.bind(controller);\n};\n","import { fetchArticleCounter, updateArticleCounter } from './articleCounter';\n\ninterface FetchPageviewOptions {\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}: FetchPageviewOptions): Promise<number[]> =>\n fetchArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions {\n serverURL: string;\n lang: string;\n path: string;\n action?: 'inc' | 'desc';\n}\n\nexport const updatePageviews = (\n options: UpdatePageviewOptions\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n });\n","import { createApp, h, reactive, watchEffect } from 'vue';\n\nimport Waline from './components/Waline.vue';\nimport { commentCount } from './comment';\nimport { pageviewCount } from './pageview';\nimport { getRoot } from './utils';\n\nimport type { WalineInitOptions } from './typings';\n\nexport interface WalineInstance {\n /**\n * Waline 被挂载到的元素\n *\n * @description 当通过 `el: null` 初始化,值为 `null`\n *\n * Element where Waline is mounted\n *\n * @description when initialized with `el: null`, it will be `null`\n */\n el: HTMLElement | null;\n\n /**\n * 更新 Waline 实例\n *\n * @description 只要不设置`path` 选项,更新时它就会被重置为 `windows.location.pathname`\n *\n * Update Waline instance\n *\n * @description when not setting `path` option, it will be reset to `window.location.pathname`\n */\n update: (newOptions?: Partial<Omit<WalineInitOptions, 'el'>>) => void;\n\n /**\n * 取消挂载并摧毁 Waline 实例\n *\n * Unmount and destroy Waline instance\n */\n destroy: () => void;\n}\n\nexport const init = ({\n el = '#waline',\n path = window.location.pathname,\n comment = false,\n pageview = false,\n ...initProps\n}: WalineInitOptions): WalineInstance | null => {\n // check el element\n const root = el ? getRoot(el) : null;\n\n // check root\n if (el && !root) throw new Error(`Option 'el' do not match any domElement!`);\n\n // check serverURL\n if (!initProps.serverURL) throw new Error(\"Option 'serverURL' is missing!\");\n\n const props = reactive({ ...initProps });\n const state = reactive({ comment, pageview, path });\n\n const updateCommentCount = (): void => {\n if (state.comment)\n commentCount({\n serverURL: props.serverURL,\n path: state.path,\n selector: typeof state.comment === 'string' ? state.comment : undefined,\n });\n };\n\n const updatePageviewCount = (): void => {\n if (state.pageview)\n pageviewCount({\n serverURL: props.serverURL,\n path: state.path,\n selector:\n typeof state.pageview === 'string' ? state.pageview : undefined,\n });\n };\n\n const app = root\n ? createApp(() => h(Waline, { path: state.path, ...props }))\n : null;\n\n if (app) app.mount(root!);\n\n const stopComment = watchEffect(updateCommentCount);\n const stopPageview = watchEffect(updatePageviewCount);\n\n return {\n el: root,\n update: ({\n comment,\n pageview,\n path = window.location.pathname,\n ...newProps\n }: Partial<Omit<WalineInitOptions, 'el'>> = {}): void => {\n Object.entries(newProps).forEach(([key, value]) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n // eslint-disable-next-line\n props[key] = value;\n });\n\n state.path = path;\n if (comment !== undefined) state.comment = comment;\n if (pageview !== undefined) state.pageview = pageview;\n },\n destroy: (): void => {\n app?.unmount();\n stopComment();\n stopPageview();\n },\n };\n};\n","declare const VERSION: string;\n\nexport const version = VERSION;\n","import { fetchRecentComment } from '../api';\nimport { useUserInfo } from '../composables';\nimport { getRoot } from '../utils';\n\nimport type { WalineComment } from '../typings';\n\nexport interface WalineRecentCommentsOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 获取最新评论的数量\n *\n * fetch number of latest comments\n */\n count: number;\n\n /**\n * 需要挂载的元素\n *\n * Element to be mounted\n */\n el?: string | HTMLElement;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default 'zh-CN'\n */\n lang?: string;\n}\n\nexport interface WalineRecentCommentsResult {\n /**\n * 评论数据\n *\n * Comment Data\n */\n comments: WalineComment[];\n\n /**\n * 取消挂载挂件\n *\n * Umount widget\n */\n destroy: () => void;\n}\n\nexport const RecentComments = ({\n el,\n serverURL,\n count,\n lang = 'zh-CN',\n}: WalineRecentCommentsOptions): Promise<WalineRecentCommentsResult> => {\n const userInfo = useUserInfo();\n const root = getRoot(el);\n const controller = new AbortController();\n\n return fetchRecentComment({\n serverURL,\n count,\n lang,\n signal: controller.signal,\n token: userInfo.value?.token,\n }).then((comments) => {\n if (root && comments.length) {\n root.innerHTML = `<ul class=\"wl-recent-list\">${comments\n .map(\n (comment) =>\n `<li class=\"wl-recent-item\"><a href=\"${comment.url}\">${comment.nick}</a>:${comment.comment}</li>`\n )\n .join('')}</ul>`;\n\n return {\n comments,\n destroy: (): void => {\n controller.abort();\n root.innerHTML = '';\n },\n };\n }\n\n return {\n comments,\n destroy: (): void => controller.abort(),\n };\n });\n};\n","import { errorCheck } from './utils';\nimport type { WalineComment } from '../typings';\n\nexport interface FetchRecentCommentOptions {\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}: FetchRecentCommentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n\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"],"names":["availableMeta","getMeta","meta","filter","item","includes","defaultLang","defaultUploadImage","file","Promise","resolve","reject","size","Error","reader","FileReader","readAsDataURL","onload","_reader$result","toString","result","onerror","defaultTexRenderer","blockMode","getDefaultSearchOptions","lang","fetchGiphy","async","url","params","querystring","URLSearchParams","limit","rating","api_key","resp","fetch","then","json","data","map","gif","title","src","images","downsized_medium","search","word","q","offset","default","more","defaultReaction","REGEXP","RegExp","source","COLORS","cache","defaultHighlighter","input","index","replace","_match","comment","color","out","length","localeKeys","generateLocale","locale","Object","fromEntries","en","jp","zhCN","zhTW","ptBR","ru","defaultLocales","zh","JSON_HEADERS","errorCheck","name","errno","TypeError","errmsg","fetchArticleCounter","_ref","serverURL","paths","type","signal","encodeURIComponent","join","updateArticleCounter","_ref2","path","action","method","headers","body","JSON","stringify","updateComment","_ref7","token","objectId","Authorization","decodePath","decodeURI","err","removeEndingSplash","content","isLinkHttp","link","test","getServerURL","getWordLimit","wordLimit","Array","isArray","fallback","value","style","padWithZeros","vNumber","width","numAsString","getTimeAgo","date","now","time","Date","indexOf","timepassed","getTime","days","Math","floor","leave1","hours","leave2","minutes","leave3","round","seconds","vDay","getDate","vMonth","getMonth","getFullYear","dateFormat","fetchEmoji","emojiStore","useStorage","Boolean","info","emojiInfo","folder","getLink","prefix","errorHandler","console","error","message","getRoot","el","HTMLElement","document","querySelector","isImage","getImagefromDataTransfer","items","image","from","find","getAsFile","inlineMathStart","inlineMathReg","blockMathReg","parseEmoji","text","emojiMap","placeholder","key","parseMarkdown","_ref41","highlighter","texRenderer","marked","setOptions","highlight","undefined","breaks","smartLists","smartypants","extensions","level","tokenizer","cap","exec","raw","start","idx","markedTexExtensions","use","parse","getQuery","element","dataset","getAttribute","commentCount","_ref42","window","location","pathname","selector","controller","AbortController","elements","querySelectorAll","_ref8","counts","fetchCommentCount","forEach","innerText","catch","abort","bind","likeStorage","useLikeStorage","recaptchaStore","useTimeAgo","useNow","computed","VOTE_IDENTIFIER","VOTE_INDEX","voteStorage","useVoteStorage","userInfoStorage","useUserInfo","_sfc_main$4","defineComponent","setup","votes","ref","config","inject","reaction","icon","vote","desc","active","_ref43","voteIdentifier","voteIndex","onMounted","_","k","fetchCounter","onUnmounted","_abort","hasVoted","_ref44","max","i","slice","LoadingIcon","_ref47","h","height","viewBox","preserveAspectRatio","cx","cy","fill","stroke","strokeWidth","r","attributeName","repeatCount","dur","values","keyTimes","_sfc_main$3","components","props","columnWidth","Number","gap","emits","resizeObserver","wall","state","columns","getColumnCount","count","getBoundingClientRect","createColumns","fillColumns","_wall$value","itemIndex","nextTick","target","children","reduce","prev","curr","push","redraw","force","scrollY","scrollTo","top","watch","ResizeObserver","observe","onBeforeUnmount","unobserve","imageLoad","e","_sfc_main$2","CloseIcon","_ref45","class","d","EmojiIcon","ImageIcon","ImageWall","MarkdownIcon","ariaHidden","PreviewIcon","GifIcon","rootId","String","replyId","replyUser","edit","_ref48","emit","editor","userMeta","nick","mail","userInfo","inputRefs","editorRef","imageUploadRef","emojiButtonRef","emojiPopupRef","gifButtonRef","gifPopupRef","gifSearchInputRef","emoji","tabs","emojiTabIndex","showEmoji","showGif","showPreview","previewText","wordNumber","searchResults","reactive","loading","list","isWordNumberLegal","isSubmitting","isLogin","_userInfo$value","canUploadImage","imageUploader","insert","textArea","startPosition","selectionStart","endPosition","selectionEnd","scrollTop","substring","focus","uploadImage","uploadText","uploading","alert","submitComment","_userInfo$value2","_userInfo$value3","login","requiredMeta","recaptchaV3Key","init","load","useRecaptchaNet","autoHideBadge","execute","instance","useReCaptcha","ua","navigator","userAgent","recaptchaV3","display_name","email","_inputRefs$value$nick","_inputRefs$value$mail","_editorRef$value","nickError","mailError","anonymous","wordHint","pid","rid","at","eid","_ref4","postComment","_props$edit","popupHandler","event","contains","onImageWallScroll","_gifSearchInputRef$va","clientHeight","scrollHeight","percent","searchOptions","keyword","setTimeout","onGifSearch","useDebounceFn","_ref49","immediate","onMessageRecive","_ref50","localStorage","sessionStorage","store","getItem","setItem","_props$edit2","addEventListener","orig","match","getWords","accumulator","trim","split","getChinese","getWordNumber","autosize","destroy","emojiConfig","getEmojis","emojis","all","emojiInfos","removeEventListener","onChange","inputElement","files","onDrop","_event$dataTransfer","dataTransfer","preventDefault","onKeyDown","ctrlKey","metaKey","onPaste","clipboardData","onLogin","_ref9","left","innerWidth","innerHeight","handler","open","postMessage","receiver","_ref10","close","remember","onLogout","onProfile","gifData","commentStatus","_sfc_main$1","CommentBox","DeleteIcon","LikeIcon","_ref46","ReplyIcon","EditIcon","VerifiedIcon","required","reply","likes","like","insertedAt","isAdmin","isOwner","user_id","isReplyingCurrent","_props$reply","isEditingCurrent","_props$edit3","sortByItems","_sfc_main","Reaction","CommentCard","_ref13","dark","pageSize","copyright","getConfig","status","page","totalPages","sortBy","darkmodeStyle","getDarkStyle","useStyleTag","fetchCommentData","pageNumber","_abort2","_userInfo$value4","_ref3","fetchComment","refresh","provide","i18n","loadMore","onSortByChange","onReply","onSubmit","repliedComment","_ref51","unshift","onStatusChange","_userInfo$value5","_ref52","onDelete","_userInfo$value7","_ref53","confirm","_ref5","deleteComment","some","_item","child","childIndex","onSticky","_userInfo$value6","sticky","onLike","hasLiked","_ref6","likeComment","id","onEdit","version","renderVisitorCount","countElements","pageviewCount","_ref54","update","query","_ref11","fetchPageviews","normalElements","elementsNeedstoBeFetched","options","_ref55","pageview","initProps","root","app","createApp","Waline","mount","stopComment","watchEffect","stopPageview","newProps","entries","_ref56","unmount","_ref57","_userInfo$value8","_ref12","fetchRecentComment","comments","innerHTML"],"mappings":"oaAOA,MAAMA,EAA8B,CAAC,OAAQ,OAAQ,QAExCC,EAAWC,GACtBA,EAAKC,QAAQC,GAASJ,EAAcK,SAASD,KAElCE,EAAc,QAEdC,EAAsBC,GACjC,IAAIC,SAAQ,CAACC,EAASC,KACpB,GAAIH,EAAKI,KAAO,MACd,OAAOD,EAAO,IAAIE,MAAM,0CAG1B,MAAMC,EAAS,IAAIC,WAEnBD,EAAOE,cAAcR,GACrBM,EAAOG,OAAS,KAAA,IAAAC,EAAA,OAAYR,GAAuBS,QAAfD,EAAAJ,EAAOM,cAAQD,IAAAA,OAAAA,EAAAA,EAAAA,aAAc,GAAjD,EAChBL,EAAOO,QAAUV,CAAjB,IAGSW,EAAsBC,IACnB,IAAdA,EACI,wDACA,8DAEOC,EAA2BC,IAiBtC,MAAMC,EAAaC,eACjBC,GAE+B,IAD/BC,yDAAiC,CACF,EAC/B,MAAMC,EAAc,IAAIC,gBAAgB,CACtCN,OACAO,MAAO,KACPC,OAAQ,IACRC,QAAS,sCACNL,IACFV,WAEGgB,QAAaC,uCACgBR,KAAOE,KACxCO,MAAMF,GAASA,EAAKG,SAEtB,OAAOH,EAAKI,KAAKC,KAAKC,IAAS,CAC7BC,MAAOD,EAAIC,MACXC,IAAKF,EAAIG,OAAOC,iBAAiBjB,OAEpC,EAED,MAAO,CACLkB,OAASC,GACPrB,EAAW,SAAU,CAAEsB,EAAGD,EAAME,OAAQ,MAC1CC,QAAS,IAAmCxB,EAAW,WAAY,IACnEyB,KAAM,SAACJ,GAAD,IAAeE,yDAAS,EAAxB,OACJvB,EAAW,SAAU,CAAEsB,EAAGD,EAAME,OAAQA,EAAO9B,YAD3C,EAJR,EASWiC,EAAkB,CAC7B,mDACA,uDACA,wDACA,uDACA,qDACA,oDCxDIC,EAAS,IAAIC,WAJjB,wFAKgBC,UAJQ,IAIoBA,eAHlB,uBAGqDA,cAFpD,uBAEuFA,WAClH,OAGIC,EAAS,CACb,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,UAEIC,EAAgC,CAAtC,EAEaC,EAAsBC,IACjC,IAAIC,EAAQ,EAEZ,OAAOD,EAAME,QAAQR,GAAQ,CAACS,EAAQf,EAAcgB,KAClD,GAAIA,EAAS,MAAO,kCAAkCA,WACtD,GAAa,MAAThB,EAAc,MAAO,OAEzB,IAAIiB,EAEAP,EAAMV,GAAOiB,EAAQP,EAAMV,IAE7BiB,EAAQR,EAAOI,GACfH,EAAMV,GAAQiB,GAGhB,MAAMC,EAAM,wBAAwBD,MAAUjB,WAI9C,OAFAa,IAAUA,EAAQJ,EAAOU,OAElBD,CAAP,GAhBF,ECrDIE,EAAa,CACjB,OACA,YACA,OACA,YACA,OACA,WACA,cACA,OACA,SACA,OACA,aACA,QACA,cACA,UACA,UACA,OACA,UACA,QACA,cACA,UACA,UACA,QACA,OACA,MACA,YACA,QACA,SACA,QACA,SACA,OACA,WACA,YACA,SACA,SACA,SACA,SACA,SACA,SACA,MACA,uBACA,UACA,WACA,UACA,OACA,WACA,SACA,SACA,UACA,iBAGWC,EAAkBC,GAC7BC,OAAOC,YACLF,EAAO7B,KAAI,CAACpC,EAAMwD,IAAU,CAACO,EAAWP,GAAQxD,MCtDpD,IAAAoE,EAAeJ,EAAe,CAC5B,WACA,wCACA,SACA,qCACA,UACA,WACA,kBACA,kBACA,SACA,OACA,cACA,QACA,eACA,WACA,UACA,eACA,UACA,QACA,eACA,cACA,cACA,YACA,WACA,WACA,YACA,QACA,SACA,QACA,SACA,QACA,2EACA,YACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,aACA,UACA,WACA,UACA,OACA,WACA,SACA,SACA,UACA,uBCjDFK,EAAeL,EAAe,CAC5B,SACA,yBACA,UACA,mBACA,MACA,QACA,UACA,aACA,OACA,OACA,cACA,OACA,QACA,OACA,KACA,UACA,QACA,MACA,YACA,KACA,KACA,MACA,KACA,OACA,SACA,SACA,QACA,MACA,SACA,MACA,gDACA,KACA,OACA,OACA,OACA,SACA,KACA,MACA,MACA,SACA,OACA,OACA,QACA,MACA,SACA,KACA,KACA,MACA,aCjDFM,EAAeN,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,MACA,QACA,OACA,KACA,MACA,KACA,OACA,MACA,MACA,MACA,gBCjDFO,EAAeP,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,MACA,QACA,OACA,KACA,MACA,KACA,OACA,MACA,MACA,MACA,gBCjDFQ,EAAeR,EAAe,CAC5B,UACA,0CACA,SACA,8CACA,UACA,WACA,kBACA,4BACA,SACA,OACA,cACA,YACA,oBACA,cACA,YACA,mBACA,aACA,QACA,gBACA,iBACA,gBACA,cACA,aACA,cACA,WACA,SACA,OACA,QACA,SACA,WACA,gFACA,UACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,gBACA,qBACA,WACA,SACA,OACA,WACA,aACA,gBACA,cACA,qBCjDFS,EAAeT,EAAe,CAC5B,YACA,uCACA,YACA,yDACA,WACA,iBACA,uBACA,yBACA,YACA,OACA,cACA,WACA,iBACA,cACA,WACA,oBACA,SACA,SACA,wBACA,eACA,wBACA,wBACA,aACA,eACA,WACA,iBACA,mBACA,QACA,SACA,QACA,8EACA,YACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,YACA,sBACA,aACA,YACA,OACA,WACA,eACA,YACA,gBACA,oBCvCW,MAAAU,EAA0B,CACrCC,GAAIL,EACJ,QAASA,EACT,QAASA,EACT,QAASC,EACT,QAASA,EACTH,GAAIA,EACJ,QAASA,EACT,QAASA,EACTC,GAAIA,EACJ,QAASA,EACT,QAASA,EACT,QAASG,EACT,QAASA,EACTC,GAAIA,EACJ,QAASA,EACT,QAASA,sBCvBJ,MAAMG,EAAuC,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"}
1
+ {"version":3,"file":"waline.js","sources":["../src/config/default.ts","../src/config/highlighter.ts","../src/config/i18n/generate.ts","../src/config/i18n/en.ts","../src/config/i18n/jp.ts","../src/config/i18n/zh-CN.ts","../src/config/i18n/zh-TW.ts","../src/config/i18n/pt-BR.ts","../src/config/i18n/ru.ts","../src/config/i18n/index.ts","../src/api/utils.ts","../src/api/articleCounter.ts","../src/api/comment.ts","../src/utils/path.ts","../src/utils/config.ts","../src/utils/darkmode.ts","../src/utils/date.ts","../src/utils/emoji.ts","../src/utils/error.ts","../src/utils/getRoot.ts","../src/utils/image.ts","../src/utils/markedMathExtension.ts","../src/utils/markdown.ts","../src/utils/query.ts","../src/comment.ts","../src/api/commentCount.ts","../src/composables/like.ts","../src/composables/recaptchaV3.ts","../src/composables/timeAgo.ts","../src/composables/vote.ts","../src/composables/userInfo.ts","../src/components/ArticleReaction.vue","../src/components/Icons.ts","../src/components/ImageWall.vue","../src/components/CommentBox.vue","../src/composables/inputs.ts","../src/utils/wordCount.ts","../src/api/login.ts","../src/components/CommentCard.vue","../src/components/Waline.vue","../src/pageview.ts","../src/api/pageview.ts","../src/init.ts","../src/version.ts","../src/widgets/recentComments.ts","../src/api/recentComment.ts","../src/widgets/userList.ts","../src/api/user.ts"],"sourcesContent":["import type { IGif } from '@giphy/js-types';\nimport type {\n WalineMeta,\n WalineSearchOptions,\n WalineSearchResult,\n} from '../typings';\n\nconst availableMeta: WalineMeta[] = ['nick', 'mail', 'link'];\n\nexport const getMeta = (meta: WalineMeta[]): WalineMeta[] =>\n meta.filter((item) => availableMeta.includes(item));\n\nexport const defaultLang = 'zh-CN';\n\nexport const defaultUploadImage = (file: File): Promise<string> =>\n new Promise((resolve, reject) => {\n if (file.size > 128 * 1000) {\n return reject(new Error('File too large! File size limit 128KB'));\n }\n\n const reader = new FileReader();\n\n reader.readAsDataURL(file);\n reader.onload = (): void => resolve(reader.result?.toString() || '');\n reader.onerror = reject;\n });\n\nexport const defaultTexRenderer = (blockMode: boolean): string =>\n blockMode === true\n ? '<p class=\"wl-tex\">Tex is not available in preview</p>'\n : '<span class=\"wl-tex\">Tex is not available in preview</span>';\n\nexport const getDefaultSearchOptions = (lang: string): WalineSearchOptions => {\n interface Result {\n meta: {\n msg: string;\n response_id: string;\n status: number;\n };\n pagination: {\n count: number;\n total_count: number;\n offset: number;\n };\n }\n interface GifsResult extends Result {\n data: IGif[];\n }\n\n const fetchGiphy = async (\n url: string,\n params: Record<string, string> = {}\n ): Promise<WalineSearchResult> => {\n const querystring = new URLSearchParams({\n lang,\n limit: '20',\n rating: 'g',\n api_key: '6CIMLkNMMOhRcXPoMCPkFy4Ybk2XUiMp',\n ...params,\n }).toString();\n\n const resp = await fetch(\n `https://api.giphy.com/v1/gifs/${url}?${querystring}`\n ).then((resp) => resp.json() as Promise<GifsResult>);\n\n return resp.data.map((gif) => ({\n title: gif.title,\n src: gif.images.downsized_medium.url,\n }));\n };\n\n return {\n search: (word: string): Promise<WalineSearchResult> =>\n fetchGiphy('search', { q: word, offset: '0' }),\n default: (): Promise<WalineSearchResult> => fetchGiphy('trending', {}),\n more: (word: string, offset = 0): Promise<WalineSearchResult> =>\n fetchGiphy('search', { q: word, offset: offset.toString() }),\n };\n};\n\nexport const defaultReaction = [\n '//unpkg.com/@waline/emojis/tieba/tieba_agree.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_look_down.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_sunglasses.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_pick_nose.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_awkward.png',\n '//unpkg.com/@waline/emojis/tieba/tieba_sleep.png',\n];\n","/**\n * The MIT License (MIT)\n *\n * Copyright (c) egoist <0x142857@gmail.com> (https://egoistian.com)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\nconst WORD_REGEXP =\n /[\\u4E00-\\u9FFF\\u3400-\\u4dbf\\uf900-\\ufaff\\u3040-\\u309f\\uac00-\\ud7af\\u0400-\\u04FF]+|\\w+/;\nconst LEFT_ANGLE_REGEXP = /</;\nconst LINE_COMMENT_REGEXP = /(?:^|\\s)\\/\\/(.+?)$/gm;\nconst BLOCK_COMMENT_REGEXP = /\\/\\*([\\S\\s]*?)\\*\\//gm;\nconst REGEXP = new RegExp(\n `(${WORD_REGEXP.source}|${LEFT_ANGLE_REGEXP.source})|((?:${LINE_COMMENT_REGEXP.source})|(?:${BLOCK_COMMENT_REGEXP.source}))`,\n 'gmi'\n);\n\nconst COLORS = [\n '23AC69',\n '91C132',\n 'F19726',\n 'E8552D',\n '1AAB8E',\n 'E1147F',\n '2980C1',\n '1BA1E6',\n '9FA0A0',\n 'F19726',\n 'E30B20',\n 'E30B20',\n 'A3338B',\n];\nconst cache: Record<string, string> = {};\n\nexport const defaultHighlighter = (input: string): string => {\n let index = 0;\n\n return input.replace(REGEXP, (_match, word: string, comment: string) => {\n if (comment) return `<span style=\"color: slategray\">${comment}</span>`;\n if (word === '<') return '&lt;';\n\n let color: string;\n\n if (cache[word]) color = cache[word];\n else {\n color = COLORS[index];\n cache[word] = color;\n }\n\n const out = `<span style=\"color: #${color}\">${word}</span>`;\n\n index = ++index % COLORS.length;\n\n return out;\n });\n};\n","import type { WalineLocale } from '../../typings';\n\nconst localeKeys = [\n 'nick',\n 'nickError',\n 'mail',\n 'mailError',\n 'link',\n 'optional',\n 'placeholder',\n 'sofa',\n 'submit',\n 'like',\n 'cancelLike',\n 'reply',\n 'cancelReply',\n 'comment',\n 'refresh',\n 'more',\n 'preview',\n 'emoji',\n 'uploadImage',\n 'seconds',\n 'minutes',\n 'hours',\n 'days',\n 'now',\n 'uploading',\n 'login',\n 'logout',\n 'admin',\n 'sticky',\n 'word',\n 'wordHint',\n 'anonymous',\n 'level0',\n 'level1',\n 'level2',\n 'level3',\n 'level4',\n 'level5',\n 'gif',\n 'gifSearchPlaceholder',\n 'profile',\n 'approved',\n 'waiting',\n 'spam',\n 'unsticky',\n 'oldest',\n 'latest',\n 'hottest',\n 'reactionTitle',\n];\n\nexport const generateLocale = (locale: string[]): WalineLocale =>\n Object.fromEntries(\n locale.map((item, index) => [localeKeys[index], item])\n ) as unknown as WalineLocale;\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'NickName',\n 'NickName cannot be less than 3 bytes.',\n 'E-Mail',\n 'Please confirm your email address.',\n 'Website',\n 'Optional',\n 'Comment here...',\n 'No comment yet.',\n 'Submit',\n 'Like',\n 'Cancel like',\n 'Reply',\n 'Cancel reply',\n 'Comments',\n 'Refresh',\n 'Load More...',\n 'Preview',\n 'Emoji',\n 'Upload Image',\n 'seconds ago',\n 'minutes ago',\n 'hours ago',\n 'days ago',\n 'just now',\n 'Uploading',\n 'Login',\n 'logout',\n 'Admin',\n 'Sticky',\n 'Words',\n 'Please input comments between $0 and $1 words!\\n Current word number: $2',\n 'Anonymous',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Search GIF',\n 'Profile',\n 'Approved',\n 'Waiting',\n 'Spam',\n 'Unsticky',\n 'Oldest',\n 'Latest',\n 'Hottest',\n 'What do you think?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'ニックネーム',\n '3バイト以上のニックネームをご入力ください.',\n 'メールアドレス',\n 'メールアドレスをご確認ください.',\n 'サイト',\n 'オプション',\n 'ここにコメント',\n 'コメントしましょう~',\n '提出する',\n 'Like',\n 'Cancel like',\n '返信する',\n 'キャンセル',\n 'コメント',\n '更新',\n 'さらに読み込む',\n 'プレビュー',\n '絵文字',\n '画像をアップロード',\n '秒前',\n '分前',\n '時間前',\n '日前',\n 'たっだ今',\n 'アップロード',\n 'ログインする',\n 'ログアウト',\n '管理者',\n 'トップに置く',\n 'ワード',\n 'コメントは $0 から $1 ワードの間でなければなりません!\\n 現在の単語番号: $2',\n '匿名',\n 'うえにん',\n 'なかにん',\n 'しもおし',\n '特にしもおし',\n 'かげ',\n 'なぬし',\n 'GIF',\n '探す GIF',\n '個人情報',\n '承認済み',\n '待っている',\n 'スパム',\n 'べたつかない',\n '逆順',\n '正順',\n '人気順',\n 'どう思いますか?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '昵称',\n '昵称不能少于3个字符',\n '邮箱',\n '请填写正确的邮件地址',\n '网址',\n '可选',\n '欢迎评论',\n '来发评论吧~',\n '提交',\n '喜欢',\n '取消喜欢',\n '回复',\n '取消回复',\n '评论',\n '刷新',\n '加载更多...',\n '预览',\n '表情',\n '上传图片',\n '秒前',\n '分钟前',\n '小时前',\n '天前',\n '刚刚',\n '正在上传',\n '登录',\n '退出',\n '博主',\n '置顶',\n '字',\n '评论字数应在 $0 到 $1 字之间!\\n当前字数:$2',\n '匿名',\n '潜水',\n '冒泡',\n '吐槽',\n '活跃',\n '话痨',\n '传说',\n '表情包',\n '搜索表情包',\n '个人资料',\n '通过',\n '待审核',\n '垃圾',\n '取消置顶',\n '按倒序',\n '按正序',\n '按热度',\n '你认为这篇文章怎么样?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '暱稱',\n '暱稱不能少於3個字元',\n '郵箱',\n '請填寫正確的郵件地址',\n '網址',\n '可選',\n '歡迎評論',\n '來發評論吧~',\n '提交',\n '喜歡',\n '取消喜歡',\n '回覆',\n '取消回覆',\n '評論',\n '刷新',\n '載入更多...',\n '預覽',\n '表情',\n '上傳圖片',\n '秒前',\n '分鐘前',\n '小時前',\n '天前',\n '剛剛',\n '正在上傳',\n '登錄',\n '退出',\n '博主',\n '置頂',\n '字',\n '評論字數應在 $0 到 $1 字之間!\\n當前字數:$2',\n '匿名',\n '潛水',\n '冒泡',\n '吐槽',\n '活躍',\n '話癆',\n '傳說',\n '表情包',\n '搜索表情包',\n '個人資料',\n '通過',\n '待審核',\n '垃圾',\n '取消置頂',\n '按倒序',\n '按正序',\n '按熱度',\n '你認為這篇文章怎麼樣?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'Apelido',\n 'Apelido não pode ser menor que 3 bytes.',\n 'E-Mail',\n 'Por favor, confirme seu endereço de e-mail.',\n 'Website',\n 'Opcional',\n 'Comente aqui...',\n 'Nenhum comentário, ainda.',\n 'Enviar',\n 'Like',\n 'Cancel like',\n 'Responder',\n 'Cancelar resposta',\n 'Comentários',\n 'Refrescar',\n 'Carregar Mais...',\n 'Visualizar',\n 'Emoji',\n 'Enviar Imagem',\n 'segundos atrás',\n 'minutos atrás',\n 'horas atrás',\n 'dias atrás',\n 'agora mesmo',\n 'Enviando',\n 'Entrar',\n 'Sair',\n 'Admin',\n 'Sticky',\n 'Palavras',\n 'Favor enviar comentário com $0 a $1 palavras!\\n Número de palavras atuais: $2',\n 'Anônimo',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Pesquisar GIF',\n 'informação pessoal',\n 'Aprovado',\n 'Espera',\n 'Spam',\n 'Unsticky',\n 'Mais velho',\n 'Mais recentes',\n 'Mais quente',\n 'O que você acha?',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n 'Псевдоним',\n 'Никнейм не может быть меньше 3 байт.',\n 'Эл. адрес',\n 'Пожалуйста, подтвердите адрес вашей электронной почты.',\n 'Веб-сайт',\n 'Необязательный',\n 'Комментарий здесь...',\n 'Пока нет комментариев.',\n 'Отправить',\n 'Like',\n 'Cancel like',\n 'Отвечать',\n 'Отменить ответ',\n 'Комментарии',\n 'Обновить',\n 'Загрузи больше...',\n 'Превью',\n 'эмодзи',\n 'Загрузить изображение',\n 'секунд назад',\n 'несколько минут назад',\n 'несколько часов назад',\n 'дней назад',\n 'прямо сейчас',\n 'Загрузка',\n 'Авторизоваться',\n 'Выход из системы',\n 'Админ',\n 'Липкий',\n 'Слова',\n 'Пожалуйста, введите комментарии от $0 до $1 слов!\\nНомер текущего слова: $2',\n 'Анонимный',\n 'Dwarves',\n 'Hobbits',\n 'Ents',\n 'Wizards',\n 'Elves',\n 'Maiar',\n 'GIF',\n 'Поиск GIF',\n 'Персональные данные',\n 'Одобренный',\n 'Ожидающий',\n 'Спам',\n 'Нелипкий',\n 'самый старый',\n 'последний',\n 'самый горячий',\n 'Что вы думаете?',\n]);\n","/* eslint-disable @typescript-eslint/naming-convention */\nimport en from './en';\nimport jp from './jp';\nimport zhCN from './zh-CN';\nimport zhTW from './zh-TW';\nimport ptBR from './pt-BR';\nimport ru from './ru';\n\nimport type { WalineLocale } from '../../typings';\n\nexport type Locales = Record<string, WalineLocale>;\n\nexport const defaultLocales: Locales = {\n zh: zhCN,\n 'zh-cn': zhCN,\n 'zh-CN': zhCN,\n 'zh-tw': zhTW,\n 'zh-TW': zhTW,\n en: en,\n 'en-US': en,\n 'en-us': en,\n jp: jp,\n 'jp-jp': jp,\n 'jp-JP': jp,\n 'pt-br': ptBR,\n 'pt-BR': ptBR,\n ru: ru,\n 'ru-ru': ru,\n 'ru-RU': ru,\n};\n","export interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nexport const JSON_HEADERS: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n};\n\nexport const errorCheck = <T = unknown>(\n data: T | FetchErrorData,\n name = ''\n): 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","import { JSON_HEADERS, errorCheck } from './utils';\n\nexport interface FetchArticleCounterOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n type: string[];\n}\n\nexport const fetchArticleCounter = ({\n serverURL,\n lang,\n paths,\n type,\n signal,\n}: FetchArticleCounterOptions): Promise<\n Record<string, number>[] | Record<string, number> | number[] | number\n> =>\n fetch(\n `${serverURL}/article?path=${encodeURIComponent(\n paths.join(',')\n )}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,\n { signal }\n )\n .then(\n (resp) =>\n resp.json() as Promise<Record<string, number>[] | number[] | number>\n )\n .then((data) => errorCheck(data, 'article count'));\n\nexport interface UpdateArticleCounterOptions {\n serverURL: string;\n lang: string;\n path: string;\n type: string;\n action?: 'inc' | 'desc';\n}\n\nexport const updateArticleCounter = ({\n serverURL,\n lang,\n path,\n type,\n action,\n}: UpdateArticleCounterOptions): Promise<number> =>\n fetch(`${serverURL}/article?lang=${lang}`, {\n method: 'POST',\n headers: JSON_HEADERS,\n body: JSON.stringify({ path, type, action }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'article count'));\n","import { JSON_HEADERS, errorCheck } from './utils';\nimport type { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchCommentOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n sortBy: string;\n signal: AbortSignal;\n token?: string;\n lang: string;\n}\n\nexport interface CommentData {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchComment = ({\n serverURL,\n lang,\n path,\n page,\n pageSize,\n sortBy,\n signal,\n token,\n}: FetchCommentOptions): Promise<CommentData> => {\n const headers: Record<string, string> = {};\n\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}&sortBy=${sortBy}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<CommentData>)\n .then((data) => errorCheck(data, 'comment data'));\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 if (comment.eid) {\n return fetch(`${serverURL}/comment/${comment.eid}?lang=${lang}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n }\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 fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'DELETE',\n headers: {\n Authorization: `Bearer ${token}`,\n },\n }).then((resp) => resp.json() as Promise<void>);\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 fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {\n method: 'PUT',\n headers: {\n ...JSON_HEADERS,\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify(data),\n }).then((resp) => resp.json() as Promise<void>);\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 defaultReaction,\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\n extends Required<Omit<WalineProps, 'wordLimit' | 'reaction'>> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n reaction: string[];\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.1.0/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,\n reaction,\n recaptchaV3Key = '',\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: search || getDefaultSearchOptions(lang),\n recaptchaV3Key,\n reaction: Array.isArray(reaction)\n ? reaction\n : reaction === true\n ? defaultReaction\n : [],\n ...more,\n});\n","const style = `{--waline-white:#000;--waline-light-grey:#666;--waline-dark-grey:#999;--waline-color:#888;--waline-bgcolor:#1e1e1e;--waline-bgcolor-light:#272727;--waline-bgcolor-hover: #444;--waline-border-color:#333;--waline-disable-bgcolor:#444;--waline-disable-color:#272727;--waline-bq-color:#272727;--waline-info-bgcolor:#272727;--waline-info-color:#666}`;\n\nexport const getDarkStyle = (selector?: string | boolean): string => {\n if (typeof selector === 'string') {\n return selector === 'auto'\n ? `@media(prefers-color-scheme:dark){body${style}}`\n : `${selector}${style}`;\n }\n\n return selector === true ? `:root${style}` : '';\n};\n","import { WalineDateLocale } from '../typings';\n\nconst padWithZeros = (vNumber: number, width: number): string => {\n let numAsString = vNumber.toString();\n\n while (numAsString.length < width) {\n numAsString = '0' + numAsString;\n }\n\n return numAsString;\n};\n\nexport const dateFormat = (date: Date): string => {\n const vDay = padWithZeros(date.getDate(), 2);\n const vMonth = padWithZeros(date.getMonth() + 1, 2);\n const vYear = padWithZeros(date.getFullYear(), 2);\n\n return `${vYear}-${vMonth}-${vDay}`;\n};\n\nexport const getTimeAgo = (\n date: Date | string,\n now: Date,\n locale: WalineDateLocale\n): string => {\n if (!date) return '';\n\n const time =\n typeof date === 'string'\n ? new Date(date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date)\n : date;\n\n const timepassed = now.getTime() - time.getTime();\n\n const days = Math.floor(timepassed / (24 * 3600 * 1000));\n\n if (days === 0) {\n // 计算相差小时数\n\n // 计算天数后剩余的毫秒数\n const leave1 = timepassed % (24 * 3600 * 1000);\n const hours = Math.floor(leave1 / (3600 * 1000));\n\n if (hours === 0) {\n //计算相差分钟数\n\n // 计算小时数后剩余的毫秒数\n const leave2 = leave1 % (3600 * 1000);\n const minutes = Math.floor(leave2 / (60 * 1000));\n\n // 计算相差秒数\n if (minutes === 0) {\n // 计算分钟数后剩余的毫秒数\n const leave3 = leave2 % (60 * 1000);\n const seconds = Math.round(leave3 / 1000);\n\n return `${seconds} ${locale.seconds}`;\n }\n\n return `${minutes} ${locale.minutes}`;\n }\n\n return `${hours} ${locale.hours}`;\n }\n\n if (days < 0) return locale.now;\n\n if (days < 8) return `${days} ${locale.days}`;\n\n return dateFormat(time);\n};\n","import { useStorage } from '@vueuse/core';\nimport { removeEndingSplash } from './path';\n\nimport type { WalineEmojiConfig } from './config';\nimport type { WalineEmojiInfo } from '../typings';\n\nconst hasVersion = (url: string): boolean =>\n Boolean(/@[0-9]+\\.[0-9]+\\.[0-9]+/.test(url));\n\nconst fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {\n const emojiStore = useStorage<Record<string, WalineEmojiInfo>>(\n 'WALINE_EMOJI',\n {}\n );\n\n const result = hasVersion(link);\n\n if (result) {\n const info = emojiStore.value[link];\n\n if (info) return Promise.resolve(info);\n }\n\n return fetch(`${link}/info.json`)\n .then((resp) => resp.json() as Promise<Omit<WalineEmojiInfo, 'folder'>>)\n .then((emojiInfo) => {\n const info = {\n folder: link,\n ...emojiInfo,\n };\n\n if (result) emojiStore.value[link] = info;\n\n return info;\n });\n};\n\nconst getLink = (name: string, folder = '', prefix = '', type = ''): string =>\n `${folder ? `${folder}/` : ''}${prefix}${name}${type ? `.${type}` : ''}`;\n\nexport const getEmojis = (\n emojis: (string | WalineEmojiInfo)[]\n): Promise<WalineEmojiConfig> =>\n Promise.all(\n emojis.map((emoji) =>\n typeof emoji === 'string'\n ? fetchEmoji(removeEndingSplash(emoji))\n : Promise.resolve(emoji)\n )\n ).then((emojiInfos) => {\n const emojiConfig: WalineEmojiConfig = {\n tabs: [],\n map: {},\n };\n\n emojiInfos.forEach((emojiInfo) => {\n const { name, folder, icon, prefix, type, items } = emojiInfo;\n\n emojiConfig.tabs.push({\n name,\n icon: getLink(icon, folder, prefix, type),\n items: items.map((item) => {\n const key = `${prefix || ''}${item}`;\n\n emojiConfig.map[key] = getLink(item, folder, prefix, type);\n\n return key;\n }),\n });\n });\n\n return emojiConfig;\n });\n","export const errorHandler = (err: Error): void => {\n if (err.name !== 'AbortError') console.error(err.message);\n};\n","export const getRoot = (\n el: string | HTMLElement | undefined\n): HTMLElement | null =>\n el instanceof HTMLElement\n ? el\n : typeof el === 'string'\n ? document.querySelector(el)\n : null;\n","const isImage = (item: DataTransferItem): boolean =>\n item.type.includes('image');\n\nexport const getImagefromDataTransfer = (\n items: DataTransferItemList\n): File | null => {\n const image = Array.from(items).find(isImage);\n\n return image ? (image.getAsFile() as File) : null;\n};\n","import type { marked } from 'marked';\nimport type { WalineTexRenderer } from '../typings';\n\nconst inlineMathStart = /\\$.*?\\$/;\nconst inlineMathReg = /^\\$(.*?)\\$/;\nconst blockMathReg = /^(?:\\s{0,3})\\$\\$((?:[^\\n]|\\n[^\\n])+?)\\n{0,1}\\$\\$/;\n\nexport const markedTexExtensions = (\n texRenderer: WalineTexRenderer\n): marked.TokenizerExtension[] => {\n const blockMathExtension: marked.TokenizerExtension = {\n name: 'blockMath',\n level: 'block',\n tokenizer(src: string) {\n const cap = blockMathReg.exec(src);\n\n if (cap !== null) {\n return {\n type: 'html',\n raw: cap[0],\n text: texRenderer(true, cap[1]),\n };\n }\n\n return undefined;\n },\n };\n\n const inlineMathExtension: marked.TokenizerExtension = {\n name: 'inlineMath',\n level: 'inline',\n start(src: string) {\n const idx = src.search(inlineMathStart);\n\n return idx !== -1 ? idx : src.length;\n },\n tokenizer(src: string) {\n const cap = inlineMathReg.exec(src);\n\n if (cap !== null) {\n return {\n type: 'html',\n raw: cap[0],\n text: texRenderer(false, cap[1]),\n };\n }\n\n return undefined;\n },\n };\n\n return [blockMathExtension, inlineMathExtension];\n};\n","import { marked } from 'marked';\nimport { markedTexExtensions } from './markedMathExtension';\n\nimport type {\n WalineEmojiMaps,\n WalineHighlighter,\n WalineTexRenderer,\n} from '../typings';\n\nexport const parseEmoji = (text = '', emojiMap: WalineEmojiMaps = {}): string =>\n text.replace(/:(.+?):/g, (placeholder, key: string) =>\n emojiMap[key]\n ? `<img class=\"wl-emoji\" src=\"${emojiMap[key]}\" alt=\"${key}\">`\n : placeholder\n );\n\nexport interface ParseMarkdownOptions {\n emojiMap: WalineEmojiMaps;\n highlighter: WalineHighlighter | false;\n texRenderer: WalineTexRenderer | false;\n}\n\nexport const parseMarkdown = (\n content: string,\n { emojiMap, highlighter, texRenderer }: ParseMarkdownOptions\n): string => {\n marked.setOptions({\n highlight: highlighter || undefined,\n breaks: true,\n smartLists: true,\n smartypants: true,\n });\n\n if (texRenderer) {\n const extensions = markedTexExtensions(texRenderer);\n\n marked.use({ extensions });\n }\n\n return marked.parse(parseEmoji(content, emojiMap));\n};\n","export const getQuery = (element: HTMLElement): string | null =>\n element.dataset.path || element.getAttribute('id');\n","import { fetchCommentCount } from './api';\nimport { decodePath, errorHandler, getServerURL } from './utils';\nimport type { WalineAbort } from './typings';\n\nexport interface WalineCommentCountOptions {\n /**\n * Waline 服务端地址\n *\n * Waline server url\n */\n serverURL: string;\n\n /**\n * 评论数 CSS 选择器\n *\n * Commment count CSS selector\n *\n * @default '.waline-comment-count'\n */\n selector?: string;\n\n /**\n * 需要获取的默认路径\n *\n * Path to be fetched by default\n *\n * @default window.location.pathname\n */\n path?: string;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default 'zh-CN'\n */\n lang?: string;\n}\n\nexport const commentCount = ({\n serverURL,\n path = window.location.pathname,\n selector = '.waline-comment-count',\n lang = 'zh-CN',\n}: // eslint-disable-next-line @typescript-eslint/no-explicit-any\nWalineCommentCountOptions): WalineAbort => {\n const controller = new AbortController();\n\n // comment count\n const elements = document.querySelectorAll<HTMLElement>(selector);\n\n if (elements.length)\n void fetchCommentCount({\n serverURL: getServerURL(serverURL),\n paths: Array.from(elements).map((element) =>\n decodePath(element.dataset.path || element.getAttribute('id') || path)\n ),\n lang,\n signal: controller.signal,\n })\n .then((counts) => {\n elements.forEach((element, index) => {\n element.innerText = counts[index].toString();\n });\n })\n .catch(errorHandler);\n\n return controller.abort.bind(controller);\n};\n","import { errorCheck } from './utils';\n\nexport interface FetchCommentCountOptions {\n serverURL: string;\n lang: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n lang,\n paths,\n signal,\n}: FetchCommentCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\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};\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\n\nconst LIKE_KEY = 'WALINE_LIKE';\n\nexport type LikeID = number | string;\n\nexport type LikeRef = Ref<LikeID[]>;\n\nlet likeStorage: LikeRef | null = null;\n\nexport const useLikeStorage = (): LikeRef =>\n likeStorage || (likeStorage = useStorage<LikeID[]>(LIKE_KEY, []));\n","import { load } from 'recaptcha-v3';\n\nimport type { ReCaptchaInstance } from 'recaptcha-v3';\n\nconst recaptchaStore: Record<string, Promise<ReCaptchaInstance>> = {};\n\ninterface ReCaptcha {\n execute: (action: string) => Promise<string>;\n}\n\nexport const useReCaptcha = (key: string): ReCaptcha => {\n const init =\n recaptchaStore[key] ??\n (recaptchaStore[key] = load(key, {\n useRecaptchaNet: true,\n autoHideBadge: true,\n }));\n\n return {\n execute: (action: string) =>\n init.then((instance) => instance.execute(action)),\n };\n};\n","import { useNow } from '@vueuse/core';\nimport { computed } from 'vue';\nimport { getTimeAgo } from '../utils';\n\nimport type { ComputedRef } from 'vue';\nimport type { WalineLocale } from '../typings';\n\nexport const useTimeAgo = (\n date: Date | string,\n locale: WalineLocale\n): ComputedRef<string> => {\n const now = useNow();\n\n return computed(() => getTimeAgo(date, now.value, locale));\n};\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\n\nconst VOTE_KEY = 'WALINE_VOTE';\n\nexport const VOTE_IDENTIFIER = 'id';\nexport const VOTE_INDEX = 'i';\n\nexport interface VoteLogItem {\n [VOTE_IDENTIFIER]: string;\n [VOTE_INDEX]: number;\n}\n\nexport type VoteRef = Ref<VoteLogItem[]>;\n\nlet voteStorage: VoteRef | null = null;\n\nexport const useVoteStorage = (): VoteRef =>\n (voteStorage ??= useStorage<VoteLogItem[]>(VOTE_KEY, []));\n","import { useStorage } from '@vueuse/core';\n\nimport type { Ref } from 'vue';\nimport type { UserInfo } from '../api';\n\nexport const USER_KEY = 'WALINE_USER';\n\nexport type UserInfoRef = Ref<UserInfo | Record<string, never>>;\n\nlet userInfoStorage: UserInfoRef | null = null;\n\nexport const useUserInfo = (): UserInfoRef =>\n (userInfoStorage ??= useStorage<UserInfo | Record<string, never>>(\n USER_KEY,\n {}\n ));\n","<template>\n <div v-if=\"reaction.length\" class=\"wl-reaction\">\n <h4 v-text=\"locale.reactionTitle\" />\n <ul>\n <li\n v-for=\"(item, index) in reaction\"\n :key=\"index\"\n :class=\"{ active: item.active }\"\n @click=\"vote(index)\"\n >\n <div class=\"wl-reaction-img\">\n <img :src=\"item.icon\" :alt=\"item.desc\" />\n <div class=\"wl-reaction-votes\">{{ item.vote }}</div>\n </div>\n <div class=\"wl-reaction-text\">{{ item.desc }}</div>\n </li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n defineComponent,\n inject,\n ComputedRef,\n computed,\n onMounted,\n onUnmounted,\n ref,\n} from 'vue';\nimport { fetchArticleCounter, updateArticleCounter } from '../api';\nimport { VOTE_IDENTIFIER, VOTE_INDEX, useVoteStorage } from '../composables';\nimport type { WalineConfig } from '../utils';\nimport type { WalineLocale } from '../typings';\n\ninterface ReactionItem {\n icon: string;\n vote: number;\n desc: string;\n active?: boolean;\n}\n\nexport default defineComponent({\n setup() {\n const votes = ref<ReactionItem['vote'][]>([]);\n const voteStorage = useVoteStorage();\n const config = inject<ComputedRef<WalineConfig>>('config')!;\n const locale = computed(() => config.value.locale);\n const reaction = computed((): ReactionItem[] => {\n const { reaction, path } = config.value;\n\n return reaction.map((icon, index) => ({\n icon,\n vote: votes.value[index] || 0,\n desc: locale.value[`reaction${index}` as keyof WalineLocale],\n active: Boolean(\n voteStorage.value.find(\n ({ [VOTE_IDENTIFIER]: voteIdentifier, [VOTE_INDEX]: voteIndex }) =>\n voteIdentifier === path && voteIndex === index\n )\n ),\n }));\n });\n\n let abort: () => void;\n\n const fetchCounter = (): void => {\n const { serverURL, lang, path, reaction } = config.value;\n\n if (reaction.length) {\n const controller = new AbortController();\n\n fetchArticleCounter({\n serverURL,\n lang,\n paths: [path],\n type: reaction.map((_, k) => `reaction${k}`),\n signal: controller.signal,\n }).then((resp) => {\n if (Array.isArray(resp) || typeof resp === 'number') return;\n votes.value = reaction.map((_, k) => resp[`reaction${k}`]);\n });\n\n abort = controller.abort.bind(controller);\n }\n };\n\n const vote = async (index: number): Promise<void> => {\n const { serverURL, lang, path } = config.value;\n const hasVoted = voteStorage.value.find(\n ({ [VOTE_IDENTIFIER]: voteIdentifier }) => voteIdentifier === path\n );\n const hasVotedTheReaction = hasVoted && hasVoted[VOTE_INDEX] === index;\n\n if (hasVotedTheReaction) return;\n\n await updateArticleCounter({\n serverURL,\n lang,\n path,\n type: `reaction${index}`,\n });\n\n votes.value[index] = (votes.value[index] || 0) + 1;\n if (hasVoted) {\n votes.value[hasVoted[VOTE_INDEX]] = Math.max(\n votes.value[hasVoted[VOTE_INDEX]] - 1,\n 0\n );\n updateArticleCounter({\n serverURL,\n lang,\n path,\n type: `reaction${hasVoted.i}`,\n action: 'desc',\n });\n\n hasVoted.i = index;\n voteStorage.value = Array.from(voteStorage.value);\n } else {\n voteStorage.value = [\n ...voteStorage.value,\n { [VOTE_IDENTIFIER]: path, [VOTE_INDEX]: index },\n ];\n }\n\n if (voteStorage.value.length > 50)\n voteStorage.value = voteStorage.value.slice(-50);\n };\n\n onMounted(() => fetchCounter());\n onUnmounted(() => abort?.());\n\n return {\n reaction,\n locale,\n vote,\n };\n },\n});\n</script>\n","import { h } from 'vue';\nimport type { FunctionalComponent } from 'vue';\n\nexport const CloseIcon: FunctionalComponent<{ size: number }> = ({ size }) =>\n h(\n 'svg',\n {\n class: 'wl-close-icon',\n viewBox: '0 0 1024 1024',\n width: size,\n height: size,\n },\n [\n h('path', {\n d: 'M697.173 85.333h-369.92c-144.64 0-241.92 101.547-241.92 252.587v348.587c0 150.613 97.28 252.16 241.92 252.16h369.92c144.64 0 241.494-101.547 241.494-252.16V337.92c0-151.04-96.854-252.587-241.494-252.587z',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'm640.683 587.52-75.947-75.861 75.904-75.862a37.29 37.29 0 0 0 0-52.778 37.205 37.205 0 0 0-52.779 0l-75.946 75.818-75.862-75.946a37.419 37.419 0 0 0-52.821 0 37.419 37.419 0 0 0 0 52.821l75.947 75.947-75.776 75.733a37.29 37.29 0 1 0 52.778 52.821l75.776-75.776 75.947 75.947a37.376 37.376 0 0 0 52.779-52.821z',\n fill: '#888',\n }),\n ]\n );\n\nexport const DeleteIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'm341.013 394.667 27.755 393.45h271.83l27.733-393.45h64.106l-28.01 397.952a64 64 0 0 1-63.83 59.498H368.768a64 64 0 0 1-63.83-59.52l-28.053-397.93h64.128zm139.307 19.818v298.667h-64V414.485h64zm117.013 0v298.667h-64V414.485h64zM181.333 288h640v64h-640v-64zm453.483-106.667v64h-256v-64h256z',\n fill: 'red',\n })\n );\n\nexport const EmojiIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M563.2 463.3 677 540c1.7 1.2 3.7 1.8 5.8 1.8.7 0 1.4-.1 2-.2 2.7-.5 5.1-2.1 6.6-4.4l25.3-37.8c1.5-2.3 2.1-5.1 1.6-7.8s-2.1-5.1-4.4-6.6l-73.6-49.1 73.6-49.1c2.3-1.5 3.9-3.9 4.4-6.6.5-2.7 0-5.5-1.6-7.8l-25.3-37.8a10.1 10.1 0 0 0-6.6-4.4c-.7-.1-1.3-.2-2-.2-2.1 0-4.1.6-5.8 1.8l-113.8 76.6c-9.2 6.2-14.7 16.4-14.7 27.5.1 11 5.5 21.3 14.7 27.4zM387 348.8h-45.5c-5.7 0-10.4 4.7-10.4 10.4v153.3c0 5.7 4.7 10.4 10.4 10.4H387c5.7 0 10.4-4.7 10.4-10.4V359.2c0-5.7-4.7-10.4-10.4-10.4zm333.8 241.3-41-20a10.3 10.3 0 0 0-8.1-.5c-2.6.9-4.8 2.9-5.9 5.4-30.1 64.9-93.1 109.1-164.4 115.2-5.7.5-9.9 5.5-9.5 11.2l3.9 45.5c.5 5.3 5 9.5 10.3 9.5h.9c94.8-8 178.5-66.5 218.6-152.7 2.4-5 .3-11.2-4.8-13.6zm186-186.1c-11.9-42-30.5-81.4-55.2-117.1-24.1-34.9-53.5-65.6-87.5-91.2-33.9-25.6-71.5-45.5-111.6-59.2-41.2-14-84.1-21.1-127.8-21.1h-1.2c-75.4 0-148.8 21.4-212.5 61.7-63.7 40.3-114.3 97.6-146.5 165.8-32.2 68.1-44.3 143.6-35.1 218.4 9.3 74.8 39.4 145 87.3 203.3.1.2.3.3.4.5l36.2 38.4c1.1 1.2 2.5 2.1 3.9 2.6 73.3 66.7 168.2 103.5 267.5 103.5 73.3 0 145.2-20.3 207.7-58.7 37.3-22.9 70.3-51.5 98.1-85 27.1-32.7 48.7-69.5 64.2-109.1 15.5-39.7 24.4-81.3 26.6-123.8 2.4-43.6-2.5-87-14.5-129zm-60.5 181.1c-8.3 37-22.8 72-43 104-19.7 31.1-44.3 58.6-73.1 81.7-28.8 23.1-61 41-95.7 53.4-35.6 12.7-72.9 19.1-110.9 19.1-82.6 0-161.7-30.6-222.8-86.2l-34.1-35.8c-23.9-29.3-42.4-62.2-55.1-97.7-12.4-34.7-18.8-71-19.2-107.9-.4-36.9 5.4-73.3 17.1-108.2 12-35.8 30-69.2 53.4-99.1 31.7-40.4 71.1-72 117.2-94.1 44.5-21.3 94-32.6 143.4-32.6 49.3 0 97 10.8 141.8 32 34.3 16.3 65.3 38.1 92 64.8 26.1 26 47.5 56 63.6 89.2 16.2 33.2 26.6 68.5 31 105.1 4.6 37.5 2.7 75.3-5.6 112.3z',\n fill: 'currentColor',\n })\n );\n\nexport const ImageIcon: FunctionalComponent = () =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: 'M784 112H240c-88 0-160 72-160 160v480c0 88 72 160 160 160h544c88 0 160-72 160-160V272c0-88-72-160-160-160zm96 640c0 52.8-43.2 96-96 96H240c-52.8 0-96-43.2-96-96V272c0-52.8 43.2-96 96-96h544c52.8 0 96 43.2 96 96v480z',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'M352 480c52.8 0 96-43.2 96-96s-43.2-96-96-96-96 43.2-96 96 43.2 96 96 96zm0-128c17.6 0 32 14.4 32 32s-14.4 32-32 32-32-14.4-32-32 14.4-32 32-32zm462.4 379.2-3.2-3.2-177.6-177.6c-25.6-25.6-65.6-25.6-91.2 0l-80 80-36.8-36.8c-25.6-25.6-65.6-25.6-91.2 0L200 728c-4.8 6.4-8 14.4-8 24 0 17.6 14.4 32 32 32 9.6 0 16-3.2 22.4-9.6L380.8 640l134.4 134.4c6.4 6.4 14.4 9.6 24 9.6 17.6 0 32-14.4 32-32 0-9.6-4.8-17.6-9.6-24l-52.8-52.8 80-80L769.6 776c6.4 4.8 12.8 8 20.8 8 17.6 0 32-14.4 32-32 0-8-3.2-16-8-20.8z',\n fill: 'currentColor',\n }),\n ]);\n\nexport const LikeIcon: FunctionalComponent<{ active: boolean }> = ({\n active = false,\n}: {\n active?: boolean;\n}) =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: `M850.654 323.804c-11.042-25.625-26.862-48.532-46.885-68.225-20.022-19.61-43.258-34.936-69.213-45.73-26.78-11.124-55.124-16.727-84.375-16.727-40.622 0-80.256 11.123-114.698 32.135A214.79 214.79 0 0 0 512 241.819a214.79 214.79 0 0 0-23.483-16.562c-34.442-21.012-74.076-32.135-114.698-32.135-29.25 0-57.595 5.603-84.375 16.727-25.872 10.711-49.19 26.12-69.213 45.73-20.105 19.693-35.843 42.6-46.885 68.225-11.453 26.615-17.303 54.877-17.303 83.963 0 27.439 5.603 56.03 16.727 85.117 9.31 24.307 22.659 49.52 39.715 74.981 27.027 40.293 64.188 82.316 110.33 124.915 76.465 70.615 152.189 119.394 155.402 121.371l19.528 12.525c8.652 5.52 19.776 5.52 28.427 0l19.529-12.525c3.213-2.06 78.854-50.756 155.401-121.371 46.143-42.6 83.304-84.622 110.33-124.915 17.057-25.46 30.487-50.674 39.716-74.981 11.124-29.087 16.727-57.678 16.727-85.117.082-29.086-5.768-57.348-17.221-83.963z${\n active\n ? ''\n : 'M512 761.5S218.665 573.55 218.665 407.767c0-83.963 69.461-152.023 155.154-152.023 60.233 0 112.473 33.618 138.181 82.727 25.708-49.109 77.948-82.727 138.18-82.727 85.694 0 155.155 68.06 155.155 152.023C805.335 573.551 512 761.5 512 761.5z'\n }`,\n fill: active ? 'red' : 'currentColor',\n }),\n ]);\n\nexport const PreviewIcon: FunctionalComponent = () =>\n h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [\n h('path', {\n d: 'M710.816 654.301c70.323-96.639 61.084-230.578-23.705-314.843-46.098-46.098-107.183-71.109-172.28-71.109-65.008 0-126.092 25.444-172.28 71.109-45.227 46.098-70.756 107.183-70.756 172.106 0 64.923 25.444 126.007 71.194 172.106 46.099 46.098 107.184 71.109 172.28 71.109 51.414 0 100.648-16.212 142.824-47.404l126.53 126.006c7.058 7.06 16.297 10.979 26.406 10.979 10.105 0 19.343-3.919 26.402-10.979 14.467-14.467 14.467-38.172 0-52.723L710.816 654.301zm-315.107-23.265c-65.88-65.88-65.88-172.54 0-238.42 32.069-32.07 74.245-49.149 119.471-49.149 45.227 0 87.407 17.603 119.472 49.149 65.88 65.879 65.88 172.539 0 238.42-63.612 63.178-175.242 63.178-238.943 0zm0 0',\n fill: 'currentColor',\n }),\n h('path', {\n d: 'M703.319 121.603H321.03c-109.8 0-199.469 89.146-199.469 199.38v382.034c0 109.796 89.236 199.38 199.469 199.38h207.397c20.653 0 37.384-16.645 37.384-37.299 0-20.649-16.731-37.296-37.384-37.296H321.03c-68.582 0-124.352-55.77-124.352-124.267V321.421c0-68.496 55.77-124.267 124.352-124.267h382.289c68.582 0 124.352 55.771 124.352 124.267V524.72c0 20.654 16.736 37.299 37.385 37.299 20.654 0 37.384-16.645 37.384-37.299V320.549c-.085-109.8-89.321-198.946-199.121-198.946zm0 0',\n fill: 'currentColor',\n }),\n ]);\n\nexport const MarkdownIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { width: '16', height: '16', ariaHidden: 'true' },\n h('path', {\n d: 'M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z',\n fill: 'currentColor',\n })\n );\n\nexport const ReplyIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M810.667 213.333a64 64 0 0 1 64 64V704a64 64 0 0 1-64 64H478.336l-146.645 96.107a21.333 21.333 0 0 1-33.024-17.856V768h-85.334a64 64 0 0 1-64-64V277.333a64 64 0 0 1 64-64h597.334zm0 64H213.333V704h149.334v63.296L459.243 704h351.424V277.333zm-271.36 213.334v64h-176.64v-64h176.64zm122.026-128v64H362.667v-64h298.666z',\n fill: 'currentColor',\n })\n );\n\nexport const EditIcon: FunctionalComponent = () =>\n h(\n 'svg',\n { viewBox: '0 0 1024 1024', width: '24', height: '24' },\n h('path', {\n d: 'M813.039 318.772L480.53 651.278H360.718V531.463L693.227 198.961C697.904 194.284 704.027 192 710.157 192C716.302 192 722.436 194.284 727.114 198.961L813.039 284.88C817.72 289.561 820 295.684 820 301.825C820 307.95 817.72 314.093 813.039 318.772ZM710.172 261.888L420.624 551.431V591.376H460.561L750.109 301.825L710.172 261.888ZM490.517 291.845H240.906V771.09H720.156V521.479C720.156 504.947 733.559 491.529 750.109 491.529C766.653 491.529 780.063 504.947 780.063 521.479V791.059C780.063 813.118 762.18 831 740.125 831H220.937C198.882 831 181 813.118 181 791.059V271.872C181 249.817 198.882 231.935 220.937 231.935H490.517C507.06 231.935 520.47 245.352 520.47 261.888C520.47 278.424 507.06 291.845 490.517 291.845Z',\n fill: 'currentColor',\n })\n );\n\nexport const VerifiedIcon: FunctionalComponent = () =>\n h(\n 'svg',\n {\n class: 'verified-icon',\n viewBox: '0 0 1024 1024',\n width: '14',\n height: '14',\n },\n h('path', {\n d: 'm894.4 461.56-54.4-63.2c-10.4-12-18.8-34.4-18.8-50.4v-68c0-42.4-34.8-77.2-77.2-77.2h-68c-15.6 0-38.4-8.4-50.4-18.8l-63.2-54.4c-27.6-23.6-72.8-23.6-100.8 0l-62.8 54.8c-12 10-34.8 18.4-50.4 18.4h-69.2c-42.4 0-77.2 34.8-77.2 77.2v68.4c0 15.6-8.4 38-18.4 50l-54 63.6c-23.2 27.6-23.2 72.4 0 100l54 63.6c10 12 18.4 34.4 18.4 50v68.4c0 42.4 34.8 77.2 77.2 77.2h69.2c15.6 0 38.4 8.4 50.4 18.8l63.2 54.4c27.6 23.6 72.8 23.6 100.8 0l63.2-54.4c12-10.4 34.4-18.8 50.4-18.8h68c42.4 0 77.2-34.8 77.2-77.2v-68c0-15.6 8.4-38.4 18.8-50.4l54.4-63.2c23.2-27.6 23.2-73.2-.4-100.8zm-216-25.2-193.2 193.2a30 30 0 0 1-42.4 0l-96.8-96.8a30.16 30.16 0 0 1 0-42.4c11.6-11.6 30.8-11.6 42.4 0l75.6 75.6 172-172c11.6-11.6 30.8-11.6 42.4 0 11.6 11.6 11.6 30.8 0 42.4z',\n fill: '#27ae60',\n })\n );\n\nexport const LoadingIcon: FunctionalComponent<{ size: number }> = ({ size }) =>\n h(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 100 100',\n preserveAspectRatio: 'xMidYMid',\n },\n h(\n 'circle',\n {\n cx: 50,\n cy: 50,\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: '4',\n r: '40',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'stroke-dasharray': '85 30',\n },\n h('animateTransform', {\n attributeName: 'transform',\n type: 'rotate',\n repeatCount: 'indefinite',\n dur: '1s',\n values: '0 50 50;360 50 50',\n keyTimes: '0;1',\n })\n )\n );\n\nexport const GifIcon: FunctionalComponent = () =>\n h(\n 'svg',\n {\n width: 24,\n height: 24,\n fill: 'currentcolor',\n viewBox: '0 0 24 24',\n },\n [\n h('path', {\n style: 'transform: translateY(0.5px)',\n d: 'M18.968 10.5H15.968V11.484H17.984V12.984H15.968V15H14.468V9H18.968V10.5V10.5ZM8.984 9C9.26533 9 9.49967 9.09367 9.687 9.281C9.87433 9.46833 9.968 9.70267 9.968 9.984V10.5H6.499V13.5H8.468V12H9.968V14.016C9.968 14.2973 9.87433 14.5317 9.687 14.719C9.49967 14.9063 9.26533 15 8.984 15H5.984C5.70267 15 5.46833 14.9063 5.281 14.719C5.09367 14.5317 5 14.2973 5 14.016V9.985C5 9.70367 5.09367 9.46933 5.281 9.282C5.46833 9.09467 5.70267 9.001 5.984 9.001H8.984V9ZM11.468 9H12.968V15H11.468V9V9Z',\n }),\n h('path', {\n d: 'M18.5 3H5.75C3.6875 3 2 4.6875 2 6.75V18C2 20.0625 3.6875 21.75 5.75 21.75H18.5C20.5625 21.75 22.25 20.0625 22.25 18V6.75C22.25 4.6875 20.5625 3 18.5 3ZM20.75 18C20.75 19.2375 19.7375 20.25 18.5 20.25H5.75C4.5125 20.25 3.5 19.2375 3.5 18V6.75C3.5 5.5125 4.5125 4.5 5.75 4.5H18.5C19.7375 4.5 20.75 5.5125 20.75 6.75V18Z',\n }),\n ]\n );\n","<!-- forked from https://github.com/DerYeger/vue-masonry-wall/blob/master/src/masonry-wall.vue -->\n\n<!-- MIT License\n\nCopyright (c) 2021 Fuxing Loh, Jan Müller\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE. -->\n\n<template>\n <div ref=\"wall\" class=\"wl-gallery\" :style=\"{ gap: `${gap}px` }\">\n <div\n v-for=\"(column, columnIndex) in columns\"\n :key=\"columnIndex\"\n class=\"wl-gallery-column\"\n :data-index=\"columnIndex\"\n :style=\"{ gap: `${gap}px` }\"\n >\n <template v-for=\"itemIndex in column\" :key=\"itemIndex\">\n <LoadingIcon\n v-if=\"!state[items[itemIndex].src]\"\n :size=\"36\"\n style=\"margin: 20px auto\"\n />\n <img\n class=\"wl-gallery-item\"\n :src=\"items[itemIndex].src\"\n :title=\"items[itemIndex].title\"\n loading=\"lazy\"\n @load=\"imageLoad\"\n @click=\"$emit('insert', `![](${items[itemIndex].src})`)\"\n />\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n defineComponent,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n watch,\n} from 'vue';\n\nimport { LoadingIcon } from './Icons';\n\nimport type { PropType } from 'vue';\nimport type { WalineSearchResult } from '../typings';\n\ntype Column = number[];\n\nexport default defineComponent({\n name: 'ImageWall',\n\n components: {\n LoadingIcon,\n },\n\n props: {\n items: { type: Array as PropType<WalineSearchResult>, default: () => [] },\n columnWidth: { type: Number, default: 300 },\n gap: { type: Number, default: 0 },\n },\n\n emits: ['insert'],\n\n setup(props) {\n let resizeObserver: ResizeObserver | null = null;\n const wall = ref<HTMLDivElement | null>(null);\n const state = ref<Record<string, boolean>>({});\n const columns = ref<Column[]>([]);\n\n const getColumnCount = (): number => {\n const count = Math.floor(\n (wall.value!.getBoundingClientRect().width + props.gap) /\n (props.columnWidth + props.gap)\n );\n\n return count > 0 ? count : 1;\n };\n\n const createColumns = (count: number): Column[] =>\n new Array(count).fill(null).map(() => []);\n\n const fillColumns = async (itemIndex: number): Promise<void> => {\n if (itemIndex >= props.items.length) return;\n\n await nextTick();\n\n const columnDivs = Array.from(\n wall.value?.children || []\n ) as HTMLDivElement[];\n\n const target = columnDivs.reduce((prev, curr) =>\n curr.getBoundingClientRect().height <\n prev.getBoundingClientRect().height\n ? curr\n : prev\n );\n\n columns.value[Number(target.dataset.index)].push(itemIndex);\n\n await fillColumns(itemIndex + 1);\n };\n\n const redraw = async (force = false): Promise<void> => {\n if (columns.value.length === getColumnCount() && !force) return;\n\n columns.value = createColumns(getColumnCount());\n\n const scrollY = window.scrollY;\n\n await fillColumns(0);\n\n window.scrollTo({ top: scrollY });\n };\n\n const imageLoad = (e: Event) => {\n state.value[(e.target as HTMLImageElement).src] = true;\n };\n\n watch(\n () => [props.items],\n () => {\n state.value = {};\n redraw(true);\n }\n );\n watch(\n () => [props.columnWidth, props.gap],\n () => redraw()\n );\n\n onMounted(() => {\n redraw(true);\n resizeObserver = new ResizeObserver(() => redraw());\n\n resizeObserver.observe(wall.value!);\n });\n\n onBeforeUnmount(() => resizeObserver!.unobserve(wall.value!));\n\n return {\n columns,\n state,\n wall,\n imageLoad,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-comment\">\n <div\n v-if=\"config.login !== 'disable' && isLogin && !edit?.objectId\"\n class=\"wl-login-info\"\n >\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"Profile\"\n :title=\"locale.profile\"\n @click=\"onProfile\"\n >\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </a>\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"Profile\"\n :title=\"locale.profile\"\n @click=\"onProfile\"\n v-text=\"userInfo.display_name\"\n />\n </div>\n\n <div class=\"wl-panel\">\n <div\n v-if=\"config.login !== 'force' && config.meta.length && !isLogin\"\n :class=\"['wl-header', `item${config.meta.length}`]\"\n >\n <div v-for=\"kind in config.meta\" :key=\"kind\" class=\"wl-header-item\">\n <label\n :for=\"`wl-${kind}`\"\n v-text=\"\n locale[kind] +\n (config.requiredMeta.includes(kind) || !config.requiredMeta.length\n ? ''\n : `(${locale.optional})`)\n \"\n />\n <input\n :id=\"`wl-${kind}`\"\n :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element as HTMLInputElement;\n }\n \"\n v-model=\"userMeta[kind]\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n />\n </div>\n </div>\n\n <textarea\n id=\"wl-edit\"\n ref=\"editorRef\"\n v-model=\"editor\"\n class=\"wl-editor\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div v-show=\"showPreview\" class=\"wl-preview\">\n <hr />\n <h4>{{ locale.preview }}:</h4>\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div class=\"wl-content\" v-html=\"previewText\" />\n </div>\n\n <div class=\"wl-footer\">\n <div class=\"wl-actions\">\n <a\n href=\"https://guides.github.com/features/mastering-markdown/\"\n title=\"Markdown Guide\"\n aria-label=\"Markdown is supported\"\n class=\"wl-action\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n <MarkdownIcon />\n </a>\n\n <button\n v-show=\"emoji.tabs.length\"\n ref=\"emojiButtonRef\"\n class=\"wl-action\"\n :class=\"{ actived: showEmoji }\"\n :title=\"locale.emoji\"\n @click=\"showEmoji = !showEmoji\"\n >\n <EmojiIcon />\n </button>\n\n <button\n v-if=\"config.search\"\n ref=\"gifButtonRef\"\n class=\"wl-action\"\n :class=\"{ actived: showGif }\"\n :title=\"locale.gif\"\n @click=\"showGif = !showGif\"\n >\n <GifIcon />\n </button>\n\n <input\n id=\"wl-image-upload\"\n ref=\"imageUploadRef\"\n class=\"upload\"\n type=\"file\"\n accept=\".png,.jpg,.jpeg,.webp,.bmp,.gif\"\n @change=\"onChange\"\n />\n\n <label\n v-if=\"canUploadImage\"\n for=\"wl-image-upload\"\n class=\"wl-action\"\n :title=\"locale.uploadImage\"\n >\n <ImageIcon />\n </label>\n\n <button\n class=\"wl-action\"\n :class=\"{ actived: showPreview }\"\n :title=\"locale.preview\"\n @click=\"showPreview = !showPreview\"\n >\n <PreviewIcon />\n </button>\n </div>\n\n <div class=\"wl-info\">\n <div class=\"wl-text-number\">\n {{ wordNumber }}\n\n <span v-if=\"config.wordLimit\">\n &nbsp;/&nbsp;\n <span\n :class=\"{ illegal: !isWordNumberLegal }\"\n v-text=\"wordLimit\"\n />\n </span>\n\n &nbsp;{{ locale.word }}\n </div>\n\n <button\n v-if=\"config.login !== 'disable' && !isLogin\"\n class=\"wl-btn\"\n @click=\"onLogin\"\n v-text=\"locale.login\"\n />\n\n <button\n v-if=\"config.login !== 'force' || isLogin\"\n class=\"wl-btn primary\"\n title=\"Cmd|Ctrl + Enter\"\n :disabled=\"isSubmitting\"\n @click=\"submitComment\"\n >\n <LoadingIcon v-if=\"isSubmitting\" :size=\"16\" />\n <template v-else>\n {{ locale.submit }}\n </template>\n </button>\n </div>\n\n <div\n ref=\"gifPopupRef\"\n class=\"wl-gif-popup\"\n :class=\"{ display: showGif }\"\n >\n <input\n ref=\"gifSearchInputRef\"\n type=\"text\"\n :placeholder=\"locale.gifSearchPlaceholder\"\n @input=\"onGifSearch\"\n />\n\n <ImageWall\n :items=\"gifData.list\"\n :column-width=\"200\"\n :gap=\"6\"\n @insert=\"insert($event)\"\n @scroll=\"onImageWallScroll\"\n >\n </ImageWall>\n\n <div v-if=\"gifData.loading\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n </div>\n <div\n ref=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template\n v-for=\"(emojiItem, index) in emoji.tabs\"\n :key=\"emojiItem.name\"\n >\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in emojiItem.items\"\n :key=\"key\"\n :title=\"key\"\n @click=\"insert(`:${key}:`)\"\n >\n <img\n v-if=\"showEmoji\"\n class=\"wl-emoji\"\n :src=\"emoji.map[key]\"\n :alt=\"key\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n />\n </button>\n </div>\n </template>\n <div v-if=\"emoji.tabs.length > 1\" class=\"wl-tabs\">\n <button\n v-for=\"(emojiItem, index) in emoji.tabs\"\n :key=\"emojiItem.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"emojiItem.icon\"\n :alt=\"emojiItem.name\"\n :title=\"emojiItem.name\"\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n />\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <button\n v-if=\"replyId || edit?.objectId\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit(replyId ? 'cancel-reply' : 'cancel-edit')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { useDebounceFn } from '@vueuse/core';\nimport { useReCaptcha } from '../composables';\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n PropType,\n reactive,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n GifIcon,\n} from './Icons';\nimport ImageWall from './ImageWall.vue';\nimport { login, postComment } from '../api';\nimport { useEditor, useUserMeta, useUserInfo } from '../composables';\nimport {\n getEmojis,\n getImagefromDataTransfer,\n getWordNumber,\n parseEmoji,\n parseMarkdown,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type {\n WalineComment,\n WalineCommentData,\n WalineImageUploader,\n WalineSearchOptions,\n WalineSearchResult,\n} from '../typings';\nimport type { WalineConfig, WalineEmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n ImageWall,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n GifIcon,\n },\n\n props: {\n rootId: {\n type: String,\n default: '',\n },\n replyId: {\n type: String,\n default: '',\n },\n replyUser: {\n type: String,\n default: '',\n },\n edit: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n },\n\n emits: ['submit', 'cancel-reply', 'cancel-edit'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<WalineConfig>>('config')!;\n\n const editor = useEditor();\n const userMeta = useUserMeta();\n const userInfo = useUserInfo();\n\n const inputRefs = ref<Record<string, HTMLInputElement>>({});\n const editorRef = ref<HTMLTextAreaElement | null>(null);\n const imageUploadRef = ref<HTMLInputElement | null>(null);\n const emojiButtonRef = ref<HTMLDivElement | null>(null);\n const emojiPopupRef = ref<HTMLDivElement | null>(null);\n const gifButtonRef = ref<HTMLDivElement | null>(null);\n const gifPopupRef = ref<HTMLDivElement | null>(null);\n const gifSearchInputRef = ref<HTMLInputElement | null>(null);\n\n const emoji = ref<DeepReadonly<WalineEmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showGif = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\n\n const searchResults = reactive({\n loading: true,\n list: [] as WalineSearchResult,\n });\n\n const wordLimit = ref(0);\n const isWordNumberLegal = ref(false);\n\n const content = ref('');\n\n const isSubmitting = ref(false);\n\n const locale = computed(() => config.value.locale);\n\n const isLogin = computed(() => Boolean(userInfo.value?.token));\n\n const canUploadImage = computed(() => config.value.imageUploader !== false);\n\n const insert = (content: string): void => {\n const textArea = editorRef.value!;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n editor.value =\n textArea.value.substring(0, startPosition) +\n content +\n textArea.value.substring(endPosition, textArea.value.length);\n textArea.focus();\n textArea.selectionStart = startPosition + content.length;\n textArea.selectionEnd = startPosition + content.length;\n textArea.scrollTop = scrollTop;\n };\n\n const onKeyDown = (event: KeyboardEvent): void => {\n const key = event.key;\n\n // Shortcut key\n if ((event.ctrlKey || event.metaKey) && key === 'Enter') submitComment();\n };\n\n const uploadImage = (file: File): Promise<void> => {\n const uploadText = `![${config.value.locale.uploading} ${file.name}]()`;\n\n insert(uploadText);\n\n return Promise.resolve()\n .then(() => (config.value.imageUploader as WalineImageUploader)(file))\n .then((url) => {\n editor.value = editor.value.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\n })\n .catch((e) => {\n alert(e.message);\n editor.value = editor.value.replace(uploadText, '');\n });\n };\n\n const onDrop = (event: DragEvent): void => {\n if (event.dataTransfer?.items) {\n const file = getImagefromDataTransfer(event.dataTransfer.items);\n\n if (file && canUploadImage.value) {\n uploadImage(file);\n event.preventDefault();\n }\n }\n };\n\n const onPaste = (event: ClipboardEvent): void => {\n if (event.clipboardData) {\n const file = getImagefromDataTransfer(event.clipboardData.items);\n\n if (file && canUploadImage.value) uploadImage(file);\n }\n };\n\n const onChange = (): void => {\n const inputElement = imageUploadRef.value!;\n\n if (inputElement.files && canUploadImage.value)\n uploadImage(inputElement.files[0]).then(() => {\n // clear input so a same image can be uploaded later\n inputElement.value = '';\n });\n };\n\n const submitComment = async (): Promise<void> => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n let token = '';\n\n if (config.value.recaptchaV3Key)\n token = await useReCaptcha(config.value.recaptchaV3Key).execute(\n 'social'\n );\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: userMeta.value.nick,\n mail: userMeta.value.mail,\n link: userMeta.value.link,\n ua: navigator.userAgent,\n url: config.value.path,\n recaptchaV3: token,\n };\n\n if (userInfo.value?.token) {\n // login user\n\n comment.nick = userInfo.value.display_name;\n comment.mail = userInfo.value.email;\n comment.link = userInfo.value.url;\n } else {\n if (login === 'force') return;\n\n // check nick\n if (requiredMeta.indexOf('nick') > -1 && !comment.nick) {\n inputRefs.value.nick?.focus();\n\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (\n (requiredMeta.indexOf('mail') > -1 && !comment.mail) ||\n (comment.mail &&\n !/^\\w(?:[\\w._-]*\\w)?@(?:\\w(?:[\\w-]*\\w)?\\.)*\\w+$/.exec(comment.mail))\n ) {\n inputRefs.value.mail?.focus();\n\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\n\n return;\n }\n\n if (!comment.nick) comment.nick = locale.value.anonymous;\n }\n\n if (!isWordNumberLegal.value)\n return alert(\n locale.value.wordHint\n .replace('$0', (wordLimit as [number, number])[0].toString())\n .replace('$1', (wordLimit as [number, number])[1].toString())\n .replace('$2', wordNumber.value.toString())\n );\n\n comment.comment = parseEmoji(comment.comment, emoji.value.map);\n\n if (props.replyId && props.rootId) {\n comment.pid = props.replyId;\n comment.rid = props.rootId;\n comment.at = props.replyUser;\n } else if (props.edit) {\n comment.eid = props.edit.objectId;\n }\n\n isSubmitting.value = true;\n\n postComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n comment,\n })\n .then((resp) => {\n isSubmitting.value = false;\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n emit('submit', resp.data!);\n\n editor.value = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\n if (props.edit?.objectId) emit('cancel-edit');\n })\n .catch((err: TypeError) => {\n isSubmitting.value = false;\n\n alert(err.message);\n });\n };\n\n const onLogin = (event: Event): void => {\n event.preventDefault();\n const { lang, serverURL } = config.value;\n\n login({\n serverURL,\n lang,\n }).then((data) => {\n userInfo.value = data;\n (data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data)\n );\n });\n };\n\n const onLogout = (): void => {\n userInfo.value = {};\n localStorage.setItem('WALINE_USER', 'null');\n sessionStorage.setItem('WALINE_USER', 'null');\n };\n\n const onProfile = (event: Event): void => {\n event.preventDefault();\n\n const { lang, serverURL } = config.value;\n\n const width = 800;\n const height = 800;\n const left = (window.innerWidth - width) / 2;\n const top = (window.innerHeight - height) / 2;\n const handler = window.open(\n `${serverURL}/ui/profile?lng=${encodeURIComponent(lang)}`,\n '_blank',\n `width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`\n );\n\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !emojiButtonRef.value!.contains(event.target as Node) &&\n !emojiPopupRef.value!.contains(event.target as Node)\n )\n showEmoji.value = false;\n\n if (\n !gifButtonRef.value!.contains(event.target as Node) &&\n !gifPopupRef.value!.contains(event.target as Node)\n )\n showGif.value = false;\n };\n\n const onImageWallScroll = async (event: Event): Promise<void> => {\n const { scrollTop, clientHeight, scrollHeight } =\n event.target as HTMLDivElement;\n const percent = (clientHeight + scrollTop) / scrollHeight;\n const searchOptions = config.value.search as WalineSearchOptions;\n const keyword = gifSearchInputRef.value?.value || '';\n\n if (percent < 0.9 || searchResults.loading) return;\n\n searchResults.loading = true;\n\n searchResults.list = [\n ...searchResults.list,\n ...(searchOptions.more && searchResults.list.length\n ? await searchOptions.more(keyword, searchResults.list.length)\n : await searchOptions.search(keyword)),\n ];\n\n searchResults.loading = false;\n\n setTimeout(() => {\n (event.target as HTMLDivElement).scrollTop = scrollTop;\n }, 50);\n };\n\n const onGifSearch = useDebounceFn((event: Event) => {\n searchResults.list = [];\n onImageWallScroll(event);\n }, 300);\n\n // update wordNumber\n watch(\n [config, wordNumber],\n ([config, wordNumber]) => {\n const { wordLimit: limit } = config;\n\n if (limit) {\n if (wordNumber < limit[0] && limit[0] !== 0) {\n wordLimit.value = limit[0];\n isWordNumberLegal.value = false;\n } else if (wordNumber > limit[1]) {\n wordLimit.value = limit[1];\n isWordNumberLegal.value = false;\n } else {\n wordLimit.value = limit[1];\n isWordNumberLegal.value = true;\n }\n } else {\n wordLimit.value = 0;\n isWordNumberLegal.value = true;\n }\n },\n { immediate: true }\n );\n\n watch(showGif, async (showGif) => {\n if (!showGif) return;\n\n const searchOptions = config.value.search as WalineSearchOptions;\n\n // clear input\n if (gifSearchInputRef.value) gifSearchInputRef.value.value = '';\n\n searchResults.loading = true;\n\n searchResults.list = searchOptions.default\n ? await searchOptions.default()\n : await searchOptions.search('');\n\n searchResults.loading = false;\n });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const onMessageRecive = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n userInfo.value = { ...userInfo.value, ...data.data };\n\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n };\n\n onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n window.addEventListener('message', onMessageRecive);\n if (props.edit?.objectId) {\n editor.value = props.edit.orig;\n }\n\n // watch editor\n watch(\n () => editor.value,\n (value) => {\n const { highlighter, texRenderer } = config.value;\n\n content.value = value;\n previewText.value = parseMarkdown(value, {\n emojiMap: emoji.value.map,\n highlighter,\n texRenderer,\n });\n wordNumber.value = getWordNumber(value);\n\n if (value) autosize(editorRef.value!);\n else autosize.destroy(editorRef.value!);\n },\n { immediate: true }\n );\n\n // watch emoji value change\n watch(\n () => config.value.emoji,\n (emojiConfig) =>\n getEmojis(Array.isArray(emojiConfig) ? emojiConfig : []).then(\n (config) => {\n emoji.value = config;\n }\n ),\n { immediate: true }\n );\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\n window.removeEventListener('message', onMessageRecive);\n });\n\n return {\n // config\n config,\n locale,\n\n // events\n insert,\n onChange,\n onDrop,\n onKeyDown,\n onPaste,\n onLogin,\n onLogout,\n onProfile,\n submitComment,\n onImageWallScroll,\n onGifSearch,\n\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n editor,\n userMeta,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // gif\n gifData: searchResults,\n showGif,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n gifButtonRef,\n gifPopupRef,\n imageUploadRef,\n gifSearchInputRef,\n };\n },\n});\n</script>\n","import { useStorage } from '@vueuse/core';\nimport type { RemovableRef } from '@vueuse/core';\n\nexport interface UserMeta {\n nick: string;\n mail: string;\n link: string;\n}\n\nexport const useUserMeta = (): RemovableRef<UserMeta> =>\n useStorage<UserMeta>('WALINE_USER_META', {\n nick: '',\n mail: '',\n link: '',\n });\n\nexport const useEditor = (): RemovableRef<string> =>\n useStorage<string>('WALINE_COMMENT_BOX_EDITOR', '');\n","/**\n * The wordCount module should be lightweight as it's packed into client.\n *\n * So We just make a simple implement here\n *\n * Forked from https://github.com/vuepress-theme-hope/vuepress-theme-hope/blob/main/packages/reading-time2/src/node/reading-time.ts\n */\n\nexport const getWords = (content: string): string[] =>\n content.match(/[\\w\\d\\s\\u00C0-\\u024F]+/giu) || [];\n\nexport const getChinese = (content: string): string[] =>\n content.match(/[\\u4E00-\\u9FA5]/gu) || [];\n\nexport const getWordNumber = (content: string): number =>\n getWords(content).reduce(\n (accumulator, word) =>\n accumulator + (word.trim() === '' ? 0 : word.trim().split(/\\s+/u).length),\n 0\n ) + getChinese(content).length;\n","/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nexport interface LoginOptions {\n lang: string;\n serverURL: string;\n}\n\nexport interface UserInfo {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n display_name: string;\n email: string;\n url: string;\n token: string;\n avatar: string;\n mailMd5: string;\n objectId: string | number;\n type: 'administrator' | 'guest';\n}\n\nexport const login = ({\n lang,\n serverURL,\n}: LoginOptions): Promise<UserInfo & { remember: boolean }> => {\n const width = 450;\n const height = 450;\n const left = (window.innerWidth - width) / 2;\n const top = (window.innerHeight - height) / 2;\n\n const handler = window.open(\n `${serverURL}/ui/login?lng=${encodeURIComponent(lang)}`,\n '_blank',\n `width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`\n );\n\n handler?.postMessage({ type: 'TOKEN', data: null }, '*');\n\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || typeof data !== 'object' || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n\n window.removeEventListener('message', receiver);\n\n resolve(data.data as UserInfo & { remember: boolean });\n }\n };\n\n window.addEventListener('message', receiver);\n });\n};\n","<template>\n <div :id=\"comment.objectId\" class=\"wl-item\">\n <div class=\"wl-user\" aria-hidden=\"true\">\n <img v-if=\"comment.avatar\" :src=\"comment.avatar\" />\n <VerifiedIcon v-if=\"comment.type\" />\n </div>\n\n <div class=\"wl-card\">\n <div class=\"wl-head\">\n <a\n v-if=\"link\"\n class=\"wl-nick\"\n :href=\"link\"\n target=\"_blank\"\n rel=\"nofollow noreferrer\"\n >{{ comment.nick }}</a\n >\n <span v-else class=\"wl-nick\">{{ comment.nick }}</span>\n\n <span\n v-if=\"comment.type === 'administrator'\"\n class=\"wl-badge\"\n v-text=\"locale.admin\"\n />\n <span v-if=\"comment.label\" class=\"wl-badge\" v-text=\"comment.label\" />\n <span v-if=\"comment.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n <span\n v-if=\"comment.level !== undefined && comment.level >= 0\"\n :class=\"`wl-badge level${comment.level}`\"\n v-text=\"locale[`level${comment.level}`] || `Level ${comment.level}`\"\n />\n <span class=\"wl-time\" v-text=\"time\" />\n\n <div class=\"wl-comment-actions\">\n <button\n v-if=\"isAdmin || isOwner\"\n class=\"wl-edit\"\n @click=\"$emit('edit', comment)\"\n >\n <EditIcon />\n </button>\n\n <button\n v-if=\"isAdmin || isOwner\"\n class=\"wl-delete\"\n @click=\"$emit('delete', comment)\"\n >\n <DeleteIcon />\n </button>\n\n <button\n class=\"wl-like\"\n :title=\"like ? locale.cancelLike : locale.like\"\n @click=\"$emit('like', comment)\"\n >\n <LikeIcon :active=\"like\" />\n <span v-if=\"'like' in comment\" v-text=\"comment.like\" />\n </button>\n\n <button\n class=\"wl-reply\"\n :class=\"{ active: isReplyingCurrent }\"\n :title=\"isReplyingCurrent ? locale.cancelReply : locale.reply\"\n @click=\"$emit('reply', isReplyingCurrent ? null : comment)\"\n >\n <ReplyIcon />\n </button>\n </div>\n </div>\n <div class=\"wl-meta\" aria-hidden=\"true\">\n <span\n v-if=\"comment.addr\"\n class=\"wl-addr\"\n :data-value=\"comment.addr\"\n v-text=\"comment.addr\"\n />\n <span\n v-if=\"comment.browser\"\n class=\"wl-browser\"\n :data-value=\"comment.browser\"\n v-text=\"comment.browser\"\n />\n <span\n v-if=\"comment.os\"\n class=\"wl-os\"\n :data-value=\"comment.os\"\n v-text=\"comment.os\"\n />\n </div>\n <!-- eslint-disable vue/no-v-html -->\n <div\n v-if=\"!isEditingCurrent\"\n class=\"wl-content\"\n v-html=\"comment.comment\"\n />\n <!-- eslint-enable vue/no-v-html -->\n\n <div v-if=\"isAdmin && !isEditingCurrent\" class=\"wl-admin-actions\">\n <span class=\"wl-comment-status\">\n <button\n v-for=\"status in commentStatus\"\n :key=\"status\"\n :class=\"`wl-btn wl-${status}`\"\n :disabled=\"comment.status === status\"\n @click=\"$emit('status', { status, comment })\"\n v-text=\"locale[status]\"\n />\n </span>\n\n <button\n v-if=\"isAdmin && !comment.rid\"\n class=\"wl-btn wl-sticky\"\n @click=\"$emit('sticky', comment)\"\n >\n {{ comment.sticky ? locale.unsticky : locale.sticky }}\n </button>\n </div>\n\n <div\n v-if=\"isReplyingCurrent || isEditingCurrent\"\n :class=\"{\n 'wl-reply-wrapper': isReplyingCurrent,\n 'wl-edit-wrapper': isEditingCurrent,\n }\"\n >\n <CommentBox\n :edit=\"edit\"\n :reply-id=\"reply?.objectId\"\n :reply-user=\"comment.nick\"\n :root-id=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', null)\"\n @cancel-edit=\"$emit('edit', null)\"\n />\n </div>\n <div v-if=\"comment.children\" class=\"wl-quote\">\n <CommentCard\n v-for=\"child in comment.children\"\n :key=\"child.objectId\"\n :comment=\"child\"\n :reply=\"reply\"\n :edit=\"edit\"\n :root-id=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $event)\"\n @like=\"$emit('like', $event)\"\n @edit=\"$emit('edit', $event)\"\n @delete=\"$emit('delete', $event)\"\n @status=\"$emit('status', $event)\"\n @sticky=\"$emit('sticky', $event)\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, inject } from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport {\n DeleteIcon,\n LikeIcon,\n ReplyIcon,\n EditIcon,\n VerifiedIcon,\n} from './Icons';\nimport { isLinkHttp } from '../utils';\nimport { useTimeAgo, useLikeStorage, useUserInfo } from '../composables';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { WalineConfig } from '../utils';\nimport type { WalineComment, WalineCommentStatus } from '../typings';\n\nconst commentStatus: WalineCommentStatus[] = ['approved', 'waiting', 'spam'];\n\nexport default defineComponent({\n components: {\n CommentBox,\n DeleteIcon,\n LikeIcon,\n ReplyIcon,\n EditIcon,\n VerifiedIcon,\n },\n\n props: {\n comment: {\n type: Object as PropType<WalineComment>,\n required: true,\n },\n rootId: {\n type: String,\n required: true,\n },\n reply: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n edit: {\n type: Object as PropType<WalineComment | null>,\n default: null,\n },\n },\n\n emits: ['submit', 'reply', 'like', 'delete', 'status', 'sticky', 'edit'],\n\n setup(props) {\n const config = inject<ComputedRef<WalineConfig>>(\n 'config'\n ) as ComputedRef<WalineConfig>;\n const likes = useLikeStorage();\n const userInfo = useUserInfo();\n\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n const { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const like = computed(() => likes.value.includes(props.comment.objectId));\n\n const time = useTimeAgo(props.comment.insertedAt, locale.value);\n\n const isAdmin = computed(() => userInfo.value.type === 'administrator');\n\n const isOwner = computed(\n () =>\n props.comment.user_id &&\n userInfo.value.objectId === props.comment.user_id\n );\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n const isEditingCurrent = computed(\n () => props.comment.objectId === props.edit?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n isEditingCurrent,\n link,\n like,\n time,\n\n isAdmin,\n isOwner,\n\n commentStatus,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <Reaction />\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-meta-head\">\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\n </div>\n <ul class=\"wl-sort\">\n <li\n v-for=\"item in sortByItems\"\n :key=\"item.key\"\n :class=\"[item.key === sortBy ? 'active' : '']\"\n @click=\"onSortByChange(item.key)\"\n >\n {{ i18n[item.name] }}\n </li>\n </ul>\n </div>\n\n <div class=\"wl-cards\">\n <CommentCard\n v-for=\"comment in data\"\n :key=\"comment.objectId\"\n :root-id=\"comment.objectId\"\n :comment=\"comment\"\n :reply=\"reply\"\n :edit=\"edit\"\n @reply=\"onReply\"\n @edit=\"onEdit\"\n @submit=\"onSubmit\"\n @status=\"onStatusChange\"\n @delete=\"onDelete\"\n @sticky=\"onSticky\"\n @like=\"onLike\"\n />\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-operation\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"refresh\"\n v-text=\"i18n.refresh\"\n />\n </div>\n\n <template v-else>\n <div v-if=\"status === 'loading'\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n\n <div v-else-if=\"!data.length\" class=\"wl-empty\" v-text=\"i18n.sofa\" />\n\n <!-- Load more button -->\n <div v-else-if=\"page < totalPages\" class=\"wl-operation\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"loadMore\"\n v-text=\"i18n.more\"\n />\n </div>\n </template>\n\n <!-- Copyright Information -->\n <div v-if=\"config.copyright\" class=\"wl-power\">\n Powered by\n <a\n href=\"https://github.com/walinejs/waline\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Waline\n </a>\n v{{ version }}\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { useStyleTag } from '@vueuse/core';\nimport { computed, defineComponent, onMounted, provide, ref, watch } from 'vue';\nimport Reaction from './ArticleReaction.vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo, useLikeStorage } from '../composables';\nimport { defaultLocales } from '../config';\nimport {\n deleteComment,\n fetchComment,\n likeComment,\n updateComment,\n} from '../api';\nimport { getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineCommentStatus,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineSearchOptions,\n WalineLocale,\n WalineProps,\n WalineMeta,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nconst props = [\n 'serverURL',\n 'path',\n 'meta',\n 'requiredMeta',\n 'dark',\n 'lang',\n 'locale',\n 'pageSize',\n 'wordLimit',\n 'emoji',\n 'login',\n 'highlighter',\n 'texRenderer',\n 'imageUploader',\n 'search',\n 'copyright',\n 'recaptchaV3Key',\n 'reaction',\n];\n\ntype SortKeyItems = 'insertedAt_desc' | 'insertedAt_asc' | 'like_desc';\ntype SortNameItems = 'latest' | 'oldest' | 'hottest';\ntype SortByItems = { key: SortKeyItems; name: SortNameItems }[];\nconst sortByItems: SortByItems = [\n {\n key: 'insertedAt_desc',\n name: 'latest',\n },\n {\n key: 'insertedAt_asc',\n name: 'oldest',\n },\n {\n key: 'like_desc',\n name: 'hottest',\n },\n];\n\nconst propsWithValidate = {\n serverURL: {\n type: String,\n required: true,\n },\n\n path: {\n type: String,\n required: true,\n },\n\n meta: {\n type: Array as PropType<WalineMeta[]>,\n default: (): WalineMeta[] => ['nick', 'mail', 'link'],\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n },\n\n requiredMeta: {\n type: Array,\n default: (): WalineMeta[] => [],\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n },\n\n dark: [String, Boolean],\n\n lang: {\n type: String,\n default: 'zh-CN',\n validator: (value: unknown): boolean =>\n Object.keys(defaultLocales).includes(value as string),\n },\n\n locale: Object as PropType<Partial<WalineLocale>>,\n\n pageSize: { type: Number, default: 10 },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n validator: (value: unknown): boolean =>\n typeof value === 'number' ||\n (Array.isArray(value) &&\n value.length === 2 &&\n value.every((item) => typeof item === 'number')),\n },\n\n emoji: {\n type: [Array, Boolean] as PropType<(string | WalineEmojiInfo)[] | false>,\n validator: (value: unknown): boolean =>\n value === false ||\n (Array.isArray(value) &&\n value.every(\n (item) =>\n typeof item === 'string' ||\n (typeof item === 'object' &&\n typeof item.name === 'string' &&\n typeof item.folder === 'string' &&\n typeof item.icon === 'string' &&\n Array.isArray(item.items) &&\n (item.items as unknown[]).every(\n (icon) => typeof icon === 'string'\n ))\n )),\n },\n\n login: String as PropType<'enable' | 'disable' | 'force'>,\n\n highlighter: Function as PropType<WalineHighlighter>,\n\n imageUploader: {\n type: [Function, Boolean] as PropType<WalineImageUploader | false>,\n default: undefined,\n },\n\n texRenderer: {\n type: [Function, Boolean] as PropType<WalineTexRenderer | false>,\n default: undefined,\n },\n\n search: {\n type: [Object, Boolean] as PropType<WalineSearchOptions | false>,\n default: undefined,\n },\n\n copyright: { type: Boolean, default: true },\n\n recaptchaV3Key: {\n type: String,\n default: '',\n },\n\n reaction: {\n type: [Array, Boolean] as PropType<string[] | false>,\n },\n};\n\nexport default defineComponent({\n name: 'WalineRoot',\n\n components: {\n Reaction,\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: SHOULD_VALIDATE ? propsWithValidate : props,\n\n setup(props) {\n const config = computed(() => getConfig(props as unknown as WalineProps));\n\n const userInfo = useUserInfo();\n const likeStorage = useLikeStorage();\n\n const status = ref<'loading' | 'success' | 'error'>('loading');\n\n const count = ref(0);\n const page = ref(1);\n const totalPages = ref(0);\n const sortBy = ref<SortKeyItems>(sortByItems[0].key);\n\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n const edit = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n useStyleTag(darkmodeStyle);\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n\n const fetchCommentData = (pageNumber: number): void => {\n const { serverURL, path, pageSize } = config.value;\n const controller = new AbortController();\n\n status.value = 'loading';\n\n abort?.();\n\n fetchComment({\n serverURL,\n lang: config.value.lang,\n path,\n pageSize,\n sortBy: sortBy.value,\n page: pageNumber,\n signal: controller.signal,\n token: userInfo.value?.token,\n })\n .then((resp) => {\n status.value = 'success';\n count.value = resp.count;\n data.value.push(...resp.data);\n page.value = pageNumber;\n totalPages.value = resp.totalPages;\n })\n .catch((err) => {\n if (err.name !== 'AbortError') {\n console.error(err.message);\n status.value = 'error';\n }\n });\n\n abort = controller.abort.bind(controller);\n };\n\n const loadMore = (): void => fetchCommentData(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchCommentData(1);\n };\n\n const onSortByChange = (item: SortKeyItems): void => {\n if (sortBy.value === item) {\n return;\n }\n sortBy.value = item;\n refresh();\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onEdit = (comment: WalineComment | null): void => {\n edit.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n if (edit.value) {\n edit.value.comment = comment.comment;\n edit.value.orig = comment.orig;\n } else if (comment.rid) {\n const repliedComment = data.value.find(\n ({ objectId }) => objectId === comment.rid\n );\n\n if (!repliedComment) return;\n\n if (!Array.isArray(repliedComment.children))\n repliedComment.children = [];\n\n repliedComment.children.push(comment);\n } else data.value.unshift(comment);\n };\n\n const onStatusChange = async ({\n comment,\n status,\n }: {\n comment: WalineComment;\n status: WalineCommentStatus;\n }): Promise<void> => {\n if (comment.status === status) return;\n\n const { serverURL, lang } = config.value;\n\n await updateComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: comment.objectId,\n status,\n });\n\n comment.status = status;\n };\n\n const onSticky = async (comment: WalineComment): Promise<void> => {\n if (comment.rid) return;\n\n const { serverURL, lang } = config.value;\n\n await updateComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: comment.objectId,\n sticky: comment.sticky ? 0 : 1,\n });\n\n comment.sticky = !comment.sticky;\n };\n\n const onDelete = async ({ objectId }: WalineComment): Promise<void> => {\n if (!confirm('Are you sure you want to delete this comment?')) return;\n\n const { serverURL, lang } = config.value;\n\n await deleteComment({\n serverURL,\n lang,\n token: userInfo.value?.token,\n objectId: objectId,\n });\n\n // delete comment from data\n data.value.some((item, index) => {\n if (item.objectId === objectId) {\n data.value = data.value.filter((_item, i) => i !== index);\n\n return true;\n }\n\n return item.children.some((child, childIndex) => {\n if (child.objectId === objectId) {\n data.value[index].children = item.children.filter(\n (_item, i) => i !== childIndex\n );\n\n return true;\n }\n\n return false;\n });\n });\n };\n\n const onLike = async (comment: WalineComment): Promise<void> => {\n const { serverURL, lang } = config.value;\n const { objectId } = comment;\n const hasLiked = likeStorage.value.includes(objectId);\n\n await likeComment({\n serverURL,\n lang,\n objectId,\n like: !hasLiked,\n });\n\n if (hasLiked)\n likeStorage.value = likeStorage.value.filter((id) => id !== objectId);\n else {\n likeStorage.value = [...likeStorage.value, objectId];\n\n if (likeStorage.value.length > 50)\n likeStorage.value = likeStorage.value.slice(-50);\n }\n\n comment.like = (comment.like || 0) + (hasLiked ? -1 : 1);\n };\n\n provide('config', config);\n\n watch(() => (props as unknown as WalineProps).path, refresh);\n\n onMounted(() => refresh());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n sortBy,\n sortByItems,\n data,\n reply,\n edit,\n\n loadMore,\n refresh,\n onSortByChange,\n onReply,\n onSubmit,\n onStatusChange,\n onDelete,\n onSticky,\n onLike,\n onEdit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","import { fetchPageviews, updatePageviews } from './api';\nimport { errorHandler, getQuery, getServerURL } 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({\n serverURL: getServerURL(serverURL),\n path,\n lang,\n }).then((count) =>\n renderVisitorCount(\n new Array<number>(normalElements.length).fill(count),\n normalElements\n )\n );\n\n // if we should fetch count of other pages\n if (elementsNeedstoBeFetched.length) {\n void fetch(elementsNeedstoBeFetched);\n }\n }\n // we should not update pageviews\n else {\n void fetch(elements);\n }\n\n return controller.abort.bind(controller);\n};\n","import { fetchArticleCounter, updateArticleCounter } from './articleCounter';\n\ninterface FetchPageviewOptions {\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}: FetchPageviewOptions): Promise<number[]> =>\n fetchArticleCounter({\n serverURL,\n lang,\n paths,\n type: ['time'],\n signal,\n })\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<\n number[]\n >;\n\nexport interface UpdatePageviewOptions {\n serverURL: string;\n lang: string;\n path: string;\n action?: 'inc' | 'desc';\n}\n\nexport const updatePageviews = (\n options: UpdatePageviewOptions\n): Promise<number> =>\n updateArticleCounter({\n ...options,\n type: 'time',\n });\n","import { createApp, h, reactive, watchEffect } from 'vue';\n\nimport Waline from './components/Waline.vue';\nimport { commentCount } from './comment';\nimport { pageviewCount } from './pageview';\nimport { getRoot } from './utils';\n\nimport type { WalineInitOptions } from './typings';\n\nexport interface WalineInstance {\n /**\n * Waline 被挂载到的元素\n *\n * @description 当通过 `el: null` 初始化,值为 `null`\n *\n * Element where Waline is mounted\n *\n * @description when initialized with `el: null`, it will be `null`\n */\n el: HTMLElement | null;\n\n /**\n * 更新 Waline 实例\n *\n * @description 只要不设置`path` 选项,更新时它就会被重置为 `windows.location.pathname`\n *\n * Update Waline instance\n *\n * @description when not setting `path` option, it will be reset to `window.location.pathname`\n */\n update: (newOptions?: Partial<Omit<WalineInitOptions, 'el'>>) => void;\n\n /**\n * 取消挂载并摧毁 Waline 实例\n *\n * Unmount and destroy Waline instance\n */\n destroy: () => void;\n}\n\nexport const init = ({\n el = '#waline',\n path = window.location.pathname,\n comment = false,\n pageview = false,\n ...initProps\n}: WalineInitOptions): WalineInstance | null => {\n // check el element\n const root = el ? getRoot(el) : null;\n\n // check root\n if (el && !root) throw new Error(`Option 'el' do not match any domElement!`);\n\n // check serverURL\n if (!initProps.serverURL) throw new Error(\"Option 'serverURL' is missing!\");\n\n const props = reactive({ ...initProps });\n const state = reactive({ comment, pageview, path });\n\n const updateCommentCount = (): void => {\n if (state.comment)\n commentCount({\n serverURL: props.serverURL,\n path: state.path,\n selector: typeof state.comment === 'string' ? state.comment : undefined,\n });\n };\n\n const updatePageviewCount = (): void => {\n if (state.pageview)\n pageviewCount({\n serverURL: props.serverURL,\n path: state.path,\n selector:\n typeof state.pageview === 'string' ? state.pageview : undefined,\n });\n };\n\n const app = root\n ? createApp(() => h(Waline, { path: state.path, ...props }))\n : null;\n\n if (app) app.mount(root!);\n\n const stopComment = watchEffect(updateCommentCount);\n const stopPageview = watchEffect(updatePageviewCount);\n\n return {\n el: root,\n update: ({\n comment,\n pageview,\n path = window.location.pathname,\n ...newProps\n }: Partial<Omit<WalineInitOptions, 'el'>> = {}): void => {\n Object.entries(newProps).forEach(([key, value]) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n // eslint-disable-next-line\n props[key] = value;\n });\n\n state.path = path;\n if (comment !== undefined) state.comment = comment;\n if (pageview !== undefined) state.pageview = pageview;\n },\n destroy: (): void => {\n app?.unmount();\n stopComment();\n stopPageview();\n },\n };\n};\n","declare const VERSION: string;\n\nexport const version = VERSION;\n","import { fetchRecentComment } from '../api';\nimport { useUserInfo } from '../composables';\nimport { getRoot } from '../utils';\n\nimport type { WalineComment } from '../typings';\n\nexport interface WalineRecentCommentsOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 获取最新评论的数量\n *\n * fetch number of latest comments\n */\n count: number;\n\n /**\n * 需要挂载的元素\n *\n * Element to be mounted\n */\n el?: string | HTMLElement;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default 'zh-CN'\n */\n lang?: string;\n}\n\nexport interface WalineRecentCommentsResult {\n /**\n * 评论数据\n *\n * Comment Data\n */\n comments: WalineComment[];\n\n /**\n * 取消挂载挂件\n *\n * Umount widget\n */\n destroy: () => void;\n}\n\nexport const RecentComments = ({\n el,\n serverURL,\n count,\n lang = 'zh-CN',\n}: WalineRecentCommentsOptions): Promise<WalineRecentCommentsResult> => {\n const userInfo = useUserInfo();\n const root = getRoot(el);\n const controller = new AbortController();\n\n return fetchRecentComment({\n serverURL,\n count,\n lang,\n signal: controller.signal,\n token: userInfo.value?.token,\n }).then((comments) => {\n if (root && comments.length) {\n root.innerHTML = `<ul class=\"wl-recent-list\">${comments\n .map(\n (comment) =>\n `<li class=\"wl-recent-item\"><a href=\"${comment.url}\">${comment.nick}</a>:${comment.comment}</li>`\n )\n .join('')}</ul>`;\n\n return {\n comments,\n destroy: (): void => {\n controller.abort();\n root.innerHTML = '';\n },\n };\n }\n\n return {\n comments,\n destroy: (): void => controller.abort(),\n };\n });\n};\n","import { errorCheck } from './utils';\nimport type { WalineComment } from '../typings';\n\nexport interface FetchRecentCommentOptions {\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}: FetchRecentCommentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n\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","import { fetchUserList, WalineUser } from '../api';\nimport { defaultLang, defaultLocales } from '../config';\nimport { WalineLocale } from '../typings';\nimport { getRoot } from '../utils';\n\nexport interface WalineUserListOptions {\n /**\n * Waline 服务端地址\n *\n * Waline serverURL\n */\n serverURL: string;\n\n /**\n * 获取用户列表的数量\n *\n * fetch number of user list\n */\n count: number;\n\n /**\n * 需要挂载的元素\n *\n * Element to be mounted\n */\n el?: string | HTMLElement;\n\n /**\n * 错误提示消息所使用的语言\n *\n * Language of error message\n *\n * @default 'zh-CN'\n */\n lang?: string;\n\n /**\n * 自定义 waline 语言显示\n *\n * @see [自定义语言](https://waline.js.org/client/i18n.html)\n *\n * Custom display language in waline\n *\n * @see [I18n](https://waline.js.org/en/client/i18n.html)\n */\n locale?: WalineLocale;\n\n /**\n * 列表模式还是头像墙模式\n *\n * list mode or avatar wall mode\n */\n mode: 'list' | 'wall';\n}\n\nexport interface WalineUserListResult {\n /**\n * 用户数据\n *\n * User Data\n */\n users: WalineUser[];\n\n /**\n * 取消挂载挂件\n *\n * Umount widget\n */\n destroy: () => void;\n}\n\nexport const UserList = ({\n el,\n serverURL,\n count,\n locale,\n lang = defaultLang,\n mode = 'list',\n}: WalineUserListOptions): Promise<WalineUserListResult> => {\n const root = getRoot(el);\n const controller = new AbortController();\n\n return fetchUserList({\n serverURL,\n pageSize: count,\n lang,\n signal: controller.signal,\n }).then((users) => {\n if (!root || !users.length) {\n return {\n users,\n destroy: (): void => controller.abort(),\n };\n }\n\n locale = {\n ...(defaultLocales[lang] || defaultLocales[defaultLang]),\n ...(typeof locale === 'object' ? locale : {}),\n } as WalineLocale;\n\n root.innerHTML = `<ul class=\"wl-user-${mode}\">${users\n .map((user, index) =>\n [\n '<li class=\"wl-user-item\">',\n user.link && `<a href=\"${user.link}\" target=\"_blank\">`,\n '<div class=\"wl-user-avatar\">',\n `<img src=\"${user.avatar}\" alt=\"${user.nick}\">`,\n `<i>${index + 1}</i>`,\n '</div>',\n '<div class=\"wl-user-meta\">',\n `<div class=\"wl-user-name\"><div>${user.nick}</div>`,\n '<div class=\"wl-user-tag wl-card\">',\n user.level &&\n `<span class=\"wl-badge\">${\n locale ? locale[`level${user.level}`] : `Level ${user.level}`\n }</span>`,\n user.label && `<span class=\"wl-badge\">${user.label}</span>`,\n '</div>',\n '</div>',\n user.link && `<span class=\"wl-user-meta\">${user.link}</span>`,\n '</div>',\n user.link && '</a>',\n '</li>',\n ]\n .filter((v) => v)\n .join('')\n )\n .join('')}</ul>`;\n\n return {\n users,\n destroy: (): void => {\n controller.abort();\n root.innerHTML = '';\n },\n };\n });\n};\n","import { WalineComment } from '../typings';\nimport { errorCheck } from './utils';\n\nexport interface FetchUserListOptions {\n serverURL: string;\n pageSize: number;\n signal: AbortSignal;\n lang: string;\n}\n\nexport interface WalineUser\n extends Pick<WalineComment, 'nick' | 'link' | 'avatar' | 'label' | 'level'> {\n count: number;\n}\n\nexport const fetchUserList = ({\n serverURL,\n signal,\n pageSize,\n lang,\n}: FetchUserListOptions): Promise<WalineUser[]> => {\n return fetch(`${serverURL}/user?pageSize=${pageSize}&lang=${lang}`, {\n signal,\n })\n .then(\n (resp) =>\n resp.json() as Promise<{\n errno: number;\n message: string;\n data: WalineUser[];\n }>\n )\n .then((resp) => errorCheck(resp, 'user list'))\n .then((resp) => resp.data);\n};\n"],"names":["availableMeta","getMeta","meta","filter","item","includes","defaultLang","defaultUploadImage","file","Promise","resolve","reject","size","Error","reader","FileReader","readAsDataURL","onload","_reader$result","toString","result","onerror","defaultTexRenderer","blockMode","getDefaultSearchOptions","lang","fetchGiphy","async","url","params","querystring","URLSearchParams","limit","rating","api_key","resp","fetch","then","json","data","map","gif","title","src","images","downsized_medium","search","word","q","offset","default","more","defaultReaction","REGEXP","RegExp","source","COLORS","cache","defaultHighlighter","input","index","replace","_match","comment","color","out","length","localeKeys","generateLocale","locale","Object","fromEntries","en","jp","zhCN","zhTW","ptBR","ru","defaultLocales","zh","JSON_HEADERS","errorCheck","name","errno","TypeError","errmsg","fetchArticleCounter","_ref","serverURL","paths","type","signal","encodeURIComponent","join","updateArticleCounter","_ref2","path","action","method","headers","body","JSON","stringify","updateComment","_ref7","token","objectId","Authorization","decodePath","decodeURI","err","removeEndingSplash","content","isLinkHttp","link","test","getServerURL","getWordLimit","wordLimit","Array","isArray","fallback","value","style","padWithZeros","vNumber","width","numAsString","getTimeAgo","date","now","time","Date","indexOf","timepassed","getTime","days","Math","floor","leave1","hours","leave2","minutes","leave3","round","seconds","vDay","getDate","vMonth","getMonth","getFullYear","dateFormat","fetchEmoji","emojiStore","useStorage","Boolean","info","emojiInfo","folder","getLink","prefix","errorHandler","console","error","message","getRoot","el","HTMLElement","document","querySelector","isImage","getImagefromDataTransfer","items","image","from","find","getAsFile","inlineMathStart","inlineMathReg","blockMathReg","parseEmoji","text","emojiMap","placeholder","key","parseMarkdown","_ref42","highlighter","texRenderer","marked","setOptions","highlight","undefined","breaks","smartLists","smartypants","extensions","level","tokenizer","cap","exec","raw","start","idx","markedTexExtensions","use","parse","getQuery","element","dataset","getAttribute","commentCount","_ref43","window","location","pathname","selector","controller","AbortController","elements","querySelectorAll","_ref8","counts","fetchCommentCount","forEach","innerText","catch","abort","bind","likeStorage","useLikeStorage","recaptchaStore","useTimeAgo","useNow","computed","VOTE_IDENTIFIER","VOTE_INDEX","voteStorage","useVoteStorage","userInfoStorage","useUserInfo","_sfc_main$4","defineComponent","setup","votes","ref","config","inject","reaction","icon","vote","desc","active","_ref44","voteIdentifier","voteIndex","onMounted","_","k","fetchCounter","onUnmounted","_abort","hasVoted","_ref45","max","i","slice","LoadingIcon","_ref48","h","height","viewBox","preserveAspectRatio","cx","cy","fill","stroke","strokeWidth","r","attributeName","repeatCount","dur","values","keyTimes","_sfc_main$3","components","props","columnWidth","Number","gap","emits","resizeObserver","wall","state","columns","getColumnCount","count","getBoundingClientRect","createColumns","fillColumns","_wall$value","itemIndex","nextTick","target","children","reduce","prev","curr","push","redraw","force","scrollY","scrollTo","top","watch","ResizeObserver","observe","onBeforeUnmount","unobserve","imageLoad","e","_sfc_main$2","CloseIcon","_ref46","class","d","EmojiIcon","ImageIcon","ImageWall","MarkdownIcon","ariaHidden","PreviewIcon","GifIcon","rootId","String","replyId","replyUser","edit","_ref49","emit","editor","userMeta","nick","mail","userInfo","inputRefs","editorRef","imageUploadRef","emojiButtonRef","emojiPopupRef","gifButtonRef","gifPopupRef","gifSearchInputRef","emoji","tabs","emojiTabIndex","showEmoji","showGif","showPreview","previewText","wordNumber","searchResults","reactive","loading","list","isWordNumberLegal","isSubmitting","isLogin","_userInfo$value","canUploadImage","imageUploader","insert","textArea","startPosition","selectionStart","endPosition","selectionEnd","scrollTop","substring","focus","uploadImage","uploadText","uploading","alert","submitComment","_userInfo$value2","_userInfo$value3","login","requiredMeta","recaptchaV3Key","init","load","useRecaptchaNet","autoHideBadge","execute","instance","useReCaptcha","ua","navigator","userAgent","recaptchaV3","display_name","email","_inputRefs$value$nick","_inputRefs$value$mail","_editorRef$value","nickError","mailError","anonymous","wordHint","pid","rid","at","eid","_ref4","postComment","_props$edit","popupHandler","event","contains","onImageWallScroll","_gifSearchInputRef$va","clientHeight","scrollHeight","percent","searchOptions","keyword","setTimeout","onGifSearch","useDebounceFn","_ref50","immediate","onMessageRecive","_ref51","localStorage","sessionStorage","store","getItem","setItem","_props$edit2","addEventListener","orig","match","getWords","accumulator","trim","split","getChinese","getWordNumber","autosize","destroy","emojiConfig","getEmojis","emojis","all","emojiInfos","removeEventListener","onChange","inputElement","files","onDrop","_event$dataTransfer","dataTransfer","preventDefault","onKeyDown","ctrlKey","metaKey","onPaste","clipboardData","onLogin","_ref9","left","innerWidth","innerHeight","handler","open","postMessage","receiver","_ref10","close","remember","onLogout","onProfile","gifData","commentStatus","_sfc_main$1","CommentBox","DeleteIcon","LikeIcon","_ref47","ReplyIcon","EditIcon","VerifiedIcon","required","reply","likes","like","insertedAt","isAdmin","isOwner","user_id","isReplyingCurrent","_props$reply","isEditingCurrent","_props$edit3","sortByItems","_sfc_main","Reaction","CommentCard","_ref14","dark","pageSize","copyright","getConfig","status","page","totalPages","sortBy","darkmodeStyle","getDarkStyle","useStyleTag","fetchCommentData","pageNumber","_abort2","_userInfo$value4","_ref3","fetchComment","refresh","provide","i18n","loadMore","onSortByChange","onReply","onSubmit","repliedComment","_ref52","unshift","onStatusChange","_userInfo$value5","_ref53","onDelete","_userInfo$value7","_ref54","confirm","_ref5","deleteComment","some","_item","child","childIndex","onSticky","_userInfo$value6","sticky","onLike","hasLiked","_ref6","likeComment","id","onEdit","version","renderVisitorCount","countElements","pageviewCount","_ref55","update","query","_ref11","fetchPageviews","normalElements","elementsNeedstoBeFetched","options","_ref56","pageview","initProps","root","app","createApp","Waline","mount","stopComment","watchEffect","stopPageview","newProps","entries","_ref57","unmount","_ref58","_userInfo$value8","_ref12","fetchRecentComment","comments","innerHTML","_ref59","mode","_ref13","fetchUserList","users","user","avatar","label","v"],"mappings":"+aAOA,MAAMA,EAA8B,CAAC,OAAQ,OAAQ,QAExCC,EAAWC,GACtBA,EAAKC,QAAQC,GAASJ,EAAcK,SAASD,KAElCE,EAAc,QAEdC,EAAsBC,GACjC,IAAIC,SAAQ,CAACC,EAASC,KACpB,GAAIH,EAAKI,KAAO,MACd,OAAOD,EAAO,IAAIE,MAAM,0CAG1B,MAAMC,EAAS,IAAIC,WAEnBD,EAAOE,cAAcR,GACrBM,EAAOG,OAAS,KAAA,IAAAC,EAAA,OAAYR,GAAuBS,QAAfD,EAAAJ,EAAOM,cAAQD,IAAAA,OAAAA,EAAAA,EAAAA,aAAc,GAAjD,EAChBL,EAAOO,QAAUV,CAAjB,IAGSW,EAAsBC,IACnB,IAAdA,EACI,wDACA,8DAEOC,EAA2BC,IAiBtC,MAAMC,EAAaC,eACjBC,GAE+B,IAD/BC,yDAAiC,CACF,EAC/B,MAAMC,EAAc,IAAIC,gBAAgB,CACtCN,OACAO,MAAO,KACPC,OAAQ,IACRC,QAAS,sCACNL,IACFV,WAEGgB,QAAaC,uCACgBR,KAAOE,KACxCO,MAAMF,GAASA,EAAKG,SAEtB,OAAOH,EAAKI,KAAKC,KAAKC,IAAS,CAC7BC,MAAOD,EAAIC,MACXC,IAAKF,EAAIG,OAAOC,iBAAiBjB,OAEpC,EAED,MAAO,CACLkB,OAASC,GACPrB,EAAW,SAAU,CAAEsB,EAAGD,EAAME,OAAQ,MAC1CC,QAAS,IAAmCxB,EAAW,WAAY,IACnEyB,KAAM,SAACJ,GAAD,IAAeE,yDAAS,EAAxB,OACJvB,EAAW,SAAU,CAAEsB,EAAGD,EAAME,OAAQA,EAAO9B,YAD3C,EAJR,EASWiC,EAAkB,CAC7B,mDACA,uDACA,wDACA,uDACA,qDACA,oDCxDIC,EAAS,IAAIC,WAJjB,wFAKgBC,UAJQ,IAIoBA,eAHlB,uBAGqDA,cAFpD,uBAEuFA,WAClH,OAGIC,EAAS,CACb,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,SACA,UAEIC,EAAgC,CAAtC,EAEaC,EAAsBC,IACjC,IAAIC,EAAQ,EAEZ,OAAOD,EAAME,QAAQR,GAAQ,CAACS,EAAQf,EAAcgB,KAClD,GAAIA,EAAS,MAAO,kCAAkCA,WACtD,GAAa,MAAThB,EAAc,MAAO,OAEzB,IAAIiB,EAEAP,EAAMV,GAAOiB,EAAQP,EAAMV,IAE7BiB,EAAQR,EAAOI,GACfH,EAAMV,GAAQiB,GAGhB,MAAMC,EAAM,wBAAwBD,MAAUjB,WAI9C,OAFAa,IAAUA,EAAQJ,EAAOU,OAElBD,CAAP,GAhBF,ECrDIE,EAAa,CACjB,OACA,YACA,OACA,YACA,OACA,WACA,cACA,OACA,SACA,OACA,aACA,QACA,cACA,UACA,UACA,OACA,UACA,QACA,cACA,UACA,UACA,QACA,OACA,MACA,YACA,QACA,SACA,QACA,SACA,OACA,WACA,YACA,SACA,SACA,SACA,SACA,SACA,SACA,MACA,uBACA,UACA,WACA,UACA,OACA,WACA,SACA,SACA,UACA,iBAGWC,EAAkBC,GAC7BC,OAAOC,YACLF,EAAO7B,KAAI,CAACpC,EAAMwD,IAAU,CAACO,EAAWP,GAAQxD,MCtDpD,IAAAoE,EAAeJ,EAAe,CAC5B,WACA,wCACA,SACA,qCACA,UACA,WACA,kBACA,kBACA,SACA,OACA,cACA,QACA,eACA,WACA,UACA,eACA,UACA,QACA,eACA,cACA,cACA,YACA,WACA,WACA,YACA,QACA,SACA,QACA,SACA,QACA,2EACA,YACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,aACA,UACA,WACA,UACA,OACA,WACA,SACA,SACA,UACA,uBCjDFK,EAAeL,EAAe,CAC5B,SACA,yBACA,UACA,mBACA,MACA,QACA,UACA,aACA,OACA,OACA,cACA,OACA,QACA,OACA,KACA,UACA,QACA,MACA,YACA,KACA,KACA,MACA,KACA,OACA,SACA,SACA,QACA,MACA,SACA,MACA,gDACA,KACA,OACA,OACA,OACA,SACA,KACA,MACA,MACA,SACA,OACA,OACA,QACA,MACA,SACA,KACA,KACA,MACA,aCjDFM,EAAeN,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,MACA,QACA,OACA,KACA,MACA,KACA,OACA,MACA,MACA,MACA,gBCjDFO,EAAeP,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,MACA,QACA,OACA,KACA,MACA,KACA,OACA,MACA,MACA,MACA,gBCjDFQ,EAAeR,EAAe,CAC5B,UACA,0CACA,SACA,8CACA,UACA,WACA,kBACA,4BACA,SACA,OACA,cACA,YACA,oBACA,cACA,YACA,mBACA,aACA,QACA,gBACA,iBACA,gBACA,cACA,aACA,cACA,WACA,SACA,OACA,QACA,SACA,WACA,gFACA,UACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,gBACA,qBACA,WACA,SACA,OACA,WACA,aACA,gBACA,cACA,qBCjDFS,EAAeT,EAAe,CAC5B,YACA,uCACA,YACA,yDACA,WACA,iBACA,uBACA,yBACA,YACA,OACA,cACA,WACA,iBACA,cACA,WACA,oBACA,SACA,SACA,wBACA,eACA,wBACA,wBACA,aACA,eACA,WACA,iBACA,mBACA,QACA,SACA,QACA,8EACA,YACA,UACA,UACA,OACA,UACA,QACA,QACA,MACA,YACA,sBACA,aACA,YACA,OACA,WACA,eACA,YACA,gBACA,oBCvCW,MAAAU,EAA0B,CACrCC,GAAIL,EACJ,QAASA,EACT,QAASA,EACT,QAASC,EACT,QAASA,EACTH,GAAIA,EACJ,QAASA,EACT,QAASA,EACTC,GAAIA,EACJ,QAASA,EACT,QAASA,EACT,QAASG,EACT,QAASA,EACTC,GAAIA,EACJ,QAASA,EACT,QAASA,sBCvBJ,MAAMG,EAAuC,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"}