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 {Function} [withSessionId] - Вызывается с URL запроса и колбэком. Вызывает колбэк с URL, к которому добавлен id сессии зрителя, когда сторонние cookie заблокированы (тот же путь, что используют запросы комментариев и голосования), либо с неизменённым 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 в начало каждого комментария:

Простое расширение - продолжение
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