FastComments.com

Создание расширений

Разработка расширений

Контекст

FastComments предоставляет возможность расширять нашу основную функциональность через скрипты, которые мы называем Extensions.

An Extension can add additional markup to the comment widget, event listeners, and run arbitrary code.

Здесь вы найдете примеры расширений, которые используются у нас в продакшне, а также документацию о том, как писать расширения.

Жизненный цикл расширения Internal Link

Скрипт для каждого расширения загружается и вызывается до того, как виджет комментариев начнёт запрашивать первый набор комментариев и отображать интерфейс пользователя.

При первоначальной загрузке к объекту расширения будут добавлены следующие данные:

  • 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 *
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 {FastCommentsUIExtensionSetupEventHandlers} [setupEventHandlers]
18 * @property {FastCommentsUIExtensionPrepareCommentForSavingCallback} [prepareCommentForSaving] - Вызывается с комментарием, который собираются опубликовать. Верните false, чтобы отменить отправку (например, когда прикреплённый опрос не завершён).
19 * @property {FastCommentsUIExtensionNewCommentCallback} [newComment]
20 * @property {FastCommentsUIExtensionReplyAreaFilter} [replyAreaFilter] - Фильтровать HTML для области комментариев.
21 * @property {FastCommentsUIExtensionWidgetFilter} [widgetFilter] - Фильтровать HTML для всего виджета при рендере.
22 * @property {FastCommentsUIExtensionCommentTopFilter} [commentFilter] - Фильтровать HTML для каждого комментария перед рендером.
23 * @property {FastCommentsUIExtensionReplyAreaFilter} [commentMenuFilter] - Фильтровать HTML для меню каждого комментария перед рендером.
24 * @property {FastCommentsUIExtensionMenuFilter} [menuFilter] - Фильтровать HTML для всего виджета при рендере.
25 * @property {FastCommentsUIExtensionReplyAreaTop} [replyAreaTop] - (УСТАРЕВШЕ) Возвращает HTML, который будет добавлен в верхнюю часть области ответа.
26 * @property {FastCommentsUIExtensionWidgetTopCallback} [widgetTop] - (УСТАРЕВШЕ) Возвращает HTML, который будет добавлен в верхнюю часть виджета.
27 * @property {FastCommentsUIExtensionCommentTopCallback} [commentTop] - (УСТАРЕВШЕ) Возвращает HTML, который будет добавлен в верхнюю часть элемента комментария.
28 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentBottom] - (УСТАРЕВШЕ) Возвращает HTML, который будет добавлен в нижнюю часть элемента комментария.
29 * @property {FastCommentsUIExtensionCommentBottomCallback} [commentContentBottom] - Возвращает HTML, который будет добавлен после текста комментария, внутри элемента содержимого комментария (используется в опросах).
30 * @property {Function} [replyAreaInputBottom] - Возвращает HTML, который будет добавлен внутри рамки ввода комментария, под текстовым полем (используется в опросах для встроенного редактора опросов). Принимает id родительского комментария или null для корневого поля ответа.
31 * @property {Function} [onPollUpdate] - Вызывается с событием в реальном времени, когда меняется количество голосов в опросе на странице.
32 * @property {Function} isSiteAdmin - Возвращает, является ли пользователь администратором или модератором арендатора. Известно после первого запроса.
33 * @property {FastCommentsUIExtensionMenuBottomCallback} [menuBottom] - (УСТАРЕВШЕ) Возвращает HTML, который будет добавлен в нижнюю часть элемента меню для каждого комментария.
34 * @property {FastCommentsUIExtensionRenderCallback} [onRender]
35 * @property {FastCommentsUIExtensionConnectionStatusCallback} [onLiveConnectionStatusUpdate]
36 * @property {FastCommentsUIExtensionInitialRenderCallback} [onInitialRenderComplete]
37 * @property {FastCommentsUIExtensionPresenceUpdateCallback} [onPresenceUpdate]
38 */
39
40/**
41 * @callback FastCommentsUIExtensionSetupEventHandlers
42 * @param {Element} element - Корневой элемент.
43 * @param {Object.<string, Function>} clickListeners - Обработчики событий кликов, по имени класса, которые могут быть изменены по ссылке.
44 * @returns void
45 */
46
47/**
48 * @callback FastCommentsUIExtensionWidgetTopCallback
49 * @param {Object} moduleData
50 * @returns {string}
51 */
52
53/**
54 * @callback FastCommentsUIExtensionWidgetFilter
55 * @param {Object} moduleData
56 * @param {Object} html
57 * @returns {string}
58 */
59
60/**
61 * @callback FastCommentsUIExtensionCommentTopCallback
62 * @param {Object} comment
63 * @returns {string}
64 */
65
66/**
67 * @callback FastCommentsUIExtensionCommentTopFilter
68 * @param {Object} comment
69 * @param {string} html
70 * @returns {string}
71 */
72
73/**
74 * @callback FastCommentsUIExtensionCommentBottomCallback
75 * @param {Object} comment
76 * @returns {string}
77 */
78
79/**
80 * @callback FastCommentsUIExtensionMenuBottomCallback
81 * @param {Object} comment
82 * @returns {string}
83 */
84
85/**
86 * @callback FastCommentsUIExtensionMenuFilter
87 * @param {Object} comment
88 * @param {string} html
89 * @returns {string}
90 */
91
92/**
93 * @callback FastCommentsUIExtensionRenderCallback
94 * @returns {string}
95 */
96
97/**
98 * @callback FastCommentsUIExtensionConnectionStatusCallback
99 * @param {boolean} isConnected
100 * @returns {void}
101 */
102
103/**
104 * @callback FastCommentsUIExtensionInitialRenderCallback
105 * @returns {void}
106 */
107
108/**
109 * @callback FastCommentsUIExtensionReplyAreaTop
110 * @param {Object|null} currentUser
111 * @param {boolean} isSaving
112 * @param {boolean} isReplyOpen
113 * @param {string|null} parentId
114 * @returns {string}
115 */
116
117/**
118 * @callback FastCommentsUIExtensionReplyAreaFilter
119 * @param {Object|null} currentUser
120 * @param {boolean} isSaving
121 * @param {boolean} isReplyOpen
122 * @param {string|null} parentId
123 * @param {string|null} html
124 * @returns {string}
125 */
126
127/**
128 * @callback FastCommentsUIExtensionPrepareCommentForSavingCallback
129 * @param {Object} comment
130 * @param {string} parentId
131 */
132
133/**
134 * @callback FastCommentsUIExtensionNewCommentCallback
135 * @param {Object} comment
136 */
137
138/**
139 * @callback FastCommentsUIExtensionPresenceUpdateCallback
140 * @param {Object} update
141 */
142

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.

Ручной запуск повторного рендера комментария

Можно дождаться начальной загрузки страницы и вручную повторно отрендерить комментарий, вызвав 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