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 * The FastCommentsUI extension object. Used for lazy-loading certain components. For example, the review system is not
4 * used by all customers, so we only load that extension when we want it.
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]
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 {FastCommentsUIExtensionMenuBottomCallback} [menuBottom] - (УСТАРЕВШЕЕ) Возвращает HTML для добавления в нижнюю часть элемента меню для каждого комментария.
30 * @property {FastCommentsUIExtensionRenderCallback} [onRender]
31 * @property {FastCommentsUIExtensionConnectionStatusCallback} [onLiveConnectionStatusUpdate]
32 * @property {FastCommentsUIExtensionInitialRenderCallback} [onInitialRenderComplete]
33 * @property {FastCommentsUIExtensionPresenceUpdateCallback} [onPresenceUpdate]
34 */
35
36/**
37 * @callback FastCommentsUIExtensionSetupEventHandlers
38 * @param {Element} element - Корневой элемент.
39 * @param {Object.<string, Function>} clickListeners - Обработчики событий для кликов, по имени класса, которые могут быть изменены по ссылке.
40 * @returns void
41 */
42
43/**
44 * @callback FastCommentsUIExtensionWidgetTopCallback
45 * @param {Object} moduleData
46 * @returns {string}
47 */
48
49/**
50 * @callback FastCommentsUIExtensionWidgetFilter
51 * @param {Object} moduleData
52 * @param {Object} html
53 * @returns {string}
54 */
55
56/**
57 * @callback FastCommentsUIExtensionCommentTopCallback
58 * @param {Object} comment
59 * @returns {string}
60 */
61
62/**
63 * @callback FastCommentsUIExtensionCommentTopFilter
64 * @param {Object} comment
65 * @param {string} html
66 * @returns {string}
67 */
68
69/**
70 * @callback FastCommentsUIExtensionCommentBottomCallback
71 * @param {Object} comment
72 * @returns {string}
73 */
74
75/**
76 * @callback FastCommentsUIExtensionMenuBottomCallback
77 * @param {Object} comment
78 * @returns {string}
79 */
80
81/**
82 * @callback FastCommentsUIExtensionMenuFilter
83 * @param {Object} comment
84 * @param {string} html
85 * @returns {string}
86 */
87
88/**
89 * @callback FastCommentsUIExtensionRenderCallback
90 * @returns {string}
91 */
92
93/**
94 * @callback FastCommentsUIExtensionConnectionStatusCallback
95 * @param {boolean} isConnected
96 * @returns {void}
97 */
98
99/**
100 * @callback FastCommentsUIExtensionInitialRenderCallback
101 * @returns {void}
102 */
103
104/**
105 * @callback FastCommentsUIExtensionReplyAreaTop
106 * @param {Object|null} currentUser
107 * @param {boolean} isSaving
108 * @param {boolean} isReplyOpen
109 * @param {string|null} parentId
110 * @returns {string}
111 */
112
113/**
114 * @callback FastCommentsUIExtensionReplyAreaFilter
115 * @param {Object|null} currentUser
116 * @param {boolean} isSaving
117 * @param {boolean} isReplyOpen
118 * @param {string|null} parentId
119 * @param {string|null} html
120 * @returns {string}
121 */
122
123/**
124 * @callback FastCommentsUIExtensionPrepareCommentForSavingCallback
125 * @param {Object} comment
126 * @param {string} parentId
127 */
128
129/**
130 * @callback FastCommentsUIExtensionNewCommentCallback
131 * @param {Object} comment
132 */
133
134/**
135 * @callback FastCommentsUIExtensionPresenceUpdateCallback
136 * @param {Object} update
137 */
138

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