@waline/client 2.0.0-alpha.4 → 2.0.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":"component.js","sources":["../src/components/Icons.ts","../src/composables/store.ts","../src/composables/inputs.ts","../src/config/default.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/utils/path.ts","../src/utils/emoji.ts","../src/utils/config.ts","../src/utils/darkmode.ts","../src/utils/data.ts","../src/utils/fetch.ts","../src/utils/markedMathExtension.ts","../src/utils/markdown.ts","../src/utils/timeAgo.ts","../src/composables/userInfo.ts","../src/utils/userInfo.ts","../src/components/CommentBox.vue","../src/utils/wordCount.ts","../src/components/CommentBox.vue?vue&type=template&id=969569c8&lang.js","../src/components/CommentCard.vue","../src/components/CommentCard.vue?vue&type=template&id=5dd9348f&lang.js","../src/components/Waline.vue","../src/components/Waline.vue?vue&type=template&id=222c3e24&lang.js","../src/version.ts"],"sourcesContent":["import { h } from 'vue';\nimport type { FunctionalComponent } from 'vue';\n\nexport const CloseIcon: FunctionalComponent<{ size: number }> = ({ size }) =>\n h(\n 'svg',\n {\n class: 'vclose-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 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 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: '18', height: '18' },\n h('path', {\n d: 'M1019.2 720C1001.6 625.6 968 566.4 904 497.6c-89.6-89.6-214.4-150.4-347.2-176v-120c0-25.6-8-51.2-25.6-64-33.6-30.4-81.6-30.4-112-4.8L33.6 441.6C12.8 459.2 0 484.8 0 510.4c0 25.6 12.8 51.2 30.4 68.8l385.6 312c17.6 12.8 33.6 17.6 51.2 17.6 12.8 0 25.6-4.8 38.4-8C536 888 552 857.6 552 824v-99.2c124.8 20.8 248 86.4 339.2 140.8 25.6 17.6 59.2 17.6 89.6 0 25.6-17.6 43.2-46.4 43.2-76.8 0-33.6 0-56-4.8-68.8zm-500.8-89.6-46.4-4.8v193.6L86.4 510.4 472 201.6V400l38.4 4.8c128 12.8 248 68.8 334.4 153.6 51.2 56 76.8 102.4 94.4 179.2 0 4.8 4.8 20.8 4.8 51.2C835.2 720 672 640 518.4 630.4z',\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","export interface Store {\n get: <T = unknown>(key: string) => T | null;\n set: <T = unknown>(key: string, content: T) => void;\n update: <T = unknown>(content: T) => void;\n}\n\nexport const useStore = (cacheKey: string): Store => {\n let storage: Record<string, unknown> = {};\n const content = localStorage.getItem(cacheKey);\n\n if (content) {\n try {\n storage = JSON.parse(content) as Record<string, unknown>;\n } catch (err) {\n // do nothing\n }\n }\n\n return {\n get: <T>(key: string): T | null => (storage[key] as T) || null,\n\n set<T>(key: string, content: T): void {\n try {\n // make sure the content can be stringify and make a deep copy here\n storage[key] = JSON.parse(JSON.stringify(content));\n localStorage.setItem(cacheKey, JSON.stringify(storage));\n } catch (err) {\n // do nothing\n }\n },\n\n update<T>(content: T): void {\n // make sure the content can be stringify and make a deep copy here\n storage = JSON.parse(JSON.stringify(content)) as Record<string, unknown>;\n localStorage.setItem(cacheKey, JSON.stringify(storage));\n },\n };\n};\n","import { reactive } from 'vue';\nimport { useStore } from './store';\n\nimport type { Store } from './store';\n\nexport interface Inputs {\n nick: string;\n mail: string;\n link: string;\n editor: string;\n}\n\nlet store: Store;\nlet inputs: Inputs;\n\nexport const useInputs = (): { inputs: Inputs; store: Store } => {\n if (!inputs) {\n store = useStore('WALINE_USER_CACHE');\n\n inputs = reactive({\n nick: store.get<string>('nick') || '',\n mail: store.get<string>('mail') || '',\n link: store.get<string>('link') || '',\n editor: '',\n });\n }\n\n return { inputs, store };\n};\n","import type { WalineMeta } 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 const reader = new FileReader();\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=\"vtex\">Tex is not available in preview</p>'\n : '<span class=\"vtex\">Tex is not available in preview</span>';\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 '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];\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 '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]);\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 'コメントは $0 から $1 ワードの間でなければなりません!\\n 現在の単語番号: $2',\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 '评论字数应在 $0 到 $1 字之间!\\n当前字数:$2',\n '匿名',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '暱稱',\n '郵箱',\n '網址',\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 '評論字數應在 $0 到 $1 字之間!\\n當前字數:$2',\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 '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]);\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 'Пожалуйста, введите комментарии от $0 до $1 слов!\\nНомер текущего слова: $2',\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 locales: 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 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 { Store, useStore } from '../composables/store';\nimport { removeEndingSplash } from './path';\n\nimport type { EmojiConfig } from './config';\nimport type { WalineEmojiInfo } from '../typings';\n\nlet store: Store;\n\nconst hasVersion = (url: string): boolean =>\n Boolean(/@[0-9]+\\.[0-9]+\\.[0-9]+/.test(url));\n\nconst fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {\n if (!store) store = useStore('WALINE_EMOJI');\n\n const result = hasVersion(link);\n\n if (result) {\n const info = store.get<WalineEmojiInfo>(link);\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) store.set(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<EmojiConfig> =>\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: EmojiConfig = {\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","import {\n defaultLang,\n defaultUploadImage,\n defaultTexRenderer,\n getMeta,\n locales,\n} from '../config';\n\nimport { decodePath, isLinkHttp, removeEndingSplash } from './path';\nimport { getEmojis } from './emoji';\n\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineLocale,\n WalineProps,\n} from '../typings';\nimport hanabi from 'hanabi';\n\nexport interface EmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface Config\n extends Required<\n Pick<\n WalineProps,\n | 'path'\n | 'lang'\n | 'meta'\n | 'pageSize'\n | 'requiredMeta'\n | 'imageUploader'\n | 'highlighter'\n | 'texRenderer'\n | 'copyright'\n | 'login'\n >\n >,\n Pick<WalineProps, 'dark' | 'serverURL'> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n emoji: Promise<EmojiConfig>;\n}\n\nconst getServerURL = (serverURL: string): string => {\n const result = removeEndingSplash(serverURL);\n\n return isLinkHttp(result) ? result : `https://${result}`;\n};\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 = ['https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo'],\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n ...more\n}: WalineProps): Config => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n lang,\n locale: {\n ...(locales[lang] || locales[defaultLang]),\n ...(typeof locale === 'object' ? locale : {}),\n },\n emoji: getEmojis(emoji),\n wordLimit: Array.isArray(wordLimit)\n ? wordLimit\n : wordLimit\n ? [0, wordLimit]\n : false,\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n pageSize,\n login,\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, hanabi),\n texRenderer: fallback(texRenderer, defaultTexRenderer),\n copyright,\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","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 { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(`${serverURL}/article?path=${encodeURIComponent(paths.join(','))}`, {\n signal,\n })\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article`, {\n method: 'POST',\n headers: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\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 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=\"vemoji\" 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","import type { WalineLocale } 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\nconst 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 timeAgo = (date: Date | string, locale: WalineLocale): string => {\n if (date)\n try {\n if (typeof date === 'string') {\n // compat with mysql output date\n date = new Date(\n date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date\n );\n }\n const oldTime = date.getTime();\n const currTime = new Date().getTime();\n const diffValue = currTime - oldTime;\n\n const days = Math.floor(diffValue / (24 * 3600 * 1000));\n\n // 计算相差小时数\n if (days === 0) {\n // 计算天数后剩余的毫秒数\n const leave1 = diffValue % (24 * 3600 * 1000);\n const hours = Math.floor(leave1 / (3600 * 1000));\n\n //计算相差分钟数\n if (hours === 0) {\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 return `${minutes} ${locale.minutes}`;\n }\n return `${hours} ${locale.hours}`;\n }\n\n if (days < 0) {\n return locale.now;\n }\n\n if (days < 8) {\n return `${days} ${locale.days}`;\n } else {\n return dateFormat(date);\n }\n } catch (error) {\n console.log(error);\n }\n\n return '';\n};\n","import { readonly, ref } from 'vue';\nimport { getUserInfo } from '../utils';\n\nimport type { Ref } from 'vue';\nimport type { UserInfo } from '../utils';\n\nexport type UserInfoRef = Ref<UserInfo | Record<string, never>>;\n\nconst userInfo: UserInfoRef = ref({});\n\nexport const useUserInfo = (): {\n userInfo: UserInfoRef;\n setUserInfo: (userInfo: UserInfo | Record<string, never>) => void;\n} => {\n if (!userInfo.value.token) {\n const info = getUserInfo();\n\n if (info) userInfo.value = info;\n }\n\n return {\n userInfo: readonly(userInfo),\n setUserInfo: (info: UserInfo | Record<string, never>): void => {\n userInfo.value = info;\n },\n };\n};\n","export 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}\n\nconst USER_KEY = 'WALINE_USER';\n\nexport const getUserInfo = (): UserInfo | null => {\n try {\n const localStorageData = localStorage.getItem(USER_KEY);\n const sessionStorageData = sessionStorage.getItem(USER_KEY);\n\n return localStorageData\n ? (JSON.parse(localStorageData) as UserInfo)\n : sessionStorageData\n ? (JSON.parse(sessionStorageData) as UserInfo)\n : null;\n } catch (err) {\n return null;\n }\n};\n","<template>\n <div class=\"wl-comment\">\n <div v-if=\"config.login !== 'disable' && isLogin\" class=\"wl-login-info\">\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"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\" class=\"wl-header-item\" :key=\"kind\">\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 :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element;\n }\n \"\n :id=\"`wl-${kind}`\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n v-model=\"inputs[kind]\"\n />\n </div>\n </div>\n\n <textarea\n class=\"wl-editor\"\n ref=\"editorRef\"\n id=\"wl-edit\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n v-model=\"inputs.editor\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div\n class=\"wl-preview\"\n :style=\"{ display: showPreview ? 'block' : 'none' }\"\n >\n <h4>{{ locale.preview }}:</h4>\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 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 <input\n ref=\"imageUploadRef\"\n class=\"upload\"\n id=\"wl-image-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=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template v-for=\"(config, index) in emoji.tabs\" :key=\"config.name\">\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in config.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=\"(config, index) in emoji.tabs\"\n :key=\"config.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"config.icon\"\n :alt=\"config.name\"\n :title=\"config.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\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit('cancel-reply')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n} from './Icons';\nimport { useInputs, useUserInfo } from '../composables';\nimport {\n getImagefromDataTransfer,\n parseMarkdown,\n getWordNumber,\n parseEmoji,\n postComment,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type { WalineCommentData, WalineImageUploader } from '../typings';\nimport type { Config, EmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\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 },\n\n emits: ['submit', 'cancel-reply'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n\n const { inputs, store } = useInputs();\n const { userInfo, setUserInfo } = 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\n const emoji = ref<DeepReadonly<EmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\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 as HTMLTextAreaElement;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n inputs.editor =\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 inputs.editor = inputs.editor.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\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 as HTMLInputElement;\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 = (): void => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: inputs.nick,\n mail: inputs.mail,\n link: inputs.link,\n ua: navigator.userAgent,\n url: config.value.path,\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 (\n (requiredMeta.indexOf('nick') > -1 || comment.nick) &&\n !comment.nick\n ) {\n inputRefs.value.nick?.focus();\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (requiredMeta.indexOf('mail') > -1 && !comment.mail) {\n inputRefs.value.mail?.focus();\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\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 }\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 store.update({\n nick: comment.nick,\n link: comment.link,\n mail: comment.mail,\n });\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n emit('submit', resp.data!);\n\n inputs.editor = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\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 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n setUserInfo(data.data);\n (data.data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data.data)\n );\n\n window.removeEventListener('message', receiver);\n }\n };\n\n window.addEventListener('message', receiver);\n };\n\n const onLogout = (): void => {\n setUserInfo({});\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 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n setUserInfo(Object.assign({}, userInfo.value, data));\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n window.removeEventListener('message', receiver);\n };\n\n window.addEventListener('message', receiver);\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !(emojiButtonRef.value as HTMLElement).contains(event.target as Node) &&\n !(emojiPopupRef.value as HTMLElement).contains(event.target as Node)\n )\n showEmoji.value = false;\n };\n\n // watch editor\n watch(\n () => inputs.editor,\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 (editorRef.value)\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 emojiConfig.then((config) => {\n emoji.value = config;\n }),\n { immediate: true }\n );\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 onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\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\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n inputs,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n imageUploadRef,\n };\n },\n});\n</script>\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","<template>\n <div class=\"wl-comment\">\n <div v-if=\"config.login !== 'disable' && isLogin\" class=\"wl-login-info\">\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"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\" class=\"wl-header-item\" :key=\"kind\">\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 :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element;\n }\n \"\n :id=\"`wl-${kind}`\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n v-model=\"inputs[kind]\"\n />\n </div>\n </div>\n\n <textarea\n class=\"wl-editor\"\n ref=\"editorRef\"\n id=\"wl-edit\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n v-model=\"inputs.editor\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div\n class=\"wl-preview\"\n :style=\"{ display: showPreview ? 'block' : 'none' }\"\n >\n <h4>{{ locale.preview }}:</h4>\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 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 <input\n ref=\"imageUploadRef\"\n class=\"upload\"\n id=\"wl-image-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=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template v-for=\"(config, index) in emoji.tabs\" :key=\"config.name\">\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in config.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=\"(config, index) in emoji.tabs\"\n :key=\"config.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"config.icon\"\n :alt=\"config.name\"\n :title=\"config.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\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit('cancel-reply')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n} from './Icons';\nimport { useInputs, useUserInfo } from '../composables';\nimport {\n getImagefromDataTransfer,\n parseMarkdown,\n getWordNumber,\n parseEmoji,\n postComment,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type { WalineCommentData, WalineImageUploader } from '../typings';\nimport type { Config, EmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\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 },\n\n emits: ['submit', 'cancel-reply'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n\n const { inputs, store } = useInputs();\n const { userInfo, setUserInfo } = 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\n const emoji = ref<DeepReadonly<EmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\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 as HTMLTextAreaElement;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n inputs.editor =\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 inputs.editor = inputs.editor.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\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 as HTMLInputElement;\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 = (): void => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: inputs.nick,\n mail: inputs.mail,\n link: inputs.link,\n ua: navigator.userAgent,\n url: config.value.path,\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 (\n (requiredMeta.indexOf('nick') > -1 || comment.nick) &&\n !comment.nick\n ) {\n inputRefs.value.nick?.focus();\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (requiredMeta.indexOf('mail') > -1 && !comment.mail) {\n inputRefs.value.mail?.focus();\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\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 }\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 store.update({\n nick: comment.nick,\n link: comment.link,\n mail: comment.mail,\n });\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n emit('submit', resp.data!);\n\n inputs.editor = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\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 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n setUserInfo(data.data);\n (data.data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data.data)\n );\n\n window.removeEventListener('message', receiver);\n }\n };\n\n window.addEventListener('message', receiver);\n };\n\n const onLogout = (): void => {\n setUserInfo({});\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 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n setUserInfo(Object.assign({}, userInfo.value, data));\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n window.removeEventListener('message', receiver);\n };\n\n window.addEventListener('message', receiver);\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !(emojiButtonRef.value as HTMLElement).contains(event.target as Node) &&\n !(emojiPopupRef.value as HTMLElement).contains(event.target as Node)\n )\n showEmoji.value = false;\n };\n\n // watch editor\n watch(\n () => inputs.editor,\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 (editorRef.value)\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 emojiConfig.then((config) => {\n emoji.value = config;\n }),\n { immediate: true }\n );\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 onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\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\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n inputs,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n imageUploadRef,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-item\" :id=\"comment.objectId\">\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.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n\n <span class=\"wl-time\" v-text=\"timeAgo(comment.insertedAt, locale)\" />\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 class=\"wl-meta\" aria-hidden=\"true\">\n <span v-if=\"comment.browser\" v-text=\"comment.browser\" />\n <span v-if=\"comment.os\" v-text=\"comment.os\" />\n </div>\n <div class=\"wl-content\" v-html=\"comment.comment\" />\n\n <div v-if=\"isReplyingCurrent\" class=\"wl-reply-wrapper\">\n <CommentBox\n :replyId=\"comment.objectId\"\n :replyUser=\"comment.nick\"\n :rootId=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', 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 :rootId=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $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 { ReplyIcon, VerifiedIcon } from './Icons';\nimport { isLinkHttp, timeAgo } from '../utils';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { Config } from '../utils';\nimport type { WalineComment } from '../typings';\n\nexport default defineComponent({\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 },\n },\n\n components: {\n CommentBox,\n ReplyIcon,\n VerifiedIcon,\n },\n\n emits: ['submit', 'reply'],\n\n setup(props) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n let { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n link,\n timeAgo,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-item\" :id=\"comment.objectId\">\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.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n\n <span class=\"wl-time\" v-text=\"timeAgo(comment.insertedAt, locale)\" />\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 class=\"wl-meta\" aria-hidden=\"true\">\n <span v-if=\"comment.browser\" v-text=\"comment.browser\" />\n <span v-if=\"comment.os\" v-text=\"comment.os\" />\n </div>\n <div class=\"wl-content\" v-html=\"comment.comment\" />\n\n <div v-if=\"isReplyingCurrent\" class=\"wl-reply-wrapper\">\n <CommentBox\n :replyId=\"comment.objectId\"\n :replyUser=\"comment.nick\"\n :rootId=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', 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 :rootId=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $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 { ReplyIcon, VerifiedIcon } from './Icons';\nimport { isLinkHttp, timeAgo } from '../utils';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { Config } from '../utils';\nimport type { WalineComment } from '../typings';\n\nexport default defineComponent({\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 },\n },\n\n components: {\n CommentBox,\n ReplyIcon,\n VerifiedIcon,\n },\n\n emits: ['submit', 'reply'],\n\n setup(props) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n let { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n link,\n timeAgo,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-action\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"refresh\"\n v-text=\"i18n.refresh\"\n />\n </div>\n\n <div v-else-if=\"status === 'loading'\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n\n <template v-else>\n <div v-if=\"!data.length\" class=\"wl-empty\" v-text=\"i18n.sofa\" />\n\n <div v-else 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 @reply=\"onReply\"\n @submit=\"onSubmit\"\n />\n </div>\n\n <!-- Load more button -->\n <div v-if=\"page < totalPages\" class=\"wl-more\">\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 {\n computed,\n defineComponent,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n watchEffect,\n} from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo } from '../composables';\nimport { locales } from '../config';\nimport { fetchCommentList, getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nexport default defineComponent({\n name: 'Waline-Root',\n\n components: {\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: {\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,\n // default: (): Meta[] => ['nick', 'mail', 'link'],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n requiredMeta: {\n type: Array,\n // default: (): Meta[] => [],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n visitor: {\n type: Boolean,\n // default: false,\n },\n\n dark: {\n type: [String, Boolean],\n // default: false,\n },\n\n lang: {\n type: String,\n // default: 'zh-CN',\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Object.keys(locales).includes(value as string),\n }\n : {}),\n },\n\n locale: {\n type: Object as PropType<Partial<WalineLocale>>,\n },\n\n pageSize: {\n type: Number,\n // default: 10,\n },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n // default: 0,\n ...(SHOULD_VALIDATE\n ? {\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 },\n\n emoji: {\n type: Array as PropType<(string | WalineEmojiInfo)[]>,\n // default: (): string[] => [\n // 'https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo',\n // ],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\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 },\n\n login: {\n type: String as PropType<'enable' | 'disable' | 'force'>,\n // default: 'enable',\n },\n\n highlighter: {\n type: Function as PropType<WalineHighlighter>,\n // default: (text: string): string => text,\n },\n\n imageUploader: {\n type: [Function, false] as PropType<WalineImageUploader>,\n // default: (file: File): Promise<string> =>\n // new Promise((resolve, reject) => {\n // const reader = new FileReader();\n // reader.readAsDataURL(file);\n // reader.onload = (): void => resolve(reader.result?.toString() || '');\n // reader.onerror = reject;\n // }),\n },\n\n texRender: {\n type: Function as PropType<WalineTexRenderer>,\n // default: (blockMode: boolean): string =>\n // blockMode === true\n // ? '<p class=\"vtex\">Tex is not available in preview</p>'\n // : '<span class=\"vtex\">Tex is not available in preview</span>',\n },\n },\n\n setup(props) {\n const config = computed(() => getConfig(props as WalineProps));\n\n const { userInfo } = useUserInfo();\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\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n let stop: () => void;\n\n const fetchComment = (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 fetchCommentList({\n serverURL,\n path,\n pageSize,\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 => fetchComment(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchComment(1);\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n 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 provide('config', config);\n\n watch(() => props.path, refresh);\n\n onMounted(() => {\n refresh();\n\n const style = document.createElement('style');\n\n style.innerText = darkmodeStyle.value;\n\n document.querySelector('[data-waline]')?.appendChild(style);\n\n stop = watchEffect(() => {\n style.innerText = darkmodeStyle.value;\n });\n });\n\n onBeforeUnmount(() => stop());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n data,\n reply,\n\n loadMore,\n refresh,\n onReply,\n onSubmit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-action\">\n <button\n type=\"button\"\n class=\"wl-btn\"\n @click=\"refresh\"\n v-text=\"i18n.refresh\"\n />\n </div>\n\n <div v-else-if=\"status === 'loading'\" class=\"wl-loading\">\n <LoadingIcon :size=\"30\" />\n </div>\n\n <template v-else>\n <div v-if=\"!data.length\" class=\"wl-empty\" v-text=\"i18n.sofa\" />\n\n <div v-else 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 @reply=\"onReply\"\n @submit=\"onSubmit\"\n />\n </div>\n\n <!-- Load more button -->\n <div v-if=\"page < totalPages\" class=\"wl-more\">\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 {\n computed,\n defineComponent,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n watchEffect,\n} from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo } from '../composables';\nimport { locales } from '../config';\nimport { fetchCommentList, getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nexport default defineComponent({\n name: 'Waline-Root',\n\n components: {\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: {\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,\n // default: (): Meta[] => ['nick', 'mail', 'link'],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n requiredMeta: {\n type: Array,\n // default: (): Meta[] => [],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n visitor: {\n type: Boolean,\n // default: false,\n },\n\n dark: {\n type: [String, Boolean],\n // default: false,\n },\n\n lang: {\n type: String,\n // default: 'zh-CN',\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Object.keys(locales).includes(value as string),\n }\n : {}),\n },\n\n locale: {\n type: Object as PropType<Partial<WalineLocale>>,\n },\n\n pageSize: {\n type: Number,\n // default: 10,\n },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n // default: 0,\n ...(SHOULD_VALIDATE\n ? {\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 },\n\n emoji: {\n type: Array as PropType<(string | WalineEmojiInfo)[]>,\n // default: (): string[] => [\n // 'https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo',\n // ],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\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 },\n\n login: {\n type: String as PropType<'enable' | 'disable' | 'force'>,\n // default: 'enable',\n },\n\n highlighter: {\n type: Function as PropType<WalineHighlighter>,\n // default: (text: string): string => text,\n },\n\n imageUploader: {\n type: [Function, false] as PropType<WalineImageUploader>,\n // default: (file: File): Promise<string> =>\n // new Promise((resolve, reject) => {\n // const reader = new FileReader();\n // reader.readAsDataURL(file);\n // reader.onload = (): void => resolve(reader.result?.toString() || '');\n // reader.onerror = reject;\n // }),\n },\n\n texRender: {\n type: Function as PropType<WalineTexRenderer>,\n // default: (blockMode: boolean): string =>\n // blockMode === true\n // ? '<p class=\"vtex\">Tex is not available in preview</p>'\n // : '<span class=\"vtex\">Tex is not available in preview</span>',\n },\n },\n\n setup(props) {\n const config = computed(() => getConfig(props as WalineProps));\n\n const { userInfo } = useUserInfo();\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\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n let stop: () => void;\n\n const fetchComment = (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 fetchCommentList({\n serverURL,\n path,\n pageSize,\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 => fetchComment(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchComment(1);\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n 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 provide('config', config);\n\n watch(() => props.path, refresh);\n\n onMounted(() => {\n refresh();\n\n const style = document.createElement('style');\n\n style.innerText = darkmodeStyle.value;\n\n document.querySelector('[data-waline]')?.appendChild(style);\n\n stop = watchEffect(() => {\n style.innerText = darkmodeStyle.value;\n });\n });\n\n onBeforeUnmount(() => stop());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n data,\n reply,\n\n loadMore,\n refresh,\n onReply,\n onSubmit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","declare const VERSION: string;\n\nexport const version = VERSION;\n"],"names":["LoadingIcon","size","h","width","height","viewBox","preserveAspectRatio","cx","cy","fill","stroke","strokeWidth","r","attributeName","type","repeatCount","dur","values","keyTimes","useStore","cacheKey","storage","content","localStorage","getItem","JSON","parse","err","get","key","set","stringify","setItem","update","store","inputs","useInputs","reactive","nick","mail","link","editor","availableMeta","getMeta","meta","filter","item","includes","defaultUploadImage","file","Promise","resolve","reject","reader","FileReader","readAsDataURL","onload","_a","result","toString","onerror","defaultTexRenderer","blockMode","localeKeys","generateLocale","locale","Object","fromEntries","map","index","en","jp","zhCN","zhTW","ptBR","ru","locales","zh","decodePath","path","decodeURI","removeEndingSplash","replace","isLinkHttp","test","fetchEmoji","Boolean","info","fetch","then","resp","json","emojiInfo","folder","getLink","name","prefix","getServerURL","serverURL","fallback","value","style","isImage","getImagefromDataTransfer","items","image","Array","from","find","getAsFile","fetchCommentList","page","pageSize","signal","token","headers","Authorization","encodeURIComponent","data","errno","TypeError","errmsg","errorCheck","inlineMathStart","inlineMathReg","blockMathReg","parseEmoji","text","emojiMap","placeholder","parseMarkdown","highlighter","texRenderer","marked","setOptions","highlight","undefined","breaks","smartLists","smartypants","extensions","level","tokenizer","src","cap","exec","raw","start","idx","search","length","markedTexExtensions","use","padWithZeros","vNumber","numAsString","timeAgo","date","Date","indexOf","oldTime","getTime","diffValue","days","Math","floor","leave1","hours","leave2","minutes","leave3","round","seconds","now","vDay","getDate","vMonth","getMonth","getFullYear","dateFormat","error","console","log","userInfo","ref","useUserInfo","localStorageData","sessionStorageData","sessionStorage","getUserInfo","readonly","setUserInfo","script$2","defineComponent","components","CloseIcon","class","d","EmojiIcon","ImageIcon","MarkdownIcon","ariaHidden","PreviewIcon","props","rootId","String","default","replyId","replyUser","emits","setup","emit","config","inject","inputRefs","editorRef","imageUploadRef","emojiButtonRef","emojiPopupRef","emoji","tabs","emojiTabIndex","showEmoji","showPreview","previewText","wordNumber","wordLimit","isWordNumberLegal","isSubmitting","computed","isLogin","canUploadImage","imageUploader","insert","textArea","startPosition","selectionStart","endPosition","selectionEnd","scrollTop","substring","focus","uploadImage","uploadText","uploading","url","submitComment","lang","login","requiredMeta","comment","ua","navigator","userAgent","display_name","email","_b","alert","nickError","_c","mailError","_d","anonymous","wordHint","pid","rid","at","method","body","postComment","_e","catch","message","popupHandler","event","contains","target","watch","match","getWords","reduce","accumulator","word","trim","split","getChinese","getWordNumber","autosize","destroy","immediate","emojiConfig","limit","onMounted","document","addEventListener","onUnmounted","removeEventListener","onChange","inputElement","files","onDrop","dataTransfer","preventDefault","onKeyDown","ctrlKey","metaKey","onPaste","clipboardData","onLogin","left","window","innerWidth","top","innerHeight","handler","open","postMessage","receiver","close","remember","onLogout","onProfile","assign","forEach","_hoisted_1","_hoisted_3","_hoisted_7","_hoisted_12","_hoisted_13","href","title","rel","_hoisted_18","_hoisted_19","_openBlock","_createElementBlock","_ctx","_hoisted_2","_createElementVNode","logout","onClick","args","_createVNode","_component_CloseIcon","avatar","alt","_toDisplayString","_normalizeClass","_Fragment","_renderList","kind","for","optional","element","id","$event","_vModelDynamic","_cache","onKeydown","_vModelText","preview","innerHTML","_hoisted_14","_component_MarkdownIcon","actived","_component_EmojiIcon","accept","_component_ImageIcon","_component_PreviewIcon","_createTextVNode","_hoisted_20","textContent","disabled","_createBlock","_component_LoadingIcon","submit","display","_hoisted_25","loading","referrerPolicy","_hoisted_28","active","icon","cancelReply","$emit","script$1","required","reply","CommentBox","ReplyIcon","VerifiedIcon","isReplyingCurrent","objectId","_hoisted_4","_hoisted_5","_component_VerifiedIcon","admin","sticky","insertedAt","_component_ReplyIcon","browser","os","_hoisted_16","_component_CommentBox","onSubmit","onCancelReply","_hoisted_17","children","child","_component_CommentCard","onReply","script","CommentCard","visitor","dark","Number","Function","texRender","location","pathname","copyright","more","emojis","all","emojiInfos","push","isArray","hanabi","getConfig","status","count","totalPages","darkmodeStyle","getDarkStyle","selector","abort","stop","fetchComment","pageNumber","controller","AbortController","bind","refresh","provide","createElement","innerText","querySelector","appendChild","watchEffect","onBeforeUnmount","i18n","loadMore","repliedComment","unshift","version","_hoisted_6","_hoisted_8","sofa","_createCommentVNode","_hoisted_9","_hoisted_11"],"mappings":"8kBAGO,MA0FMA,EAAqD,EAAGC,KAAAA,KACnEC,EACE,MACA,CACEC,MAAOF,EACPG,OAAQH,EACRI,QAAS,cACTC,oBAAqB,YAEvBJ,EACE,SACA,CACEK,GAAI,GACJC,GAAI,GACJC,KAAM,OACNC,OAAQ,eACRC,YAAa,IACbC,EAAG,KAEH,mBAAoB,SAEtBV,EAAE,mBAAoB,CACpBW,cAAe,YACfC,KAAM,SACNC,YAAa,aACbC,IAAK,KACLC,OAAQ,oBACRC,SAAU,UClHLC,EAAYC,IACvB,IAAIC,EAAmC,GACvC,MAAMC,EAAUC,aAAaC,QAAQJ,GAErC,GAAIE,EACF,IACED,EAAUI,KAAKC,MAAMJ,GACrB,MAAOK,IAKX,MAAO,CACLC,IAASC,GAA2BR,EAAQQ,IAAc,KAE1DC,IAAOD,EAAaP,GAClB,IAEED,EAAQQ,GAAOJ,KAAKC,MAAMD,KAAKM,UAAUT,IACzCC,aAAaS,QAAQZ,EAAUK,KAAKM,UAAUV,IAC9C,MAAOM,MAKXM,OAAUX,GAERD,EAAUI,KAAKC,MAAMD,KAAKM,UAAUT,IACpCC,aAAaS,QAAQZ,EAAUK,KAAKM,UAAUV,OCtBpD,IAAIa,EACAC,EAEG,MAAMC,EAAY,KAClBD,IACHD,EAAQf,EAAS,qBAEjBgB,EAASE,EAAS,CAChBC,KAAMJ,EAAMN,IAAY,SAAW,GACnCW,KAAML,EAAMN,IAAY,SAAW,GACnCY,KAAMN,EAAMN,IAAY,SAAW,GACnCa,OAAQ,MAIL,CAAEN,OAAAA,EAAQD,MAAAA,ICzBbQ,EAA8B,CAAC,OAAQ,OAAQ,QAExCC,EAAWC,GACtBA,EAAKC,QAAQC,GAASJ,EAAcK,SAASD,KAIlCE,EAAsBC,GACjC,IAAIC,SAAQ,CAACC,EAASC,KACpB,MAAMC,EAAS,IAAIC,WACnBD,EAAOE,cAAcN,GACrBI,EAAOG,OAAS,KAAY,IAAAC,EAAA,OAAAN,WAAQM,EAAAJ,EAAOK,6BAAQC,aAAc,KACjEN,EAAOO,QAAUR,KAGRS,EAAsBC,IACnB,IAAdA,EACI,sDACA,4DClBAC,EAAa,CACjB,OACA,YACA,OACA,YACA,OACA,WACA,cACA,OACA,SACA,QACA,cACA,UACA,UACA,OACA,UACA,QACA,cACA,UACA,UACA,QACA,OACA,MACA,YACA,QACA,SACA,QACA,SACA,OACA,WACA,aAGWC,EAAkBC,GAC7BC,OAAOC,YACLF,EAAOG,KAAI,CAACtB,EAAMuB,IAAU,CAACN,EAAWM,GAAQvB,MCnCpD,IAAAwB,EAAeN,EAAe,CAC5B,WACA,wCACA,SACA,qCACA,UACA,WACA,kBACA,kBACA,SACA,QACA,eACA,WACA,UACA,eACA,UACA,QACA,eACA,cACA,cACA,YACA,WACA,WACA,YACA,QACA,SACA,QACA,SACA,QACA,2EACA,cC9BFO,EAAeP,EAAe,CAC5B,SACA,yBACA,UACA,mBACA,MACA,QACA,UACA,aACA,OACA,OACA,QACA,OACA,KACA,UACA,QACA,MACA,YACA,KACA,KACA,MACA,KACA,OACA,SACA,SACA,QACA,MACA,SACA,MACA,gDACA,OC9BFQ,EAAeR,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,OC9BFS,EAAeT,EAAe,CAC5B,KACA,KACA,KACA,KACA,aACA,aACA,OACA,SACA,KACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,OC9BFU,EAAeV,EAAe,CAC5B,UACA,0CACA,SACA,8CACA,UACA,WACA,kBACA,4BACA,SACA,YACA,oBACA,cACA,YACA,mBACA,aACA,QACA,gBACA,iBACA,gBACA,cACA,aACA,cACA,WACA,SACA,OACA,QACA,SACA,WACA,gFACA,YC9BFW,EAAeX,EAAe,CAC5B,YACA,uCACA,YACA,yDACA,WACA,iBACA,uBACA,yBACA,YACA,WACA,iBACA,cACA,WACA,oBACA,SACA,SACA,wBACA,eACA,wBACA,wBACA,aACA,eACA,WACA,iBACA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"}
1
+ {"version":3,"file":"component.js","sources":["../src/components/Icons.ts","../src/composables/store.ts","../src/composables/inputs.ts","../src/config/default.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/utils/path.ts","../src/utils/emoji.ts","../src/utils/config.ts","../src/utils/darkmode.ts","../src/utils/data.ts","../src/utils/fetch.ts","../src/utils/markedMathExtension.ts","../src/utils/markdown.ts","../src/utils/timeAgo.ts","../src/composables/userInfo.ts","../src/utils/userInfo.ts","../src/components/CommentBox.vue","../src/utils/wordCount.ts","../src/components/CommentBox.vue?vue&type=template&id=969569c8&lang.js","../src/components/CommentCard.vue","../src/components/CommentCard.vue?vue&type=template&id=5dd9348f&lang.js","../src/components/Waline.vue","../src/components/Waline.vue?vue&type=template&id=222c3e24&lang.js","../src/version.ts"],"sourcesContent":["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 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 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: '18', height: '18' },\n h('path', {\n d: 'M1019.2 720C1001.6 625.6 968 566.4 904 497.6c-89.6-89.6-214.4-150.4-347.2-176v-120c0-25.6-8-51.2-25.6-64-33.6-30.4-81.6-30.4-112-4.8L33.6 441.6C12.8 459.2 0 484.8 0 510.4c0 25.6 12.8 51.2 30.4 68.8l385.6 312c17.6 12.8 33.6 17.6 51.2 17.6 12.8 0 25.6-4.8 38.4-8C536 888 552 857.6 552 824v-99.2c124.8 20.8 248 86.4 339.2 140.8 25.6 17.6 59.2 17.6 89.6 0 25.6-17.6 43.2-46.4 43.2-76.8 0-33.6 0-56-4.8-68.8zm-500.8-89.6-46.4-4.8v193.6L86.4 510.4 472 201.6V400l38.4 4.8c128 12.8 248 68.8 334.4 153.6 51.2 56 76.8 102.4 94.4 179.2 0 4.8 4.8 20.8 4.8 51.2C835.2 720 672 640 518.4 630.4z',\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","export interface Store {\n get: <T = unknown>(key: string) => T | null;\n set: <T = unknown>(key: string, content: T) => void;\n update: <T = unknown>(content: T) => void;\n}\n\nexport const useStore = (cacheKey: string): Store => {\n let storage: Record<string, unknown> = {};\n const content = localStorage.getItem(cacheKey);\n\n if (content) {\n try {\n storage = JSON.parse(content) as Record<string, unknown>;\n } catch (err) {\n // do nothing\n }\n }\n\n return {\n get: <T>(key: string): T | null => (storage[key] as T) || null,\n\n set<T>(key: string, content: T): void {\n try {\n // make sure the content can be stringify and make a deep copy here\n storage[key] = JSON.parse(JSON.stringify(content));\n localStorage.setItem(cacheKey, JSON.stringify(storage));\n } catch (err) {\n // do nothing\n }\n },\n\n update<T>(content: T): void {\n // make sure the content can be stringify and make a deep copy here\n storage = JSON.parse(JSON.stringify(content)) as Record<string, unknown>;\n localStorage.setItem(cacheKey, JSON.stringify(storage));\n },\n };\n};\n","import { reactive } from 'vue';\nimport { useStore } from './store';\n\nimport type { Store } from './store';\n\nexport interface Inputs {\n nick: string;\n mail: string;\n link: string;\n editor: string;\n}\n\nlet store: Store;\nlet inputs: Inputs;\n\nexport const useInputs = (): { inputs: Inputs; store: Store } => {\n if (!inputs) {\n store = useStore('WALINE_USER_CACHE');\n\n inputs = reactive({\n nick: store.get<string>('nick') || '',\n mail: store.get<string>('mail') || '',\n link: store.get<string>('link') || '',\n editor: '',\n });\n }\n\n return { inputs, store };\n};\n","import type { WalineMeta } 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 const reader = new FileReader();\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=\"vtex\">Tex is not available in preview</p>'\n : '<span class=\"vtex\">Tex is not available in preview</span>';\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 '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];\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 '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]);\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 'コメントは $0 から $1 ワードの間でなければなりません!\\n 現在の単語番号: $2',\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 '评论字数应在 $0 到 $1 字之间!\\n当前字数:$2',\n '匿名',\n]);\n","import { generateLocale } from './generate';\n\nexport default generateLocale([\n '暱稱',\n '郵箱',\n '網址',\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 '評論字數應在 $0 到 $1 字之間!\\n當前字數:$2',\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 '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]);\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 'Пожалуйста, введите комментарии от $0 до $1 слов!\\nНомер текущего слова: $2',\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 locales: 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 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 { Store, useStore } from '../composables/store';\nimport { removeEndingSplash } from './path';\n\nimport type { EmojiConfig } from './config';\nimport type { WalineEmojiInfo } from '../typings';\n\nlet store: Store;\n\nconst hasVersion = (url: string): boolean =>\n Boolean(/@[0-9]+\\.[0-9]+\\.[0-9]+/.test(url));\n\nconst fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {\n if (!store) store = useStore('WALINE_EMOJI');\n\n const result = hasVersion(link);\n\n if (result) {\n const info = store.get<WalineEmojiInfo>(link);\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) store.set(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<EmojiConfig> =>\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: EmojiConfig = {\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","import {\n defaultLang,\n defaultUploadImage,\n defaultTexRenderer,\n getMeta,\n locales,\n} from '../config';\n\nimport { decodePath, isLinkHttp, removeEndingSplash } from './path';\nimport { getEmojis } from './emoji';\n\nimport type {\n WalineEmojiInfo,\n WalineEmojiMaps,\n WalineLocale,\n WalineProps,\n} from '../typings';\nimport hanabi from 'hanabi';\n\nexport interface EmojiConfig {\n tabs: Pick<WalineEmojiInfo, 'name' | 'icon' | 'items'>[];\n map: WalineEmojiMaps;\n}\n\nexport interface Config\n extends Required<\n Pick<\n WalineProps,\n | 'path'\n | 'lang'\n | 'meta'\n | 'pageSize'\n | 'requiredMeta'\n | 'imageUploader'\n | 'highlighter'\n | 'texRenderer'\n | 'copyright'\n | 'login'\n >\n >,\n Pick<WalineProps, 'dark' | 'serverURL'> {\n locale: WalineLocale;\n wordLimit: [number, number] | false;\n emoji: Promise<EmojiConfig>;\n}\n\nconst getServerURL = (serverURL: string): string => {\n const result = removeEndingSplash(serverURL);\n\n return isLinkHttp(result) ? result : `https://${result}`;\n};\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 = ['https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo'],\n meta = ['nick', 'mail', 'link'],\n requiredMeta = [],\n pageSize = 10,\n wordLimit,\n imageUploader,\n highlighter,\n texRenderer,\n copyright = true,\n login = 'enable',\n ...more\n}: WalineProps): Config => ({\n serverURL: getServerURL(serverURL),\n path: decodePath(path),\n lang,\n locale: {\n ...(locales[lang] || locales[defaultLang]),\n ...(typeof locale === 'object' ? locale : {}),\n },\n emoji: getEmojis(emoji),\n wordLimit: Array.isArray(wordLimit)\n ? wordLimit\n : wordLimit\n ? [0, wordLimit]\n : false,\n meta: getMeta(meta),\n requiredMeta: getMeta(requiredMeta),\n pageSize,\n login,\n imageUploader: fallback(imageUploader, defaultUploadImage),\n highlighter: fallback(highlighter, hanabi),\n texRenderer: fallback(texRenderer, defaultTexRenderer),\n copyright,\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","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 { WalineComment, WalineCommentData } from '../typings';\n\nexport interface FetchErrorData {\n errno: number;\n errmsg: string;\n}\n\nconst errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {\n if (typeof data === 'object' && (data as FetchErrorData).errno)\n throw new TypeError(\n `Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${\n (data as FetchErrorData).errmsg\n }`\n );\n\n return data as T;\n};\n\nexport interface FetchCountOptions {\n serverURL: string;\n paths: string[];\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchCommentCount = ({\n serverURL,\n paths,\n signal,\n token,\n}: FetchCountOptions): Promise<number[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return (\n fetch(\n `${serverURL}/comment?type=count&url=${encodeURIComponent(\n paths.join(',')\n )}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<number | number[]>)\n .then((data) => errorCheck(data, 'comment count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]))\n );\n};\nexport interface FetchRecentOptions {\n serverURL: string;\n count: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport const fetchRecentComment = ({\n serverURL,\n count,\n signal,\n token,\n}: FetchRecentOptions): Promise<WalineComment[]> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?type=recent&count=${count}`, {\n signal,\n headers,\n })\n .then((resp) => resp.json() as Promise<WalineComment[]>)\n .then((data) => errorCheck(data, 'recent comment'));\n};\n\nexport interface FetchListOptions {\n serverURL: string;\n path: string;\n page: number;\n pageSize: number;\n signal: AbortSignal;\n token?: string;\n}\n\nexport interface FetchListResult {\n count: number;\n data: WalineComment[];\n totalPages: number;\n}\n\nexport const fetchCommentList = ({\n serverURL,\n path,\n page,\n pageSize,\n signal,\n token,\n}: FetchListOptions): Promise<FetchListResult> => {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(\n `${serverURL}/comment?path=${encodeURIComponent(\n path\n )}&pageSize=${pageSize}&page=${page}`,\n { signal, headers }\n )\n .then((resp) => resp.json() as Promise<FetchListResult>)\n .then((data) => errorCheck(data, 'comment list'));\n};\n\nexport interface PostCommentOptions {\n serverURL: string;\n lang: string;\n token?: string;\n comment: WalineCommentData;\n}\n\nexport interface PostCommentResponse {\n data?: WalineComment;\n errmsg?: string;\n}\n\nexport const postComment = ({\n serverURL,\n lang,\n token,\n comment,\n}: PostCommentOptions): Promise<PostCommentResponse> => {\n const headers: Record<string, string> = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n };\n\n if (token) headers.Authorization = `Bearer ${token}`;\n\n return fetch(`${serverURL}/comment?lang=${lang}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(comment),\n }).then((resp) => resp.json() as Promise<PostCommentResponse>);\n};\n\nexport interface FetchPageviewsOptions {\n serverURL: string;\n paths: string[];\n signal: AbortSignal;\n}\n\nexport const fetchPageviews = ({\n serverURL,\n paths,\n signal,\n}: FetchPageviewsOptions): Promise<number[]> =>\n fetch(`${serverURL}/article?path=${encodeURIComponent(paths.join(','))}`, {\n signal,\n })\n .then((resp) => resp.json() as Promise<number[] | number>)\n .then((data) => errorCheck(data, 'visit count'))\n // TODO: Improve this API\n .then((counts) => (Array.isArray(counts) ? counts : [counts]));\n\nexport interface UpdatePageviewsOptions {\n serverURL: string;\n path: string;\n}\n\nexport const updatePageviews = ({\n serverURL,\n path,\n}: UpdatePageviewsOptions): Promise<number> =>\n fetch(`${serverURL}/article`, {\n method: 'POST',\n headers: {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ path }),\n })\n .then((resp) => resp.json() as Promise<number>)\n .then((data) => errorCheck(data, 'visit count'));\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 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=\"vemoji\" 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","import type { WalineLocale } 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\nconst 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 timeAgo = (date: Date | string, locale: WalineLocale): string => {\n if (date)\n try {\n if (typeof date === 'string') {\n // compat with mysql output date\n date = new Date(\n date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date\n );\n }\n const oldTime = date.getTime();\n const currTime = new Date().getTime();\n const diffValue = currTime - oldTime;\n\n const days = Math.floor(diffValue / (24 * 3600 * 1000));\n\n // 计算相差小时数\n if (days === 0) {\n // 计算天数后剩余的毫秒数\n const leave1 = diffValue % (24 * 3600 * 1000);\n const hours = Math.floor(leave1 / (3600 * 1000));\n\n //计算相差分钟数\n if (hours === 0) {\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 return `${minutes} ${locale.minutes}`;\n }\n return `${hours} ${locale.hours}`;\n }\n\n if (days < 0) {\n return locale.now;\n }\n\n if (days < 8) {\n return `${days} ${locale.days}`;\n } else {\n return dateFormat(date);\n }\n } catch (error) {\n console.log(error);\n }\n\n return '';\n};\n","import { readonly, ref } from 'vue';\nimport { getUserInfo } from '../utils';\n\nimport type { Ref } from 'vue';\nimport type { UserInfo } from '../utils';\n\nexport type UserInfoRef = Ref<UserInfo | Record<string, never>>;\n\nconst userInfo: UserInfoRef = ref({});\n\nexport const useUserInfo = (): {\n userInfo: UserInfoRef;\n setUserInfo: (userInfo: UserInfo | Record<string, never>) => void;\n} => {\n if (!userInfo.value.token) {\n const info = getUserInfo();\n\n if (info) userInfo.value = info;\n }\n\n return {\n userInfo: readonly(userInfo),\n setUserInfo: (info: UserInfo | Record<string, never>): void => {\n userInfo.value = info;\n },\n };\n};\n","export 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}\n\nconst USER_KEY = 'WALINE_USER';\n\nexport const getUserInfo = (): UserInfo | null => {\n try {\n const localStorageData = localStorage.getItem(USER_KEY);\n const sessionStorageData = sessionStorage.getItem(USER_KEY);\n\n return localStorageData\n ? (JSON.parse(localStorageData) as UserInfo)\n : sessionStorageData\n ? (JSON.parse(sessionStorageData) as UserInfo)\n : null;\n } catch (err) {\n return null;\n }\n};\n","<template>\n <div class=\"wl-comment\">\n <div v-if=\"config.login !== 'disable' && isLogin\" class=\"wl-login-info\">\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"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\" class=\"wl-header-item\" :key=\"kind\">\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 :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element;\n }\n \"\n :id=\"`wl-${kind}`\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n v-model=\"inputs[kind]\"\n />\n </div>\n </div>\n\n <textarea\n class=\"wl-editor\"\n ref=\"editorRef\"\n id=\"wl-edit\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n v-model=\"inputs.editor\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div\n class=\"wl-preview\"\n :style=\"{ display: showPreview ? 'block' : 'none' }\"\n >\n <h4>{{ locale.preview }}:</h4>\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 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 <input\n ref=\"imageUploadRef\"\n class=\"upload\"\n id=\"wl-image-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=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template v-for=\"(config, index) in emoji.tabs\" :key=\"config.name\">\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in config.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=\"(config, index) in emoji.tabs\"\n :key=\"config.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"config.icon\"\n :alt=\"config.name\"\n :title=\"config.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\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit('cancel-reply')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n} from './Icons';\nimport { useInputs, useUserInfo } from '../composables';\nimport {\n getImagefromDataTransfer,\n parseMarkdown,\n getWordNumber,\n parseEmoji,\n postComment,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type { WalineCommentData, WalineImageUploader } from '../typings';\nimport type { Config, EmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\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 },\n\n emits: ['submit', 'cancel-reply'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n\n const { inputs, store } = useInputs();\n const { userInfo, setUserInfo } = 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\n const emoji = ref<DeepReadonly<EmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\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 as HTMLTextAreaElement;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n inputs.editor =\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 inputs.editor = inputs.editor.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\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 as HTMLInputElement;\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 = (): void => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: inputs.nick,\n mail: inputs.mail,\n link: inputs.link,\n ua: navigator.userAgent,\n url: config.value.path,\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 (\n (requiredMeta.indexOf('nick') > -1 || comment.nick) &&\n !comment.nick\n ) {\n inputRefs.value.nick?.focus();\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (requiredMeta.indexOf('mail') > -1 && !comment.mail) {\n inputRefs.value.mail?.focus();\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\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 }\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 store.update({\n nick: comment.nick,\n link: comment.link,\n mail: comment.mail,\n });\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n emit('submit', resp.data!);\n\n inputs.editor = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\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 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n setUserInfo(data.data);\n (data.data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data.data)\n );\n\n window.removeEventListener('message', receiver);\n }\n };\n\n window.addEventListener('message', receiver);\n };\n\n const onLogout = (): void => {\n setUserInfo({});\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 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n setUserInfo(Object.assign({}, userInfo.value, data));\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n window.removeEventListener('message', receiver);\n };\n\n window.addEventListener('message', receiver);\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !(emojiButtonRef.value as HTMLElement).contains(event.target as Node) &&\n !(emojiPopupRef.value as HTMLElement).contains(event.target as Node)\n )\n showEmoji.value = false;\n };\n\n // watch editor\n watch(\n () => inputs.editor,\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 (editorRef.value)\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 emojiConfig.then((config) => {\n emoji.value = config;\n }),\n { immediate: true }\n );\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 onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\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\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n inputs,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n imageUploadRef,\n };\n },\n});\n</script>\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","<template>\n <div class=\"wl-comment\">\n <div v-if=\"config.login !== 'disable' && isLogin\" class=\"wl-login-info\">\n <div class=\"wl-avatar\">\n <button class=\"wl-logout-btn\" :title=\"locale.logout\" @click=\"onLogout\">\n <CloseIcon :size=\"14\" />\n </button>\n\n <img :src=\"userInfo.avatar\" alt=\"avatar\" />\n </div>\n <a\n href=\"#\"\n class=\"wl-login-nick\"\n aria-label=\"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\" class=\"wl-header-item\" :key=\"kind\">\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 :ref=\"\n (element) => {\n if (element) inputRefs[kind] = element;\n }\n \"\n :id=\"`wl-${kind}`\"\n :class=\"['wl-input', `wl-${kind}`]\"\n :name=\"kind\"\n :type=\"kind === 'mail' ? 'email' : 'text'\"\n v-model=\"inputs[kind]\"\n />\n </div>\n </div>\n\n <textarea\n class=\"wl-editor\"\n ref=\"editorRef\"\n id=\"wl-edit\"\n :placeholder=\"replyUser ? `@${replyUser}` : locale.placeholder\"\n v-model=\"inputs.editor\"\n @keydown=\"onKeyDown\"\n @drop=\"onDrop\"\n @paste=\"onPaste\"\n />\n\n <div\n class=\"wl-preview\"\n :style=\"{ display: showPreview ? 'block' : 'none' }\"\n >\n <h4>{{ locale.preview }}:</h4>\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 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 <input\n ref=\"imageUploadRef\"\n class=\"upload\"\n id=\"wl-image-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=\"emojiPopupRef\"\n class=\"wl-emoji-popup\"\n :class=\"{ display: showEmoji }\"\n >\n <template v-for=\"(config, index) in emoji.tabs\" :key=\"config.name\">\n <div v-if=\"index === emojiTabIndex\" class=\"wl-tab-wrapper\">\n <button\n v-for=\"key in config.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=\"(config, index) in emoji.tabs\"\n :key=\"config.name\"\n class=\"wl-tab\"\n :class=\"{ active: emojiTabIndex === index }\"\n @click=\"emojiTabIndex = index\"\n >\n <img\n class=\"wl-emoji\"\n :src=\"config.icon\"\n :alt=\"config.name\"\n :title=\"config.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\"\n class=\"wl-close\"\n :title=\"locale.cancelReply\"\n @click=\"$emit('cancel-reply')\"\n >\n <CloseIcon :size=\"24\" />\n </button>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport autosize from 'autosize';\nimport {\n computed,\n defineComponent,\n inject,\n onMounted,\n onUnmounted,\n ref,\n watch,\n} from 'vue';\n\nimport {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\n} from './Icons';\nimport { useInputs, useUserInfo } from '../composables';\nimport {\n getImagefromDataTransfer,\n parseMarkdown,\n getWordNumber,\n parseEmoji,\n postComment,\n} from '../utils';\n\nimport type { ComputedRef, DeepReadonly } from 'vue';\nimport type { WalineCommentData, WalineImageUploader } from '../typings';\nimport type { Config, EmojiConfig } from '../utils';\n\nexport default defineComponent({\n name: 'CommentBox',\n\n components: {\n CloseIcon,\n EmojiIcon,\n ImageIcon,\n MarkdownIcon,\n PreviewIcon,\n LoadingIcon,\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 },\n\n emits: ['submit', 'cancel-reply'],\n\n setup(props, { emit }) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n\n const { inputs, store } = useInputs();\n const { userInfo, setUserInfo } = 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\n const emoji = ref<DeepReadonly<EmojiConfig>>({ tabs: [], map: {} });\n const emojiTabIndex = ref(0);\n const showEmoji = ref(false);\n const showPreview = ref(false);\n const previewText = ref('');\n const wordNumber = ref(0);\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 as HTMLTextAreaElement;\n const startPosition = textArea.selectionStart;\n const endPosition = textArea.selectionEnd || 0;\n const scrollTop = textArea.scrollTop;\n\n inputs.editor =\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 inputs.editor = inputs.editor.replace(\n uploadText,\n `\\r\\n![${file.name}](${url})`\n );\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 as HTMLInputElement;\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 = (): void => {\n const { serverURL, lang, login, wordLimit, requiredMeta } = config.value;\n\n const comment: WalineCommentData = {\n comment: content.value,\n nick: inputs.nick,\n mail: inputs.mail,\n link: inputs.link,\n ua: navigator.userAgent,\n url: config.value.path,\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 (\n (requiredMeta.indexOf('nick') > -1 || comment.nick) &&\n !comment.nick\n ) {\n inputRefs.value.nick?.focus();\n return alert(locale.value.nickError);\n }\n\n // check mail\n if (requiredMeta.indexOf('mail') > -1 && !comment.mail) {\n inputRefs.value.mail?.focus();\n return alert(locale.value.mailError);\n }\n\n // check comment\n if (!comment.comment) {\n editorRef.value?.focus();\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 }\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 store.update({\n nick: comment.nick,\n link: comment.link,\n mail: comment.mail,\n });\n\n if (resp.errmsg) return alert(resp.errmsg);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n emit('submit', resp.data!);\n\n inputs.editor = '';\n\n previewText.value = '';\n\n if (props.replyId) emit('cancel-reply');\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 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'userInfo') return;\n\n if (data.data.token) {\n handler?.close();\n setUserInfo(data.data);\n (data.data.remember ? localStorage : sessionStorage).setItem(\n 'WALINE_USER',\n JSON.stringify(data.data)\n );\n\n window.removeEventListener('message', receiver);\n }\n };\n\n window.addEventListener('message', receiver);\n };\n\n const onLogout = (): void => {\n setUserInfo({});\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 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n handler?.postMessage({ type: 'TOKEN', data: userInfo.value!.token }, '*');\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const receiver = ({ data }: any): void => {\n if (!data || data.type !== 'profile') return;\n\n setUserInfo(Object.assign({}, userInfo.value, data));\n [localStorage, sessionStorage]\n .filter((store) => store.getItem('WALINE_USER'))\n .forEach((store) =>\n store.setItem('WALINE_USER', JSON.stringify(userInfo))\n );\n window.removeEventListener('message', receiver);\n };\n\n window.addEventListener('message', receiver);\n };\n\n const popupHandler = (event: MouseEvent): void => {\n if (\n !(emojiButtonRef.value as HTMLElement).contains(event.target as Node) &&\n !(emojiPopupRef.value as HTMLElement).contains(event.target as Node)\n )\n showEmoji.value = false;\n };\n\n // watch editor\n watch(\n () => inputs.editor,\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 (editorRef.value)\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 emojiConfig.then((config) => {\n emoji.value = config;\n }),\n { immediate: true }\n );\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 onMounted(() => {\n document.body.addEventListener('click', popupHandler);\n });\n\n onUnmounted(() => {\n document.body.removeEventListener('click', popupHandler);\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\n isLogin,\n userInfo,\n isSubmitting,\n\n // word\n wordNumber,\n wordLimit,\n isWordNumberLegal,\n\n // inputs\n inputs,\n\n // emoji\n emoji,\n emojiTabIndex,\n showEmoji,\n\n // image\n canUploadImage,\n\n // preview\n previewText,\n showPreview,\n\n // ref\n inputRefs,\n editorRef,\n emojiButtonRef,\n emojiPopupRef,\n imageUploadRef,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-item\" :id=\"comment.objectId\">\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.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n\n <span class=\"wl-time\" v-text=\"timeAgo(comment.insertedAt, locale)\" />\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 class=\"wl-meta\" aria-hidden=\"true\">\n <span v-if=\"comment.browser\" v-text=\"comment.browser\" />\n <span v-if=\"comment.os\" v-text=\"comment.os\" />\n </div>\n <div class=\"wl-content\" v-html=\"comment.comment\" />\n\n <div v-if=\"isReplyingCurrent\" class=\"wl-reply-wrapper\">\n <CommentBox\n :replyId=\"comment.objectId\"\n :replyUser=\"comment.nick\"\n :rootId=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', 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 :rootId=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $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 { ReplyIcon, VerifiedIcon } from './Icons';\nimport { isLinkHttp, timeAgo } from '../utils';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { Config } from '../utils';\nimport type { WalineComment } from '../typings';\n\nexport default defineComponent({\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 },\n },\n\n components: {\n CommentBox,\n ReplyIcon,\n VerifiedIcon,\n },\n\n emits: ['submit', 'reply'],\n\n setup(props) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n let { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n link,\n timeAgo,\n };\n },\n});\n</script>\n","<template>\n <div class=\"wl-item\" :id=\"comment.objectId\">\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.sticky\" class=\"wl-badge\" v-text=\"locale.sticky\" />\n\n <span class=\"wl-time\" v-text=\"timeAgo(comment.insertedAt, locale)\" />\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 class=\"wl-meta\" aria-hidden=\"true\">\n <span v-if=\"comment.browser\" v-text=\"comment.browser\" />\n <span v-if=\"comment.os\" v-text=\"comment.os\" />\n </div>\n <div class=\"wl-content\" v-html=\"comment.comment\" />\n\n <div v-if=\"isReplyingCurrent\" class=\"wl-reply-wrapper\">\n <CommentBox\n :replyId=\"comment.objectId\"\n :replyUser=\"comment.nick\"\n :rootId=\"rootId\"\n @submit=\"$emit('submit', $event)\"\n @cancel-reply=\"$emit('reply', 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 :rootId=\"rootId\"\n @reply=\"$emit('reply', $event)\"\n @submit=\"$emit('submit', $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 { ReplyIcon, VerifiedIcon } from './Icons';\nimport { isLinkHttp, timeAgo } from '../utils';\n\nimport type { ComputedRef, PropType } from 'vue';\nimport type { Config } from '../utils';\nimport type { WalineComment } from '../typings';\n\nexport default defineComponent({\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 },\n },\n\n components: {\n CommentBox,\n ReplyIcon,\n VerifiedIcon,\n },\n\n emits: ['submit', 'reply'],\n\n setup(props) {\n const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;\n const locale = computed(() => config.value.locale);\n\n const link = computed(() => {\n let { link } = props.comment;\n\n return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';\n });\n\n const isReplyingCurrent = computed(\n () => props.comment.objectId === props.reply?.objectId\n );\n\n return {\n config,\n locale,\n\n isReplyingCurrent,\n link,\n timeAgo,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\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 @reply=\"onReply\"\n @submit=\"onSubmit\"\n />\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-action\">\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-more\">\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 {\n computed,\n defineComponent,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n watchEffect,\n} from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo } from '../composables';\nimport { locales } from '../config';\nimport { fetchCommentList, getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nexport default defineComponent({\n name: 'WalineRoot',\n\n components: {\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: {\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,\n // default: (): Meta[] => ['nick', 'mail', 'link'],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n requiredMeta: {\n type: Array,\n // default: (): Meta[] => [],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n visitor: {\n type: Boolean,\n // default: false,\n },\n\n dark: {\n type: [String, Boolean],\n // default: false,\n },\n\n lang: {\n type: String,\n // default: 'zh-CN',\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Object.keys(locales).includes(value as string),\n }\n : {}),\n },\n\n locale: {\n type: Object as PropType<Partial<WalineLocale>>,\n },\n\n pageSize: {\n type: Number,\n // default: 10,\n },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n // default: 0,\n ...(SHOULD_VALIDATE\n ? {\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 },\n\n emoji: {\n type: Array as PropType<(string | WalineEmojiInfo)[]>,\n // default: (): string[] => [\n // 'https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo',\n // ],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\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 },\n\n login: {\n type: String as PropType<'enable' | 'disable' | 'force'>,\n // default: 'enable',\n },\n\n highlighter: {\n type: Function as PropType<WalineHighlighter>,\n // default: (text: string): string => text,\n },\n\n imageUploader: {\n type: [Function, false] as PropType<WalineImageUploader>,\n // default: (file: File): Promise<string> =>\n // new Promise((resolve, reject) => {\n // const reader = new FileReader();\n // reader.readAsDataURL(file);\n // reader.onload = (): void => resolve(reader.result?.toString() || '');\n // reader.onerror = reject;\n // }),\n },\n\n texRender: {\n type: Function as PropType<WalineTexRenderer>,\n // default: (blockMode: boolean): string =>\n // blockMode === true\n // ? '<p class=\"vtex\">Tex is not available in preview</p>'\n // : '<span class=\"vtex\">Tex is not available in preview</span>',\n },\n },\n\n setup(props) {\n const config = computed(() => getConfig(props as WalineProps));\n\n const { userInfo } = useUserInfo();\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\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n let stop: () => void;\n\n const fetchComment = (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 fetchCommentList({\n serverURL,\n path,\n pageSize,\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 => fetchComment(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchComment(1);\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n 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 provide('config', config);\n\n watch(() => props.path, refresh);\n\n onMounted(() => {\n refresh();\n\n const style = document.createElement('style');\n\n style.innerText = darkmodeStyle.value;\n\n document.querySelector('[data-waline]')?.appendChild(style);\n\n stop = watchEffect(() => {\n style.innerText = darkmodeStyle.value;\n });\n });\n\n onBeforeUnmount(() => stop());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n data,\n reply,\n\n loadMore,\n refresh,\n onReply,\n onSubmit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","<template>\n <div data-waline>\n <CommentBox v-if=\"!reply\" @submit=\"onSubmit\" />\n <div class=\"wl-count\">\n <span v-if=\"count\" class=\"wl-num\" v-text=\"count\" />\n {{ i18n.comment }}\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 @reply=\"onReply\"\n @submit=\"onSubmit\"\n />\n </div>\n\n <div v-if=\"status === 'error'\" class=\"wl-action\">\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-more\">\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 {\n computed,\n defineComponent,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n watch,\n watchEffect,\n} from 'vue';\nimport CommentBox from './CommentBox.vue';\nimport CommentCard from './CommentCard.vue';\nimport { LoadingIcon } from './Icons';\nimport { useUserInfo } from '../composables';\nimport { locales } from '../config';\nimport { fetchCommentList, getConfig, getDarkStyle } from '../utils';\n\nimport type { PropType } from 'vue';\nimport type {\n WalineComment,\n WalineEmojiInfo,\n WalineHighlighter,\n WalineTexRenderer,\n WalineImageUploader,\n WalineLocale,\n WalineProps,\n} from '../typings';\n\ndeclare const SHOULD_VALIDATE: boolean;\ndeclare const VERSION: string;\n\nexport default defineComponent({\n name: 'WalineRoot',\n\n components: {\n CommentBox,\n CommentCard,\n LoadingIcon,\n },\n\n props: {\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,\n // default: (): Meta[] => ['nick', 'mail', 'link'],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n requiredMeta: {\n type: Array,\n // default: (): Meta[] => [],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Array.isArray(value) &&\n value.every((item) => ['nick', 'mail', 'link'].includes(item)),\n }\n : {}),\n },\n\n visitor: {\n type: Boolean,\n // default: false,\n },\n\n dark: {\n type: [String, Boolean],\n // default: false,\n },\n\n lang: {\n type: String,\n // default: 'zh-CN',\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\n Object.keys(locales).includes(value as string),\n }\n : {}),\n },\n\n locale: {\n type: Object as PropType<Partial<WalineLocale>>,\n },\n\n pageSize: {\n type: Number,\n // default: 10,\n },\n\n wordLimit: {\n type: [Number, Array] as PropType<number | [number, number]>,\n // default: 0,\n ...(SHOULD_VALIDATE\n ? {\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 },\n\n emoji: {\n type: Array as PropType<(string | WalineEmojiInfo)[]>,\n // default: (): string[] => [\n // 'https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo',\n // ],\n ...(SHOULD_VALIDATE\n ? {\n validator: (value: unknown): boolean =>\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 },\n\n login: {\n type: String as PropType<'enable' | 'disable' | 'force'>,\n // default: 'enable',\n },\n\n highlighter: {\n type: Function as PropType<WalineHighlighter>,\n // default: (text: string): string => text,\n },\n\n imageUploader: {\n type: [Function, false] as PropType<WalineImageUploader>,\n // default: (file: File): Promise<string> =>\n // new Promise((resolve, reject) => {\n // const reader = new FileReader();\n // reader.readAsDataURL(file);\n // reader.onload = (): void => resolve(reader.result?.toString() || '');\n // reader.onerror = reject;\n // }),\n },\n\n texRender: {\n type: Function as PropType<WalineTexRenderer>,\n // default: (blockMode: boolean): string =>\n // blockMode === true\n // ? '<p class=\"vtex\">Tex is not available in preview</p>'\n // : '<span class=\"vtex\">Tex is not available in preview</span>',\n },\n },\n\n setup(props) {\n const config = computed(() => getConfig(props as WalineProps));\n\n const { userInfo } = useUserInfo();\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\n const data = ref<WalineComment[]>([]);\n const reply = ref<WalineComment | null>(null);\n\n const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));\n\n // eslint-disable-next-line vue/no-setup-props-destructure\n let abort: () => void;\n let stop: () => void;\n\n const fetchComment = (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 fetchCommentList({\n serverURL,\n path,\n pageSize,\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 => fetchComment(page.value + 1);\n\n const refresh = (): void => {\n count.value = 0;\n data.value = [];\n fetchComment(1);\n };\n\n const onReply = (comment: WalineComment | null): void => {\n reply.value = comment;\n };\n\n const onSubmit = (comment: WalineComment): void => {\n 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 provide('config', config);\n\n watch(() => props.path, refresh);\n\n onMounted(() => {\n refresh();\n\n const style = document.createElement('style');\n\n style.innerText = darkmodeStyle.value;\n\n document.querySelector('[data-waline]')?.appendChild(style);\n\n stop = watchEffect(() => {\n style.innerText = darkmodeStyle.value;\n });\n });\n\n onBeforeUnmount(() => stop());\n\n return {\n config,\n darkmodeStyle,\n i18n: computed(() => config.value.locale),\n\n status,\n count,\n page,\n totalPages,\n data,\n reply,\n\n loadMore,\n refresh,\n onReply,\n onSubmit,\n\n version: VERSION,\n };\n },\n});\n</script>\n","declare const VERSION: string;\n\nexport const version = VERSION;\n"],"names":["LoadingIcon","size","h","width","height","viewBox","preserveAspectRatio","cx","cy","fill","stroke","strokeWidth","r","attributeName","type","repeatCount","dur","values","keyTimes","useStore","cacheKey","storage","content","localStorage","getItem","JSON","parse","err","get","key","set","stringify","setItem","update","store","inputs","useInputs","reactive","nick","mail","link","editor","availableMeta","getMeta","meta","filter","item","includes","defaultUploadImage","file","Promise","resolve","reject","reader","FileReader","readAsDataURL","onload","_a","result","toString","onerror","defaultTexRenderer","blockMode","localeKeys","generateLocale","locale","Object","fromEntries","map","index","en","jp","zhCN","zhTW","ptBR","ru","locales","zh","decodePath","path","decodeURI","removeEndingSplash","replace","isLinkHttp","test","fetchEmoji","Boolean","info","fetch","then","resp","json","emojiInfo","folder","getLink","name","prefix","getServerURL","serverURL","fallback","value","style","isImage","getImagefromDataTransfer","items","image","Array","from","find","getAsFile","fetchCommentList","page","pageSize","signal","token","headers","Authorization","encodeURIComponent","data","errno","TypeError","errmsg","errorCheck","inlineMathStart","inlineMathReg","blockMathReg","parseEmoji","text","emojiMap","placeholder","parseMarkdown","highlighter","texRenderer","marked","setOptions","highlight","undefined","breaks","smartLists","smartypants","extensions","level","tokenizer","src","cap","exec","raw","start","idx","search","length","markedTexExtensions","use","padWithZeros","vNumber","numAsString","timeAgo","date","Date","indexOf","oldTime","getTime","diffValue","days","Math","floor","leave1","hours","leave2","minutes","leave3","round","seconds","now","vDay","getDate","vMonth","getMonth","getFullYear","dateFormat","error","console","log","userInfo","ref","useUserInfo","localStorageData","sessionStorageData","sessionStorage","getUserInfo","readonly","setUserInfo","script$2","defineComponent","components","CloseIcon","class","d","EmojiIcon","ImageIcon","MarkdownIcon","ariaHidden","PreviewIcon","props","rootId","String","default","replyId","replyUser","emits","setup","emit","config","inject","inputRefs","editorRef","imageUploadRef","emojiButtonRef","emojiPopupRef","emoji","tabs","emojiTabIndex","showEmoji","showPreview","previewText","wordNumber","wordLimit","isWordNumberLegal","isSubmitting","computed","isLogin","canUploadImage","imageUploader","insert","textArea","startPosition","selectionStart","endPosition","selectionEnd","scrollTop","substring","focus","uploadImage","uploadText","uploading","url","submitComment","lang","login","requiredMeta","comment","ua","navigator","userAgent","display_name","email","_b","alert","nickError","_c","mailError","_d","anonymous","wordHint","pid","rid","at","method","body","postComment","_e","catch","message","popupHandler","event","contains","target","watch","match","getWords","reduce","accumulator","word","trim","split","getChinese","getWordNumber","autosize","destroy","immediate","emojiConfig","limit","onMounted","document","addEventListener","onUnmounted","removeEventListener","onChange","inputElement","files","onDrop","dataTransfer","preventDefault","onKeyDown","ctrlKey","metaKey","onPaste","clipboardData","onLogin","left","window","innerWidth","top","innerHeight","handler","open","postMessage","receiver","close","remember","onLogout","onProfile","assign","forEach","_hoisted_1","_hoisted_3","_hoisted_7","_hoisted_12","_hoisted_13","href","title","rel","_hoisted_18","_hoisted_19","_openBlock","_createElementBlock","_ctx","_hoisted_2","_createElementVNode","logout","onClick","args","_createVNode","_component_CloseIcon","avatar","alt","_toDisplayString","_normalizeClass","_Fragment","_renderList","kind","for","optional","element","id","$event","_vModelDynamic","_cache","onKeydown","_vModelText","preview","innerHTML","_hoisted_14","_component_MarkdownIcon","actived","_component_EmojiIcon","accept","_component_ImageIcon","_component_PreviewIcon","_createTextVNode","_hoisted_20","textContent","disabled","_createBlock","_component_LoadingIcon","submit","display","_hoisted_25","loading","referrerPolicy","_hoisted_28","active","icon","cancelReply","$emit","script$1","required","reply","CommentBox","ReplyIcon","VerifiedIcon","isReplyingCurrent","objectId","_hoisted_4","_hoisted_5","_component_VerifiedIcon","admin","sticky","insertedAt","_component_ReplyIcon","browser","os","_hoisted_16","_component_CommentBox","onSubmit","onCancelReply","_hoisted_17","children","child","_component_CommentCard","onReply","script","CommentCard","visitor","dark","Number","Function","texRender","location","pathname","copyright","more","emojis","all","emojiInfos","push","isArray","hanabi","getConfig","status","count","totalPages","darkmodeStyle","getDarkStyle","selector","abort","stop","fetchComment","pageNumber","controller","AbortController","bind","refresh","provide","createElement","innerText","querySelector","appendChild","watchEffect","onBeforeUnmount","i18n","loadMore","repliedComment","unshift","version","_hoisted_9","_createCommentVNode","sofa","_hoisted_11"],"mappings":"8kBAGO,MA0FMA,EAAqD,EAAGC,KAAAA,KACnEC,EACE,MACA,CACEC,MAAOF,EACPG,OAAQH,EACRI,QAAS,cACTC,oBAAqB,YAEvBJ,EACE,SACA,CACEK,GAAI,GACJC,GAAI,GACJC,KAAM,OACNC,OAAQ,eACRC,YAAa,IACbC,EAAG,KAEH,mBAAoB,SAEtBV,EAAE,mBAAoB,CACpBW,cAAe,YACfC,KAAM,SACNC,YAAa,aACbC,IAAK,KACLC,OAAQ,oBACRC,SAAU,UClHLC,EAAYC,IACvB,IAAIC,EAAmC,GACvC,MAAMC,EAAUC,aAAaC,QAAQJ,GAErC,GAAIE,EACF,IACED,EAAUI,KAAKC,MAAMJ,GACrB,MAAOK,IAKX,MAAO,CACLC,IAASC,GAA2BR,EAAQQ,IAAc,KAE1DC,IAAOD,EAAaP,GAClB,IAEED,EAAQQ,GAAOJ,KAAKC,MAAMD,KAAKM,UAAUT,IACzCC,aAAaS,QAAQZ,EAAUK,KAAKM,UAAUV,IAC9C,MAAOM,MAKXM,OAAUX,GAERD,EAAUI,KAAKC,MAAMD,KAAKM,UAAUT,IACpCC,aAAaS,QAAQZ,EAAUK,KAAKM,UAAUV,OCtBpD,IAAIa,EACAC,EAEG,MAAMC,EAAY,KAClBD,IACHD,EAAQf,EAAS,qBAEjBgB,EAASE,EAAS,CAChBC,KAAMJ,EAAMN,IAAY,SAAW,GACnCW,KAAML,EAAMN,IAAY,SAAW,GACnCY,KAAMN,EAAMN,IAAY,SAAW,GACnCa,OAAQ,MAIL,CAAEN,OAAAA,EAAQD,MAAAA,ICzBbQ,EAA8B,CAAC,OAAQ,OAAQ,QAExCC,EAAWC,GACtBA,EAAKC,QAAQC,GAASJ,EAAcK,SAASD,KAIlCE,EAAsBC,GACjC,IAAIC,SAAQ,CAACC,EAASC,KACpB,MAAMC,EAAS,IAAIC,WACnBD,EAAOE,cAAcN,GACrBI,EAAOG,OAAS,KAAY,IAAAC,EAAA,OAAAN,WAAQM,EAAAJ,EAAOK,6BAAQC,aAAc,KACjEN,EAAOO,QAAUR,KAGRS,EAAsBC,IACnB,IAAdA,EACI,sDACA,4DClBAC,EAAa,CACjB,OACA,YACA,OACA,YACA,OACA,WACA,cACA,OACA,SACA,QACA,cACA,UACA,UACA,OACA,UACA,QACA,cACA,UACA,UACA,QACA,OACA,MACA,YACA,QACA,SACA,QACA,SACA,OACA,WACA,aAGWC,EAAkBC,GAC7BC,OAAOC,YACLF,EAAOG,KAAI,CAACtB,EAAMuB,IAAU,CAACN,EAAWM,GAAQvB,MCnCpD,IAAAwB,EAAeN,EAAe,CAC5B,WACA,wCACA,SACA,qCACA,UACA,WACA,kBACA,kBACA,SACA,QACA,eACA,WACA,UACA,eACA,UACA,QACA,eACA,cACA,cACA,YACA,WACA,WACA,YACA,QACA,SACA,QACA,SACA,QACA,2EACA,cC9BFO,EAAeP,EAAe,CAC5B,SACA,yBACA,UACA,mBACA,MACA,QACA,UACA,aACA,OACA,OACA,QACA,OACA,KACA,UACA,QACA,MACA,YACA,KACA,KACA,MACA,KACA,OACA,SACA,SACA,QACA,MACA,SACA,MACA,gDACA,OC9BFQ,EAAeR,EAAe,CAC5B,KACA,aACA,KACA,aACA,KACA,KACA,OACA,SACA,KACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,OC9BFS,EAAeT,EAAe,CAC5B,KACA,KACA,KACA,KACA,aACA,aACA,OACA,SACA,KACA,KACA,OACA,KACA,KACA,UACA,KACA,KACA,OACA,KACA,MACA,MACA,KACA,KACA,OACA,KACA,KACA,KACA,KACA,IACA,+BACA,OC9BFU,EAAeV,EAAe,CAC5B,UACA,0CACA,SACA,8CACA,UACA,WACA,kBACA,4BACA,SACA,YACA,oBACA,cACA,YACA,mBACA,aACA,QACA,gBACA,iBACA,gBACA,cACA,aACA,cACA,WACA,SACA,OACA,QACA,SACA,WACA,gFACA,YC9BFW,EAAeX,EAAe,CAC5B,YACA,uCACA,YACA,yDACA,WACA,iBACA,uBACA,yBACA,YACA,WACA,iBACA,cACA,WACA,oBACA,SACA,SACA,wBACA,eACA,wBACA,wBACA,aACA,eACA,WACA,iBACA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"}