FastComments.com

拡張機能の作成

Extensions の開発

コンテキスト

FastComments は、Extensions と呼ぶスクリプトを介してコア機能を拡張する機能を提供します。

An Extension はコメントウィジェットに追加のマークアップを加えたり、イベントリスナーを設定したり、任意のコードを実行したりできます。

ここでは、本番で使用している Extensions の例と、Extensions の書き方に関するドキュメントを紹介します。

拡張機能のライフサイクル Internal Link

各拡張機能のスクリプトは、コメントウィジェットが最初のコメントセットの取得とUIのレンダリングを開始する前にフェッチされ、実行されます。

初回読み込み時に、次のデータが extension オブジェクトに付与されます:

  • 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

extension オブジェクトは以下の定義で構成されています:

Extension Object JSDoc
Copy CopyRun External Link
1
2/**
3 * FastCommentsUI の extension オブジェクト。特定のコンポーネントを遅延読み込みするために使用します。例えば、レビュー
4 * システムはすべての顧客が使用するわけではないため、必要なときにのみその extension を読み込みます。
5 *
6 * @typedef {Object} FastCommentsUIExtension
7 * @property {string} id
8 * @property {Element} scriptNode
9 * @property {Element} root - ウィジェットのルート DOM ノード。
10 * @property {string} [css]
11 * @property {Object} config - FastComments の設定オブジェクト。
12 * @property {Object} commentsById - ID ごとのすべてのコメントを含むオブジェクトへの参照。常に最新の状態に保たれます。
13 * @property {Object} translations - すべての翻訳への参照。
14 * @property {Function} reRenderComment - 呼び出すことでコメントを再レンダリングできる関数への参照。
15 * @property {Function} removeCommentAndReRender - 呼び出すことでコメントをメモリから削除し、DOM の該当部分を再レンダリングできる関数への参照。
16 * @property {Function} newBroadcastId - 呼び出すことで新しい broadcast id を作成し、無視する broadcast id のローカルリストに追加できる関数への参照。
17 * @property {Function} [withSessionId] - リクエスト URL とコールバックを引数に呼び出します。サードパーティ Cookie がブロックされている場合(コメントおよび投票リクエストと同じ経路)、ビューアーのセッション ID を付加した URL でコールバックを呼び出し、それ以外の場合は URL をそのまま渡します。その方法でセッション ID が取得できない場合は、rememberAnonSessionId に最後に渡された匿名セッション ID があればそれを付加します。SSO では使用されません。
18 * @property {Function} [rememberAnonSessionId] - レスポンスが返した anonSessionId を引数に呼び出します。サーバーは、リクエストにセッション Cookie がないゲストに対してのみこれを返し、ログイン済みセッションでは決して返しません。localStorage(ストレージが利用できない場合はメモリ)に保持されるため、withSessionId が以降のリクエストでそれを送信し、ゲストは同一の識別情報を維持できます。
19 * @property {FastCommentsUIExtensionSetupEventHandlers} [setupEventHandlers]
20 * @property {FastCommentsUIExtensionPrepareCommentForSavingCallback} [prepareCommentForSaving] - 投稿されようとしているコメントとともに呼び出されます。false を返すと送信をキャンセルします(例:添付された投票が未完了の場合)。
21 * @property {FastCommentsUIExtensionNewCommentCallback} [newComment]
22 * @property {FastCommentsUIExtensionReplyAreaFilter} [replyAreaFilter] - コメントエリアの HTML をフィルターします。
23 * @property {FastCommentsUIExtensionWidgetFilter} [widgetFilter] - レンダリング時にウィジェット全体の HTML をフィルターします。
24 * @property {FastCommentsUIExtensionCommentTopFilter} [commentFilter] - レンダリング前に各コメントの HTML をフィルターします。
25 * @property {FastCommentsUIExtensionReplyAreaFilter} [commentMenuFilter] - レンダリング前に各コメントメニューの HTML をフィルターします。
26 * @property {FastCommentsUIExtensionMenuFilter} [menuFilter] - レンダリング時にウィジェット全体の HTML をフィルターします。
27 * @property {FastCommentsUIExtensionReplyAreaTop} [replyAreaTop] - (レガシー) 返信エリアの上部に追加する HTML を返します。
28 * @property {FastCommentsUIExtensionWidgetTopCallback} [widgetTop] - (レガシー) ウィジェットの上部に追加する HTML を返します。
29 * @property {FastCommentsUIExtensionCommentTopCallback} [commentTop] - (レガシー) コメント要素の上部に追加する HTML を返します。
30 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentBottom] - (レガシー) コメント要素の下部に追加する HTML を返します。
31 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentContentBottom] - コメントテキストの後に、コメントコンテンツ要素内に追加する HTML を返します(投票で使用されます)。
32 * @property {Function} [replyAreaInputBottom] - コメント入力フレーム内、テキスト入力の下に追加する HTML を返します(投票ではインプレース投票エディターに使用されます)。親コメントの ID を受け取ります。ルートの返信ボックスの場合は null が渡されます。
33 * @property {Function} [onPollUpdate] - ページ上の投票の投票数が変化したときに、ライブイベントとともに呼び出されます。
34 * @property {Function} isSiteAdmin - ビューアーがテナントの管理者またはモデレーターであるかどうかを返します。最初のフェッチ後に判明します。
35 * @property {FastCommentsUIExtensionMenuBottomCallback} [menuBottom] - (レガシー) 各コメントのメニュー要素の下部に追加する HTML を返します。
36 * @property {FastCommentsUIExtensionRenderCallback} [onRender]
37 * @property {FastCommentsUIExtensionConnectionStatusCallback} [onLiveConnectionStatusUpdate]
38 * @property {FastCommentsUIExtensionInitialRenderCallback} [onInitialRenderComplete]
39 * @property {FastCommentsUIExtensionPresenceUpdateCallback} [onPresenceUpdate]
40 */
41
42/**
43 * @callback FastCommentsUIExtensionSetupEventHandlers
44 * @param {Element} element - ルート要素。
45 * @param {Object.<string, Function>} clickListeners - クリックのイベントハンドラー。クラス名で管理され、参照経由で変更できます。
46 * @returns void
47 */
48
49/**
50 * @callback FastCommentsUIExtensionWidgetTopCallback
51 * @param {Object} moduleData
52 * @returns {string}
53 */
54
55/**
56 * @callback FastCommentsUIExtensionWidgetFilter
57 * @param {Object} moduleData
58 * @param {Object} html
59 * @returns {string}
60 */
61
62/**
63 * @callback FastCommentsUIExtensionCommentTopCallback
64 * @param {Object} comment
65 * @returns {string}
66 */
67
68/**
69 * @callback FastCommentsUIExtensionCommentTopFilter
70 * @param {Object} comment
71 * @param {string} html
72 * @returns {string}
73 */
74
75/**
76 * @callback FastCommentsUIExtensionCommentBottomCallback
77 * @param {Object} comment
78 * @returns {string}
79 */
80
81/**
82 * @callback FastCommentsUIExtensionMenuBottomCallback
83 * @param {Object} comment
84 * @returns {string}
85 */
86
87/**
88 * @callback FastCommentsUIExtensionMenuFilter
89 * @param {Object} comment
90 * @param {string} html
91 * @returns {string}
92 */
93
94/**
95 * @callback FastCommentsUIExtensionRenderCallback
96 * @returns {string}
97 */
98
99/**
100 * @callback FastCommentsUIExtensionConnectionStatusCallback
101 * @param {boolean} isConnected
102 * @returns {void}
103 */
104
105/**
106 * @callback FastCommentsUIExtensionInitialRenderCallback
107 * @returns {void}
108 */
109
110/**
111 * @callback FastCommentsUIExtensionReplyAreaTop
112 * @param {Object|null} currentUser
113 * @param {boolean} isSaving
114 * @param {boolean} isReplyOpen
115 * @param {string|null} parentId
116 * @returns {string}
117 */
118
119/**
120 * @callback FastCommentsUIExtensionReplyAreaFilter
121 * @param {Object|null} currentUser
122 * @param {boolean} isSaving
123 * @param {boolean} isReplyOpen
124 * @param {string|null} parentId
125 * @param {string|null} html
126 * @returns {string}
127 */
128
129/**
130 * @callback FastCommentsUIExtensionPrepareCommentForSavingCallback
131 * @param {Object} comment
132 * @param {string} parentId
133 */
134
135/**
136 * @callback FastCommentsUIExtensionNewCommentCallback
137 * @param {Object} comment
138 */
139
140/**
141 * @callback FastCommentsUIExtensionPresenceUpdateCallback
142 * @param {Object} update
143 */
144

拡張機能のAPI Internal Link

Extension との連携はシンプルです。実行したい関数への参照を定義するだけだからです。

先ほどの例を踏まえて、各コメントの先頭にHTMLを追加したい場合を考えてみましょう:

シンプルな Extension - 続き
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-diffingアルゴリズムを通じて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