FastComments.com

撰寫擴充套件

開發擴充功能

背景

FastComments 提供透過我們稱為擴充功能的腳本來擴充我們的核心功能的能力。

An Extension 可以向留言元件新增額外的標記、事件監聽器,並執行任意程式碼。

在這裡你會找到我們在生產環境中使用的擴充功能範例,以及如何撰寫擴充功能的文件。

擴充套件生命週期 Internal Link


每個擴充功能的腳本會在評論元件開始抓取第一批評論並渲染 UI 之前被抓取並執行。

在初始載入時,下列資料會被標記到擴充功能物件上:

  • config - 一個指向 config 物件的參考。
  • translations - 一個指向 translations 物件的參考。
  • commentsById - 一個以 id 為索引的所有評論的參考。
  • root - 一個指向根 DOM 節點的參考。

擴充功能應覆寫所需的函式,評論元件會在適當的時機呼叫它們。

定義擴充套件 Internal Link


最小的擴充功能範例為:

一個簡單的擴充功能
Copy CopyRun External Link
1
2(function () {
3 const extension = FastCommentsUI.extensions.find((extension) => {
4 return extension.id === 'my-extension';
5 });
6})();
7

為了本範例,將此儲存為 my-extension.js,並讓它可透過 https://example.com/my-extension.min.js 存取。

這個擴充功能本身不會執行任何動作,只有在載入時會取回由核心留言函式庫所建立的擴充物件。

此 Extension 物件為單例,且不會與其他擴充功能共用。

接下來,要載入我們的擴充功能,必須告知留言小工具。例如:

Using a Custom Extension
Copy CopyRun External Link
1
2<script async src="https://cdn.fastcomments.com/js/embed-v2-async.min.js"></script>
3<div id="fastcomments-widget"></div>
4<script>
5window.fcConfigs = [{
6 "tenantId": "demo",
7 "extensions": [
8 {
9 "id": "my-extension",
10 "path": "https://example.com/my-extension.min.js"
11 }
12 ]
13}];
14</script>
15

關於功能範例,請參閱下一節。

擴充套件物件 Internal Link

擴充物件包含以下定義:

擴充物件 JSDoc
Copy CopyRun External Link
1
2/**
3 * FastCommentsUI 擴充物件。用於延遲載入某些元件。例如,評論系統並非所有客戶都使用,因此我們僅在需要時載入該擴充功能。
4 *
5 * @typedef {Object} FastCommentsUIExtension
6 * @property {string} id
7 * @property {Element} scriptNode
8 * @property {Element} root - 小工具根 DOM 節點。
9 * @property {string} [css]
10 * @property {Object} config - FastComments 設定物件。
11 * @property {Object} commentsById - 指向一個包含所有依 ID 分類之評論的物件參考,會保持最新。
12 * @property {Object} translations - 指向所有翻譯的參考。
13 * @property {Function} reRenderComment - 可呼叫以重新渲染評論的函式參考。
14 * @property {Function} removeCommentAndReRender - 可呼叫以從記憶體中移除評論並重新渲染 DOM 中相應部分的函式參考。
15 * @property {Function} newBroadcastId - 可呼叫以建立新廣播 ID 並將其加入本地要忽略的廣播 ID 清單的函式參考。
16 * @property {FastCommentsUIExtensionSetupEventHandlers} [setupEventHandlers]
17 * @property {FastCommentsUIExtensionPrepareCommentForSavingCallback} [prepareCommentForSaving] - 在即將發佈的評論上被呼叫。返回 false 可取消提交(例如當附加的投票未完成時)。
18 * @property {FastCommentsUIExtensionNewCommentCallback} [newComment]
19 * @property {FastCommentsUIExtensionReplyAreaFilter} [replyAreaFilter] - 過濾評論區域的 HTML。
20 * @property {FastCommentsUIExtensionWidgetFilter} [widgetFilter] - 在渲染時過濾整個小工具的 HTML。
21 * @property {FastCommentsUIExtensionCommentTopFilter} [commentFilter] - 在渲染前過濾每則評論的 HTML。
22 * @property {FastCommentsUIExtensionReplyAreaFilter} [commentMenuFilter] - 在渲染前過濾每則評論選單的 HTML。
23 * @property {FastCommentsUIExtensionMenuFilter} [menuFilter] - 在渲染時過濾整個小工具的 HTML。
24 * @property {FastCommentsUIExtensionReplyAreaTop} [replyAreaTop] - (LEGACY) (舊版) 回傳要加入回覆區域頂部的 HTML。
25 * @property {FastCommentsUIExtensionWidgetTopCallback} [widgetTop] - (LEGACY) (舊版) 回傳要加入小工具頂部的 HTML。
26 * @property {FastCommentsUIExtensionCommentTopCallback} [commentTop] - (LEGACY) (舊版) 回傳要加入評論元素頂部的 HTML。
27 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentBottom] - (LEGACY) (舊版) 回傳要加入評論元素底部的 HTML。
28 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentContentBottom] - 回傳要在評論文字之後、評論內容元素內加入的 HTML(用於投票)。
29 * @property {Function} [replyAreaInputBottom] - 回傳要在評論輸入框內、文字輸入下方加入的 HTML(用於投票的即時投票編輯器)。接收父評論 ID,若為根回覆框則為 null。
30 * @property {Function} [onPollUpdate] - 在頁面上投票計數變更時,透過即時事件呼叫。
31 * @property {Function} isSiteAdmin - 回傳檢視者是否為租戶的管理員或版主。於首次取得後得知。
32 * @property {FastCommentsUIExtensionMenuBottomCallback} [menuBottom] - (LEGACY) (舊版) 回傳要加入每則評論選單元素底部的 HTML。
33 * @property {FastCommentsUIExtensionRenderCallback} [onRender]
34 * @property {FastCommentsUIExtensionConnectionStatusCallback} [onLiveConnectionStatusUpdate]
35 * @property {FastCommentsUIExtensionInitialRenderCallback} [onInitialRenderComplete]
36 * @property {FastCommentsUIExtensionPresenceUpdateCallback} [onPresenceUpdate]
37 */
38
39/**
40 * @callback FastCommentsUIExtensionSetupEventHandlers
41 * @param {Element} element - 根元素。
42 * @param {Object.<string, Function>} clickListeners - 依類別名稱的點擊事件處理函式,可透過參考進行修改。
43 * @returns void
44 */
45
46/**
47 * @callback FastCommentsUIExtensionWidgetTopCallback
48 * @param {Object} moduleData
49 * @returns {string}
50 */
51
52/**
53 * @callback FastCommentsUIExtensionWidgetFilter
54 * @param {Object} moduleData
55 * @param {Object} html
56 * @returns {string}
57 */
58
59/**
60 * @callback FastCommentsUIExtensionCommentTopCallback
61 * @param {Object} comment
62 * @returns {string}
63 */
64
65/**
66 * @callback FastCommentsUIExtensionCommentTopFilter
67 * @param {Object} comment
68 * @param {string} html
69 * @returns {string}
70 */
71
72/**
73 * @callback FastCommentsUIExtensionCommentBottomCallback
74 * @param {Object} comment
75 * @returns {string}
76 */
77
78/**
79 * @callback FastCommentsUIExtensionMenuBottomCallback
80 * @param {Object} comment
81 * @returns {string}
82 */
83
84/**
85 * @callback FastCommentsUIExtensionMenuFilter
86 * @param {Object} comment
87 * @param {string} html
88 * @returns {string}
89 */
90
91/**
92 * @callback FastCommentsUIExtensionRenderCallback
93 * @returns {string}
94 */
95
96/**
97 * @callback FastCommentsUIExtensionConnectionStatusCallback
98 * @param {boolean} isConnected
99 * @returns {void}
100 */
101
102/**
103 * @callback FastCommentsUIExtensionInitialRenderCallback
104 * @returns {void}
105 */
106
107/**
108 * @callback FastCommentsUIExtensionReplyAreaTop
109 * @param {Object|null} currentUser
110 * @param {boolean} isSaving
111 * @param {boolean} isReplyOpen
112 * @param {string|null} parentId
113 * @returns {string}
114 */
115
116/**
117 * @callback FastCommentsUIExtensionReplyAreaFilter
118 * @param {Object|null} currentUser
119 * @param {boolean} isSaving
120 * @param {boolean} isReplyOpen
121 * @param {string|null} parentId
122 * @param {string|null} html
123 * @returns {string}
124 */
125
126/**
127 * @callback FastCommentsUIExtensionPrepareCommentForSavingCallback
128 * @param {Object} comment
129 * @param {string} parentId
130 */
131
132/**
133 * @callback FastCommentsUIExtensionNewCommentCallback
134 * @param {Object} comment
135 */
136
137/**
138 * @callback FastCommentsUIExtensionPresenceUpdateCallback
139 * @param {Object} update
140 */
141

擴充套件 API Internal Link

與 Extension 的互動很簡單,只要定義我們想呼叫的函式參考。

延續先前的範例,假設我們想在每個評論的頂部加入 HTML:

簡單的擴充功能 - 繼續
Copy CopyRun External Link
1
2(function () {
3 const extension = FastCommentsUI.extensions.find((extension) => {
4 return extension.id === 'my-extension';
5 });
6
7 extension.commentFilter = function(comment, html) {
8 return `<h3>The user's name is ${comment.commenterName}!</h3>` + html;
9 }
10})();
11

每當你返回這類 HTML 時,它會透過 DOM 差異比對演算法合併到 UI 中。

手動觸發評論的重新渲染

我們可以等到初始頁面載入完成,並透過呼叫 reRenderComment 手動重新渲染評論:

重新渲染評論
Copy CopyRun External Link
1
2(function () {
3 const extension = FastCommentsUI.extensions.find((extension) => {
4 return extension.id === 'my-extension';
5 });
6
7 let renderCount = 0;
8
9 extension.commentFilter = function(comment, html) {
10 renderCount++;
11 return `<h3>The render count is ${renderCount}!</h3>` + html;
12 }
13
14 extension.onInitialRenderComplete = function() {
15 setInterval(function() {
16 extension.reRenderComment(extension.commentsById[Object.keys(extension.commentsById)[0]], function renderDone() {
17 console.log('Comment re-render done.');
18 });
19 }, 2000); // timeout not required, just an example.
20 }
21})();
22