nodebb-plugin-timestamp 1.0.0 → 1.1.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.
package/build/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var TIMESTAMP_REGEX=/\[timestamp](\d{10,13})\[\/timestamp]/g;function registerFormatting(payload,callback){payload.options.push({name:`timestamp`,className:`fa fa-clock-o`,title:`[[timestamp:composer.timestamp]]`}),callback(null,payload)}function applyTimestamp(content){return content.replace(TIMESTAMP_REGEX,(_match,ts)=>{let epoch=parseInt(ts,10);if(isNaN(epoch))return _match;let date=new Date(epoch);return[`<time`,` class="timeago plugin-timestamp"`,` datetime="${date.toISOString()}"`,` title="${date.toLocaleString(`zh-CN`,{timeZone:`Asia/Shanghai`})}"`,` data-timestamp="${epoch}"`,`>${date.toLocaleString(`zh-CN`)}</time>`].join(` `)})}function parsePost(data,callback){if(!data?.postData?.content){callback(null,data);return}data.postData.content=applyTimestamp(data.postData.content),callback(null,data)}function parseRaw(raw,callback){if(!raw){callback(null,raw);return}callback(null,applyTimestamp(raw))}export{parsePost,parseRaw,registerFormatting};
1
+ var TIMESTAMP_REGEX=/\[timestamp](\d{10,13})\[\/timestamp]/g;function registerFormatting(payload,callback){payload.options.push({name:`timestamp`,className:`fa fa-clock-o`,title:`[[timestamp:composer.timestamp]]`}),callback(null,payload)}function applyTimestamp(content){return content.replace(TIMESTAMP_REGEX,(_match,ts)=>{let epoch=parseInt(ts,10);if(isNaN(epoch))return _match;let iso=new Date(epoch).toISOString();return[`<time`,` class="timeago plugin-timestamp"`,` datetime="${iso}"`,` title="${iso}"`,` data-timestamp="${epoch}"`,`>${iso}</time>`].join(` `)})}function parsePost(data,callback){if(!data?.postData?.content){callback(null,data);return}data.postData.content=applyTimestamp(data.postData.content),callback(null,data)}function parseRaw(raw,callback){if(!raw){callback(null,raw);return}callback(null,applyTimestamp(raw))}export{parsePost,parseRaw,registerFormatting};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../lib/index.ts"],"sourcesContent":["import type { FormattingPayload, ParsePostData, ParseRawData } from \"./type.ts\";\n\n// 匹配标记:[timestamp]1700000000000[/timestamp]\nconst TIMESTAMP_REGEX = /\\[timestamp](\\d{10,13})\\[\\/timestamp]/g;\n\n/**\n * 向编辑器工具栏注册按钮\n * 对应 plugin.json 中 filter:composer.formatting\n */\nexport function registerFormatting(\n payload: FormattingPayload,\n callback: (err: Error | null, payload: FormattingPayload) => void\n): void {\n payload.options.push({\n name: \"timestamp\",\n className: \"fa fa-clock-o\",\n title: \"[[timestamp:composer.timestamp]]\"\n });\n callback(null, payload);\n}\n\nfunction applyTimestamp(content: string) {\n return content.replace(TIMESTAMP_REGEX, (_match: string, ts: string) => {\n const epoch = parseInt(ts, 10);\n if (isNaN(epoch)) return _match;\n\n const date = new Date(epoch);\n const iso = date.toISOString();\n // NodeBB 内置的 timeago class,框架会自动渲染相对时间\n // title 属性提供 hover tooltip 的精确时间\n return [\n `<time`,\n ` class=\"timeago plugin-timestamp\"`,\n ` datetime=\"${iso}\"`,\n ` title=\"${date.toLocaleString(\"zh-CN\", { timeZone: \"Asia/Shanghai\" })}\"`,\n ` data-timestamp=\"${epoch}\"`,\n `>${date.toLocaleString(\"zh-CN\")}</time>`\n ].join(\" \");\n });\n}\n\n/**\n * 解析帖子内容,将时间戳标记转换为 HTML\n * 对应 plugin.json 中 filter:parse.post\n */\nexport function parsePost(\n data: ParsePostData,\n callback: (err: Error | null, data: ParsePostData) => void\n): void {\n if (!data?.postData?.content) {\n callback(null, data);\n return;\n }\n\n data.postData.content = applyTimestamp(data.postData.content);\n\n callback(null, data);\n}\n\n/**\n * 解析 Raw,将时间戳标记转换为 HTML\n * 对应 plugin.json 中 filter:parse.raw\n *\n * 注意:filter:parse.raw 传入的是原始字符串本身(用于编辑器预览等场景),\n * 与 filter:parse.post 的对象结构不同\n */\nexport function parseRaw(\n raw: ParseRawData,\n callback: (err: Error | null, raw: ParseRawData) => void\n): void {\n if (!raw) {\n callback(null, raw);\n return;\n }\n\n callback(null, applyTimestamp(raw));\n}\n"],"mappings":"AAGA,IAAM,gBAAkB,yCAMxB,SAAgB,mBACd,QACA,SACM,CACN,QAAQ,QAAQ,KAAK,CACnB,KAAM,YACN,UAAW,gBACX,MAAO,kCACT,CAAC,EACD,SAAS,KAAM,OAAO,CACxB,CAEA,SAAS,eAAe,QAAiB,CACvC,OAAO,QAAQ,QAAQ,iBAAkB,OAAgB,KAAe,CACtE,IAAM,MAAQ,SAAS,GAAI,EAAE,EAC7B,GAAI,MAAM,KAAK,EAAG,OAAO,OAEzB,IAAM,KAAO,IAAI,KAAK,KAAK,EAI3B,MAAO,CACL,QACA,qCACA,eANU,KAAK,YAME,EAAE,GACnB,YAAY,KAAK,eAAe,QAAS,CAAE,SAAU,eAAgB,CAAC,EAAE,GACxE,qBAAqB,MAAM,GAC3B,IAAI,KAAK,eAAe,OAAO,EAAE,QACnC,CAAC,CAAC,KAAK,GAAG,CACZ,CAAC,CACH,CAMA,SAAgB,UACd,KACA,SACM,CACN,GAAI,CAAC,MAAM,UAAU,QAAS,CAC5B,SAAS,KAAM,IAAI,EACnB,MACF,CAEA,KAAK,SAAS,QAAU,eAAe,KAAK,SAAS,OAAO,EAE5D,SAAS,KAAM,IAAI,CACrB,CASA,SAAgB,SACd,IACA,SACM,CACN,GAAI,CAAC,IAAK,CACR,SAAS,KAAM,GAAG,EAClB,MACF,CAEA,SAAS,KAAM,eAAe,GAAG,CAAC,CACpC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../lib/index.ts"],"sourcesContent":["import type { FormattingPayload, ParsePostData, ParseRawData } from \"./type.ts\";\n\n// 匹配标记:[timestamp]1700000000000[/timestamp]\nconst TIMESTAMP_REGEX = /\\[timestamp](\\d{10,13})\\[\\/timestamp]/g;\n\n/**\n * 向编辑器工具栏注册按钮\n * 对应 plugin.json 中 filter:composer.formatting\n */\nexport function registerFormatting(\n payload: FormattingPayload,\n callback: (err: Error | null, payload: FormattingPayload) => void\n): void {\n payload.options.push({\n name: \"timestamp\",\n className: \"fa fa-clock-o\",\n title: \"[[timestamp:composer.timestamp]]\"\n });\n callback(null, payload);\n}\n\nfunction applyTimestamp(content: string) {\n return content.replace(TIMESTAMP_REGEX, (_match: string, ts: string) => {\n const epoch = parseInt(ts, 10);\n if (isNaN(epoch)) return _match;\n\n const date = new Date(epoch);\n const iso = date.toISOString();\n // datetime 提供机器可读的 ISO 时间\n // 实际显示文本由客户端 JS 根据用户本地时区渲染\n // 服务端仅输出 UTC 作为 fallback\n return [\n `<time`,\n ` class=\"timeago plugin-timestamp\"`,\n ` datetime=\"${iso}\"`,\n ` title=\"${iso}\"`,\n ` data-timestamp=\"${epoch}\"`,\n `>${iso}</time>`\n ].join(\" \");\n });\n}\n\n/**\n * 解析帖子内容,将时间戳标记转换为 HTML\n * 对应 plugin.json 中 filter:parse.post\n */\nexport function parsePost(\n data: ParsePostData,\n callback: (err: Error | null, data: ParsePostData) => void\n): void {\n if (!data?.postData?.content) {\n callback(null, data);\n return;\n }\n\n data.postData.content = applyTimestamp(data.postData.content);\n\n callback(null, data);\n}\n\n/**\n * 解析 Raw,将时间戳标记转换为 HTML\n * 对应 plugin.json 中 filter:parse.raw\n *\n * 注意:filter:parse.raw 传入的是原始字符串本身(用于编辑器预览等场景),\n * 与 filter:parse.post 的对象结构不同\n */\nexport function parseRaw(\n raw: ParseRawData,\n callback: (err: Error | null, raw: ParseRawData) => void\n): void {\n if (!raw) {\n callback(null, raw);\n return;\n }\n\n callback(null, applyTimestamp(raw));\n}\n"],"mappings":"AAGA,IAAM,gBAAkB,yCAMxB,SAAgB,mBACd,QACA,SACM,CACN,QAAQ,QAAQ,KAAK,CACnB,KAAM,YACN,UAAW,gBACX,MAAO,kCACT,CAAC,EACD,SAAS,KAAM,OAAO,CACxB,CAEA,SAAS,eAAe,QAAiB,CACvC,OAAO,QAAQ,QAAQ,iBAAkB,OAAgB,KAAe,CACtE,IAAM,MAAQ,SAAS,GAAI,EAAE,EAC7B,GAAI,MAAM,KAAK,EAAG,OAAO,OAGzB,IAAM,IAAM,IADK,KAAK,KACP,CAAC,CAAC,YAAY,EAI7B,MAAO,CACL,QACA,qCACA,eAAe,IAAI,GACnB,YAAY,IAAI,GAChB,qBAAqB,MAAM,GAC3B,IAAI,IAAI,QACV,CAAC,CAAC,KAAK,GAAG,CACZ,CAAC,CACH,CAMA,SAAgB,UACd,KACA,SACM,CACN,GAAI,CAAC,MAAM,UAAU,QAAS,CAC5B,SAAS,KAAM,IAAI,EACnB,MACF,CAEA,KAAK,SAAS,QAAU,eAAe,KAAK,SAAS,OAAO,EAE5D,SAAS,KAAM,IAAI,CACrB,CASA,SAAgB,SACd,IACA,SACM,CACN,GAAI,CAAC,IAAK,CACR,SAAS,KAAM,GAAG,EAClB,MACF,CAEA,SAAS,KAAM,eAAe,GAAG,CAAC,CACpC"}
@@ -11,5 +11,5 @@
11
11
  [[timestamp:dialog.description]]
12
12
  </div>
13
13
  </div>
14
- `,buttons:{cancel:{label:`[[timestamp:dialog.cancel]]`,className:`btn-secondary`},confirm:{label:`[[timestamp:dialog.confirm]]`,className:`btn-primary`,callback(){let input=document.getElementById(`plugin-ts-picker`);if(!input?.value)return;let ts=new Date(input.value).getTime();isNaN(ts)||insertAtCursor(textarea,selectionStart,selectionEnd,`[timestamp]${ts}[/timestamp]`)}}}})})}$(window).on(`action:app.load`,()=>{require([`composer/formatting`],formatting=>{formatting.addButtonDispatch(`timestamp`,function(textarea,selectionStart,selectionEnd){openTimePicker(textarea,selectionStart,selectionEnd)})})})});
14
+ `,buttons:{cancel:{label:`[[timestamp:dialog.cancel]]`,className:`btn-secondary`},confirm:{label:`[[timestamp:dialog.confirm]]`,className:`btn-primary`,callback(){let input=document.getElementById(`plugin-ts-picker`);if(!input?.value)return;let ts=new Date(input.value).getTime();isNaN(ts)||insertAtCursor(textarea,selectionStart,selectionEnd,`[timestamp]${ts}[/timestamp]`)}}}})})}function localizeTimestamps(root=document){root.querySelectorAll(`time.plugin-timestamp`).forEach(el=>{let iso=el.getAttribute(`datetime`);if(!iso)return;let date=new Date(iso);isNaN(date.getTime())||(el.title=date.toLocaleString(void 0,{year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`}))})}$(window).on(`action:app.load`,()=>{require([`composer/formatting`],formatting=>{formatting.addButtonDispatch(`timestamp`,function(textarea,selectionStart,selectionEnd){openTimePicker(textarea,selectionStart,selectionEnd)})})}),$(window).on(`action:app.load action:ajaxify.end`,()=>{localizeTimestamps()}),$(window).on(`action:posts.loaded`,()=>{localizeTimestamps()})});
15
15
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../public/client.ts"],"sourcesContent":["/// <reference types=\"jquery\"/>\n\n// bootbox 模块类型(通过 require([\"bootbox\"], ...) 按需加载)\ninterface Bootbox {\n dialog: (options: {\n title: string;\n message: string;\n buttons: Record<\n string,\n {\n label: string;\n className: string;\n callback?: () => void | boolean;\n }\n >;\n }) => void;\n}\n\n// NodeBB 的 AMD require(RequireJS 风格)\ndeclare function require(deps: string[], callback: (...modules: unknown[]) => void): void;\n\n// composer/formatting 模块只用到 addButtonDispatch\ninterface FormattingModule {\n // handler 由 dispatch table 调用,this 指向 postContainer\n addButtonDispatch: (\n name: string,\n onClick: (\n this: JQuery,\n textarea: HTMLTextAreaElement,\n selectionStart: number,\n selectionEnd: number,\n event: JQuery.Event\n ) => void\n ) => void;\n}\n\n/**\n * 获取 datetime-local input 所需的格式 \"YYYY-MM-DDTHH:MM\"\n */\nfunction toDatetimeLocalValue(date: Date): string {\n const pad = (n: number): string => String(n).padStart(2, \"0\");\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +\n `T${pad(date.getHours())}:${pad(date.getMinutes())}`\n );\n}\n\n/**\n * 在 textarea 光标位置插入文本\n */\nfunction insertAtCursor(\n textarea: HTMLTextAreaElement,\n start: number,\n end: number,\n text: string\n): void {\n const before = textarea.value.substring(0, start);\n const after = textarea.value.substring(end);\n textarea.value = before + text + after;\n textarea.selectionStart = textarea.selectionEnd = start + text.length;\n textarea.focus();\n // 触发 NodeBB 编辑器的响应式更新与预览刷新\n textarea.dispatchEvent(new Event(\"input\", { bubbles: true }));\n}\n\n/**\n * 打开时间选择弹窗,确认后把标记插入到 textarea 光标处\n */\nfunction openTimePicker(\n textarea: HTMLTextAreaElement,\n selectionStart: number,\n selectionEnd: number\n): void {\n const defaultValue = toDatetimeLocalValue(new Date());\n\n require([\"bootbox\"], (bootbox: unknown) => {\n (bootbox as Bootbox).dialog({\n title: \"[[timestamp:dialog.title]]\",\n message: `\n <div class=\"form-group\">\n <label for=\"plugin-ts-picker\" class=\"form-label\">[[timestamp:dialog.label]]</label>\n <input\n type=\"datetime-local\"\n id=\"plugin-ts-picker\"\n class=\"form-control\"\n value=\"${defaultValue}\"\n />\n <div class=\"form-text text-muted\" style=\"margin-top:6px\">\n [[timestamp:dialog.description]]\n </div>\n </div>\n `,\n buttons: {\n cancel: {\n label: \"[[timestamp:dialog.cancel]]\",\n className: \"btn-secondary\"\n },\n confirm: {\n label: \"[[timestamp:dialog.confirm]]\",\n className: \"btn-primary\",\n callback(): void {\n const input = document.getElementById(\"plugin-ts-picker\") as HTMLInputElement | null;\n if (!input?.value) return;\n\n const ts = new Date(input.value).getTime();\n if (isNaN(ts)) return;\n\n insertAtCursor(textarea, selectionStart, selectionEnd, `[timestamp]${ts}[/timestamp]`);\n }\n }\n }\n });\n });\n}\n\n// NodeBB 页面加载完成后,向 composer 的 dispatch table 注册按钮点击处理\n$(window).on(\"action:app.load\", () => {\n require([\"composer/formatting\"], (formatting: unknown) => {\n (formatting as FormattingModule).addButtonDispatch(\n \"timestamp\",\n function (textarea, selectionStart, selectionEnd): void {\n openTimePicker(textarea, selectionStart, selectionEnd);\n }\n );\n });\n});\n"],"mappings":"gHAuCA,SAAS,qBAAqB,KAAoB,CAChD,IAAM,IAAO,GAAsB,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,GAAG,EAC5D,MACE,GAAG,KAAK,YAAY,EAAE,GAAG,IAAI,KAAK,SAAS,EAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC,EAAA,GACnE,IAAI,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,KAAK,WAAW,CAAC,GAErD,CAKA,SAAS,eACP,SACA,MACA,IACA,KACM,CACN,IAAM,OAAS,SAAS,MAAM,UAAU,EAAG,KAAK,EAC1C,MAAQ,SAAS,MAAM,UAAU,GAAG,EAC1C,SAAS,MAAQ,OAAS,KAAO,MACjC,SAAS,eAAiB,SAAS,aAAe,MAAQ,KAAK,OAC/D,SAAS,MAAM,EAEf,SAAS,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,EAAK,CAAC,CAAC,CAC9D,CAKA,SAAS,eACP,SACA,eACA,aACM,CACN,IAAM,aAAe,qBAAqB,IAAI,IAAM,EAEpD,QAAQ,CAAC,SAAS,EAAI,SAAqB,CACzC,QAAqB,OAAO,CAC1B,MAAO,6BACP,QAAS;;;;;;;qBAOM,aAAa;;;;;;QAO5B,QAAS,CACP,OAAQ,CACN,MAAO,8BACP,UAAW,eACb,EACA,QAAS,CACP,MAAO,+BACP,UAAW,cACX,UAAiB,CACf,IAAM,MAAQ,SAAS,eAAe,kBAAkB,EACxD,GAAI,CAAC,OAAO,MAAO,OAEnB,IAAM,GAAK,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,QAAQ,EACrC,MAAM,EAAE,GAEZ,eAAe,SAAU,eAAgB,aAAc,cAAc,GAAG,aAAa,CACvF,CACF,CACF,CACF,CAAC,CACH,CAAC,CACH,CAGA,EAAE,MAAM,CAAC,CAAC,GAAG,sBAAyB,CACpC,QAAQ,CAAC,qBAAqB,EAAI,YAAwB,CACxD,WAAiC,kBAC/B,YACA,SAAU,SAAU,eAAgB,aAAoB,CACtD,eAAe,SAAU,eAAgB,YAAY,CACvD,CACF,CACF,CAAC,CACH,CAAC"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../public/client.ts"],"sourcesContent":["/// <reference types=\"jquery\"/>\n\n// bootbox 模块类型(通过 require([\"bootbox\"], ...) 按需加载)\ninterface Bootbox {\n dialog: (options: {\n title: string;\n message: string;\n buttons: Record<\n string,\n {\n label: string;\n className: string;\n callback?: () => void | boolean;\n }\n >;\n }) => void;\n}\n\n// NodeBB 的 AMD require(RequireJS 风格)\ndeclare function require(deps: string[], callback: (...modules: unknown[]) => void): void;\n\n// composer/formatting 模块只用到 addButtonDispatch\ninterface FormattingModule {\n // handler 由 dispatch table 调用,this 指向 postContainer\n addButtonDispatch: (\n name: string,\n onClick: (\n this: JQuery,\n textarea: HTMLTextAreaElement,\n selectionStart: number,\n selectionEnd: number,\n event: JQuery.Event\n ) => void\n ) => void;\n}\n\n/**\n * 获取 datetime-local input 所需的格式 \"YYYY-MM-DDTHH:MM\"\n */\nfunction toDatetimeLocalValue(date: Date): string {\n const pad = (n: number): string => String(n).padStart(2, \"0\");\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +\n `T${pad(date.getHours())}:${pad(date.getMinutes())}`\n );\n}\n\n/**\n * 在 textarea 光标位置插入文本\n */\nfunction insertAtCursor(\n textarea: HTMLTextAreaElement,\n start: number,\n end: number,\n text: string\n): void {\n const before = textarea.value.substring(0, start);\n const after = textarea.value.substring(end);\n textarea.value = before + text + after;\n textarea.selectionStart = textarea.selectionEnd = start + text.length;\n textarea.focus();\n // 触发 NodeBB 编辑器的响应式更新与预览刷新\n textarea.dispatchEvent(new Event(\"input\", { bubbles: true }));\n}\n\n/**\n * 打开时间选择弹窗,确认后把标记插入到 textarea 光标处\n */\nfunction openTimePicker(\n textarea: HTMLTextAreaElement,\n selectionStart: number,\n selectionEnd: number\n): void {\n const defaultValue = toDatetimeLocalValue(new Date());\n\n require([\"bootbox\"], (bootbox: unknown) => {\n (bootbox as Bootbox).dialog({\n title: \"[[timestamp:dialog.title]]\",\n message: `\n <div class=\"form-group\">\n <label for=\"plugin-ts-picker\" class=\"form-label\">[[timestamp:dialog.label]]</label>\n <input\n type=\"datetime-local\"\n id=\"plugin-ts-picker\"\n class=\"form-control\"\n value=\"${defaultValue}\"\n />\n <div class=\"form-text text-muted\" style=\"margin-top:6px\">\n [[timestamp:dialog.description]]\n </div>\n </div>\n `,\n buttons: {\n cancel: {\n label: \"[[timestamp:dialog.cancel]]\",\n className: \"btn-secondary\"\n },\n confirm: {\n label: \"[[timestamp:dialog.confirm]]\",\n className: \"btn-primary\",\n callback(): void {\n const input = document.getElementById(\"plugin-ts-picker\") as HTMLInputElement | null;\n if (!input?.value) return;\n\n const ts = new Date(input.value).getTime();\n if (isNaN(ts)) return;\n\n insertAtCursor(textarea, selectionStart, selectionEnd, `[timestamp]${ts}[/timestamp]`);\n }\n }\n }\n });\n });\n}\n\n/**\n * 将页面中所有 .plugin-timestamp 元素的 title(hover tooltip)\n * 替换为用户浏览器本地时区的格式化时间。\n * 不修改 textContent —— 让 NodeBB 内置的 timeago 继续渲染相对时间。\n */\nfunction localizeTimestamps(root: ParentNode = document): void {\n const elements = root.querySelectorAll<HTMLTimeElement>(\"time.plugin-timestamp\");\n elements.forEach((el) => {\n const iso = el.getAttribute(\"datetime\");\n if (!iso) return;\n\n const date = new Date(iso);\n if (isNaN(date.getTime())) return;\n\n el.title = date.toLocaleString(undefined, {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\"\n });\n });\n}\n\n// NodeBB 页面加载完成后,向 composer 的 dispatch table 注册按钮点击处理\n$(window).on(\"action:app.load\", () => {\n require([\"composer/formatting\"], (formatting: unknown) => {\n (formatting as FormattingModule).addButtonDispatch(\n \"timestamp\",\n function (textarea, selectionStart, selectionEnd): void {\n openTimePicker(textarea, selectionStart, selectionEnd);\n }\n );\n });\n});\n\n// 初次加载 + ajaxify 切换页面时,本地化所有时间戳\n$(window).on(\"action:app.load action:ajaxify.end\", () => {\n localizeTimestamps();\n});\n\n// 帖子动态追加时(无限滚动等),也需要处理新出现的时间戳\n$(window).on(\"action:posts.loaded\", () => {\n localizeTimestamps();\n});\n"],"mappings":"gHAuCA,SAAS,qBAAqB,KAAoB,CAChD,IAAM,IAAO,GAAsB,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,GAAG,EAC5D,MACE,GAAG,KAAK,YAAY,EAAE,GAAG,IAAI,KAAK,SAAS,EAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC,EAAA,GACnE,IAAI,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,KAAK,WAAW,CAAC,GAErD,CAKA,SAAS,eACP,SACA,MACA,IACA,KACM,CACN,IAAM,OAAS,SAAS,MAAM,UAAU,EAAG,KAAK,EAC1C,MAAQ,SAAS,MAAM,UAAU,GAAG,EAC1C,SAAS,MAAQ,OAAS,KAAO,MACjC,SAAS,eAAiB,SAAS,aAAe,MAAQ,KAAK,OAC/D,SAAS,MAAM,EAEf,SAAS,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,EAAK,CAAC,CAAC,CAC9D,CAKA,SAAS,eACP,SACA,eACA,aACM,CACN,IAAM,aAAe,qBAAqB,IAAI,IAAM,EAEpD,QAAQ,CAAC,SAAS,EAAI,SAAqB,CACzC,QAAqB,OAAO,CAC1B,MAAO,6BACP,QAAS;;;;;;;qBAOM,aAAa;;;;;;QAO5B,QAAS,CACP,OAAQ,CACN,MAAO,8BACP,UAAW,eACb,EACA,QAAS,CACP,MAAO,+BACP,UAAW,cACX,UAAiB,CACf,IAAM,MAAQ,SAAS,eAAe,kBAAkB,EACxD,GAAI,CAAC,OAAO,MAAO,OAEnB,IAAM,GAAK,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,QAAQ,EACrC,MAAM,EAAE,GAEZ,eAAe,SAAU,eAAgB,aAAc,cAAc,GAAG,aAAa,CACvF,CACF,CACF,CACF,CAAC,CACH,CAAC,CACH,CAOA,SAAS,mBAAmB,KAAmB,SAAgB,CAE7D,KADsB,iBAAkC,uBACjD,CAAC,CAAC,QAAS,IAAO,CACvB,IAAM,IAAM,GAAG,aAAa,UAAU,EACtC,GAAI,CAAC,IAAK,OAEV,IAAM,KAAO,IAAI,KAAK,GAAG,EACrB,MAAM,KAAK,QAAQ,CAAC,IAExB,GAAG,MAAQ,KAAK,eAAe,IAAA,GAAW,CACxC,KAAM,UACN,MAAO,UACP,IAAK,UACL,KAAM,UACN,OAAQ,UACR,OAAQ,SACV,CAAC,EACH,CAAC,CACH,CAGA,EAAE,MAAM,CAAC,CAAC,GAAG,sBAAyB,CACpC,QAAQ,CAAC,qBAAqB,EAAI,YAAwB,CACxD,WAAiC,kBAC/B,YACA,SAAU,SAAU,eAAgB,aAAoB,CACtD,eAAe,SAAU,eAAgB,YAAY,CACvD,CACF,CACF,CAAC,CACH,CAAC,EAGD,EAAE,MAAM,CAAC,CAAC,GAAG,yCAA4C,CACvD,mBAAmB,CACrB,CAAC,EAGD,EAAE,MAAM,CAAC,CAAC,GAAG,0BAA6B,CACxC,mBAAmB,CACrB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-timestamp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Insert a relative time component into the post | 在帖子中插入相对时间组件",
5
5
  "homepage": "https://www.tasaed.top",
6
6
  "bugs": {