nodebb-plugin-katex2 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +8 -0
- package/.eslintrc.json +8 -0
- package/LICENSE +26 -0
- package/README.md +277 -0
- package/lib/index.js +18 -0
- package/package.json +39 -0
- package/plugin.json +18 -0
- package/static/js/render.js +312 -0
package/.editorconfig
ADDED
package/.eslintrc.json
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Benjamin Abel.
|
|
4
|
+
|
|
5
|
+
This software also uses portions of the katex auto-render extension from the
|
|
6
|
+
Katex project, which is MIT licensed with the following copyright:
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2015 Khan Academy
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in
|
|
18
|
+
all copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
26
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# KaTeX Math Renderer for NodeBB
|
|
2
|
+
|
|
3
|
+
[English](#english) | [Русский](#russian)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<a name="english"></a>
|
|
8
|
+
## English
|
|
9
|
+
|
|
10
|
+
Modern KaTeX math rendering plugin for NodeBB 4+.
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- ✨ **Lazy loading** - KaTeX loads only when math expressions are detected on the page
|
|
15
|
+
- 📐 **Display mode syntax** - Currently supports `$$...$$` delimiters
|
|
16
|
+
- 🎨 **Server-side ready** - Minimal server logic, client-side rendering
|
|
17
|
+
- 🌐 **CDN delivery** - Uses bundled KaTeX for fast delivery
|
|
18
|
+
- 🚀 **Parser hook integration** - Seamlessly integrates with NodeBB's parser
|
|
19
|
+
- 📱 **Responsive design** - Works on mobile and desktop devices
|
|
20
|
+
- 🌙 **Dark theme support** - Automatically adapts to color schemes
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
23
|
+
|
|
24
|
+
#### Via npm (recommended)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd /path/to/nodebb
|
|
28
|
+
npm install nodebb-plugin-katex2
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Manual installation
|
|
32
|
+
|
|
33
|
+
1. Clone the plugin into `/nodebb/node_modules/`
|
|
34
|
+
2. Activate the plugin in NodeBB admin panel
|
|
35
|
+
3. Restart NodeBB
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cd /path/to/nodebb/node_modules
|
|
39
|
+
git clone https://github.com/mysteren/nodebb-plugin-katex.git
|
|
40
|
+
cd ../..
|
|
41
|
+
npm install ./node_modules/nodebb-plugin-katex
|
|
42
|
+
./nodebb restart
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Usage
|
|
46
|
+
|
|
47
|
+
#### Display mode (separate line)
|
|
48
|
+
|
|
49
|
+
Currently, only the `$$...$$` syntax is fully supported and tested:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
$$
|
|
53
|
+
\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
|
|
54
|
+
$$
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Example with integrals:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
$$
|
|
61
|
+
\int_{0}^{\infty} e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
|
|
62
|
+
$$
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Note:** While the code includes support for `\[...\]` (display) and `\(...\)` (inline) delimiters, these modes are not currently guaranteed to work correctly. Use `$$...$$` for reliable math rendering.
|
|
66
|
+
|
|
67
|
+
### Architecture
|
|
68
|
+
|
|
69
|
+
#### `lib/index.js`
|
|
70
|
+
Main plugin module with hooks:
|
|
71
|
+
- `init()` - Plugin initialization on load
|
|
72
|
+
|
|
73
|
+
#### `static/js/render.js`
|
|
74
|
+
Client-side script for:
|
|
75
|
+
- Loading KaTeX CSS and JS from bundled assets
|
|
76
|
+
- Lazy initialization (only when expressions are present)
|
|
77
|
+
- Dynamic content support (AJAX navigation)
|
|
78
|
+
- Cleaning HTML tags inside math expressions
|
|
79
|
+
|
|
80
|
+
#### `static/css/katex.css`
|
|
81
|
+
Additional styles for:
|
|
82
|
+
- Proper inline expression spacing
|
|
83
|
+
- Display expression alignment
|
|
84
|
+
- Dark theme support
|
|
85
|
+
|
|
86
|
+
### Technical Details
|
|
87
|
+
|
|
88
|
+
#### Server-side
|
|
89
|
+
- Minimal server-side logic
|
|
90
|
+
- Plugin initialization hook only
|
|
91
|
+
- No server-side parsing overhead
|
|
92
|
+
|
|
93
|
+
#### Client-side Loading
|
|
94
|
+
- KaTeX CSS loads only when math expressions are detected
|
|
95
|
+
- KaTeX JS loads from bundled assets
|
|
96
|
+
- Auto-render extension for automatic detection
|
|
97
|
+
- Support for dynamic content via AJAX
|
|
98
|
+
- HTML tag cleanup inside math expressions
|
|
99
|
+
|
|
100
|
+
### Compatibility
|
|
101
|
+
|
|
102
|
+
- **NodeBB**: 4.0+
|
|
103
|
+
- **Node.js**: 18+
|
|
104
|
+
- **Browsers**: All modern browsers (Chrome, Firefox, Safari, Edge)
|
|
105
|
+
|
|
106
|
+
### Dependencies
|
|
107
|
+
|
|
108
|
+
- **katex** (^0.16.27) - KaTeX math typesetting library
|
|
109
|
+
|
|
110
|
+
### Development Dependencies
|
|
111
|
+
|
|
112
|
+
- **eslint** (^9.35.0) - Code linting
|
|
113
|
+
|
|
114
|
+
### Performance
|
|
115
|
+
|
|
116
|
+
- Fast client-side rendering
|
|
117
|
+
- Lazy resource loading
|
|
118
|
+
- Minimal page load impact
|
|
119
|
+
- Caching support
|
|
120
|
+
- No server-side parsing overhead
|
|
121
|
+
|
|
122
|
+
### Scripts
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm run lint # Check code style
|
|
126
|
+
npm run fix # Auto-fix linting issues
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### License
|
|
130
|
+
|
|
131
|
+
MIT
|
|
132
|
+
|
|
133
|
+
### Author
|
|
134
|
+
|
|
135
|
+
Timofey (mysteren)
|
|
136
|
+
|
|
137
|
+
### Acknowledgments
|
|
138
|
+
|
|
139
|
+
- Original plugin by [Benjamin Abel](https://github.com/benabel/nodebb-plugin-katex)
|
|
140
|
+
- [KaTeX](https://katex.org/) - Fast math typesetting library by Khan Academy
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
<a name="russian"></a>
|
|
145
|
+
## Русский
|
|
146
|
+
|
|
147
|
+
Современный плагин для поддержки математических выражений KaTeX в NodeBB 4+.
|
|
148
|
+
|
|
149
|
+
### Возможности
|
|
150
|
+
|
|
151
|
+
- ✨ **Ленивая загрузка** - KaTeX подгружается только когда на странице есть математические выражения
|
|
152
|
+
- 📐 **Режим отображения** - В настоящее время поддерживается синтаксис `$$...$$`
|
|
153
|
+
- 🎨 **Готов к серверу** - Минимальная серверная логика, рендеринг на клиенте
|
|
154
|
+
- 🌐 **CDN доставка** - Использует встроенный KaTeX для быстрой доставки
|
|
155
|
+
- 🚀 **Интеграция с парсером** - Бесшовно интегрируется с парсером NodeBB
|
|
156
|
+
- 📱 **Адаптивный дизайн** - Работает на мобильных и десктопных устройствах
|
|
157
|
+
- 🌙 **Поддержка тёмной темы** - Автоматически адаптируется к схеме цветов
|
|
158
|
+
|
|
159
|
+
### Установка
|
|
160
|
+
|
|
161
|
+
#### Через npm (рекомендуется)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
cd /путь/к/nodebb
|
|
165
|
+
npm install nodebb-plugin-katex2
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Ручная установка
|
|
169
|
+
|
|
170
|
+
1. Клонируйте плагин в `/nodebb/node_modules/`
|
|
171
|
+
2. Активируйте плагин в панели администратора NodeBB
|
|
172
|
+
3. Перезапустите NodeBB
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
cd /путь/к/nodebb/node_modules
|
|
176
|
+
git clone https://github.com/mysteren/nodebb-plugin-katex.git
|
|
177
|
+
cd ../..
|
|
178
|
+
npm install ./node_modules/nodebb-plugin-katex
|
|
179
|
+
./nodebb restart
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Использование
|
|
183
|
+
|
|
184
|
+
#### Display режим (отдельной строкой)
|
|
185
|
+
|
|
186
|
+
В настоящее время полностью поддерживается и протестирован только синтаксис `$$...$$`:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
$$
|
|
190
|
+
\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
|
|
191
|
+
$$
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Пример с интегралами:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
$$
|
|
198
|
+
\int_{0}^{\infty} e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
|
|
199
|
+
$$
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Примечание:** Хотя в коде присутствует поддержка разделителей `\[...\]` (отображаемый режим) и `\(...\)` (встроенный режим), корректная работа этих режимов в настоящее время не гарантируется. Используйте `$$...$$` для надёжного отображения формул.
|
|
203
|
+
|
|
204
|
+
### Архитектура
|
|
205
|
+
|
|
206
|
+
#### `lib/index.js`
|
|
207
|
+
Основной модуль плагина с хуками:
|
|
208
|
+
- `init()` - Инициализация плагина при загрузке
|
|
209
|
+
|
|
210
|
+
#### `static/js/render.js`
|
|
211
|
+
Клиентский скрипт для:
|
|
212
|
+
- Загрузки KaTeX CSS и JS из встроенных ресурсов
|
|
213
|
+
- Ленивой инициализации (только при наличии выражений)
|
|
214
|
+
- Поддержки динамического контента (AJAX навигация)
|
|
215
|
+
- Очистки HTML-тегов внутри математических выражений
|
|
216
|
+
|
|
217
|
+
#### `static/css/katex.css`
|
|
218
|
+
Дополнительные стили для:
|
|
219
|
+
- Правильного отступа inline выражений
|
|
220
|
+
- Выравнивания display выражений
|
|
221
|
+
- Поддержки тёмной темы
|
|
222
|
+
|
|
223
|
+
### Технические детали
|
|
224
|
+
|
|
225
|
+
#### Серверная часть
|
|
226
|
+
- Минимальная логика на сервере
|
|
227
|
+
- Только хук инициализации плагина
|
|
228
|
+
- Отсутствие нагрузки на парсинг на сервере
|
|
229
|
+
|
|
230
|
+
#### Загрузка на клиенте
|
|
231
|
+
- KaTeX CSS загружается только при обнаружении математических выражений
|
|
232
|
+
- KaTeX JS загружается из встроенных ресурсов
|
|
233
|
+
- Расширение auto-render для автоматического обнаружения
|
|
234
|
+
- Поддержка динамического контента через AJAX
|
|
235
|
+
- Очистка HTML-тегов внутри математических выражений
|
|
236
|
+
|
|
237
|
+
### Совместимость
|
|
238
|
+
|
|
239
|
+
- **NodeBB**: 4.0+
|
|
240
|
+
- **Node.js**: 18+
|
|
241
|
+
- **Браузеры**: Все современные браузеры (Chrome, Firefox, Safari, Edge)
|
|
242
|
+
|
|
243
|
+
### Зависимости
|
|
244
|
+
|
|
245
|
+
- **katex** (^0.16.27) - Библиотека математической вёрстки KaTeX
|
|
246
|
+
|
|
247
|
+
### Зависимости для разработки
|
|
248
|
+
|
|
249
|
+
- **eslint** (^9.35.0) - Проверка стиля кода
|
|
250
|
+
|
|
251
|
+
### Производительность
|
|
252
|
+
|
|
253
|
+
- Быстрый рендеринг на клиенте
|
|
254
|
+
- Ленивая загрузка ресурсов
|
|
255
|
+
- Минимальное влияние на загрузку страницы
|
|
256
|
+
- Поддержка кэширования
|
|
257
|
+
- Отсутствие нагрузки на парсинг на сервере
|
|
258
|
+
|
|
259
|
+
### Скрипты
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
npm run lint # Проверка стиля кода
|
|
263
|
+
npm run fix # Автоматическое исправление ошибок стиля
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Лицензия
|
|
267
|
+
|
|
268
|
+
MIT
|
|
269
|
+
|
|
270
|
+
### Автор
|
|
271
|
+
|
|
272
|
+
Timofey (mysteren)
|
|
273
|
+
|
|
274
|
+
### Благодарности
|
|
275
|
+
|
|
276
|
+
- Оригинальный плагин от [Benjamin Abel](https://github.com/benabel/nodebb-plugin-katex)
|
|
277
|
+
- [KaTeX](https://katex.org/) - Быстрая библиотека математической вёрстки от Khan Academy
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Серверная часть плагина
|
|
3
|
+
* Минимальная логика - вся работа на клиенте
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Инициализация плагина при загрузке приложения
|
|
10
|
+
*/
|
|
11
|
+
function init(_params, callback) {
|
|
12
|
+
console.log("[KaTeX] Plugin initialized");
|
|
13
|
+
callback();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
init,
|
|
18
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodebb-plugin-katex2",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "KaTeX math rendering plugin for NodeBB",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/mysteren/nodebb-plugin-katex"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"nodebb",
|
|
12
|
+
"plugin",
|
|
13
|
+
"katex",
|
|
14
|
+
"latex",
|
|
15
|
+
"math",
|
|
16
|
+
"tex"
|
|
17
|
+
],
|
|
18
|
+
"author": "Timofey",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/mysteren/nodebb-plugin-katex/issues"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"katex": "^0.16.27"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"eslint": "^9.35.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"lint": "eslint lib/ static/js/",
|
|
31
|
+
"fix": "eslint --fix lib/ static/js/"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"nbbpm": {
|
|
37
|
+
"compatibility": "^4.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "nodebb-plugin-katex2",
|
|
3
|
+
"name": "KaTeX Math Renderer",
|
|
4
|
+
"description": "Render LaTeX math expressions with KaTeX in NodeBB posts",
|
|
5
|
+
"url": "https://github.com/mysteren/nodebb-plugin-katex",
|
|
6
|
+
"library": "lib/index.js",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"hook": "static:app.load",
|
|
10
|
+
"method": "init"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"scripts": ["static/js/render.js"],
|
|
14
|
+
"stylesheets": ["static/css/katex.css"],
|
|
15
|
+
"staticDirs": {
|
|
16
|
+
"katex": "./node_modules/katex/dist"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ленивая загрузка и рендеринг KaTeX
|
|
3
|
+
* Библиотека загружается только если на странице есть формулы
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
(function () {
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
console.log("Katex render");
|
|
10
|
+
|
|
11
|
+
// Флаги загрузки
|
|
12
|
+
let katexLoaded = false;
|
|
13
|
+
let katexLoading = false;
|
|
14
|
+
let loadCallbacks = [];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Регулярное выражение для поиска формул
|
|
18
|
+
* Ищем разделители: $$, \[, \(
|
|
19
|
+
*/
|
|
20
|
+
const MATH_PATTERN = /\$\$|\\\[|\\\(/;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Проверка наличия формул на странице
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
function hasMathContent() {
|
|
27
|
+
// Проверяем в постах
|
|
28
|
+
const posts = document.querySelectorAll('[component="post/content"]');
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < posts.length; i++) {
|
|
31
|
+
if (MATH_PATTERN.test(posts[i].textContent)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Проверяем в превью редактора
|
|
37
|
+
const preview = document.querySelector(".preview-container");
|
|
38
|
+
if (preview && MATH_PATTERN.test(preview.textContent)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Проверяем в заголовках
|
|
43
|
+
const titles = document.querySelectorAll('[component="topic/title"]');
|
|
44
|
+
for (let i = 0; i < titles.length; i++) {
|
|
45
|
+
if (MATH_PATTERN.test(titles[i].textContent)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Динамическая загрузка CSS файла
|
|
55
|
+
* @param {string} href - Путь к CSS файлу
|
|
56
|
+
* @returns {Promise}
|
|
57
|
+
*/
|
|
58
|
+
function loadCSS(href) {
|
|
59
|
+
return new Promise(function (resolve, reject) {
|
|
60
|
+
// Проверяем, не загружен ли уже
|
|
61
|
+
const existing = document.querySelector('link[href="' + href + '"]');
|
|
62
|
+
if (existing) {
|
|
63
|
+
resolve();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const link = document.createElement("link");
|
|
68
|
+
link.rel = "stylesheet";
|
|
69
|
+
link.href = href;
|
|
70
|
+
link.onload = resolve;
|
|
71
|
+
link.onerror = reject;
|
|
72
|
+
document.head.appendChild(link);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Динамическая загрузка JavaScript файла
|
|
78
|
+
* @param {string} src - Путь к JS файлу
|
|
79
|
+
* @returns {Promise}
|
|
80
|
+
*/
|
|
81
|
+
function loadScript(src) {
|
|
82
|
+
return new Promise(function (resolve, reject) {
|
|
83
|
+
// Проверяем, не загружен ли уже
|
|
84
|
+
const existing = document.querySelector('script[src="' + src + '"]');
|
|
85
|
+
if (existing) {
|
|
86
|
+
resolve();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const script = document.createElement("script");
|
|
91
|
+
script.src = src;
|
|
92
|
+
script.onload = resolve;
|
|
93
|
+
script.onerror = reject;
|
|
94
|
+
document.body.appendChild(script);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Загрузка библиотеки KaTeX (с async/await и параллельной загрузкой)
|
|
100
|
+
* @returns {Promise}
|
|
101
|
+
*/
|
|
102
|
+
async function loadKaTeX() {
|
|
103
|
+
// Если уже загружено
|
|
104
|
+
if (katexLoaded) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Если загружается сейчас - ждем
|
|
109
|
+
if (katexLoading) {
|
|
110
|
+
return new Promise(function (resolve) {
|
|
111
|
+
loadCallbacks.push(resolve);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log("[KaTeX] Loading library...");
|
|
116
|
+
katexLoading = true;
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// Путь к библиотеке в node_modules
|
|
120
|
+
// const basePath = "/plugins/nodebb-plugin-katex/node_modules/katex/dist/";
|
|
121
|
+
// Находим правильный путь
|
|
122
|
+
// Путь к файлам через modules
|
|
123
|
+
const basePath = "/assets/plugins/nodebb-plugin-katex/katex/";
|
|
124
|
+
|
|
125
|
+
// Параллельная загрузка всех файлов
|
|
126
|
+
await Promise.all([
|
|
127
|
+
loadCSS(basePath + "katex.min.css"),
|
|
128
|
+
loadScript(basePath + "katex.min.js"),
|
|
129
|
+
loadScript(basePath + "contrib/auto-render.min.js"),
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
katexLoaded = true;
|
|
133
|
+
katexLoading = false;
|
|
134
|
+
console.log("[KaTeX] Library loaded successfully");
|
|
135
|
+
|
|
136
|
+
// Вызываем все ожидающие колбэки
|
|
137
|
+
loadCallbacks.forEach(function (callback) {
|
|
138
|
+
callback();
|
|
139
|
+
});
|
|
140
|
+
loadCallbacks = [];
|
|
141
|
+
} catch (err) {
|
|
142
|
+
katexLoading = false;
|
|
143
|
+
console.error("[KaTeX] Failed to load library:", err);
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Конфигурация KaTeX
|
|
150
|
+
*/
|
|
151
|
+
const KATEX_CONFIG = {
|
|
152
|
+
delimiters: [
|
|
153
|
+
{ left: "$$", right: "$$", display: true },
|
|
154
|
+
{ left: "\\[", right: "\\]", display: true },
|
|
155
|
+
{ left: "\\(", right: "\\)", display: false },
|
|
156
|
+
],
|
|
157
|
+
throwOnError: false,
|
|
158
|
+
errorColor: "#cc0000",
|
|
159
|
+
strict: false,
|
|
160
|
+
trust: false,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Очистка HTML-тегов внутри формул
|
|
165
|
+
* Markdown может добавить <br>, <p> и другие теги
|
|
166
|
+
* @param {HTMLElement} element
|
|
167
|
+
*/
|
|
168
|
+
function cleanMathElements(element) {
|
|
169
|
+
const walker = document.createTreeWalker(
|
|
170
|
+
element,
|
|
171
|
+
NodeFilter.SHOW_TEXT,
|
|
172
|
+
null,
|
|
173
|
+
false,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const nodesToProcess = [];
|
|
177
|
+
let node;
|
|
178
|
+
|
|
179
|
+
// Собираем все текстовые узлы с формулами
|
|
180
|
+
while ((node = walker.nextNode())) {
|
|
181
|
+
const text = node.textContent;
|
|
182
|
+
if (MATH_PATTERN.test(text)) {
|
|
183
|
+
nodesToProcess.push(node);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Очищаем найденные узлы от HTML
|
|
188
|
+
nodesToProcess.forEach(function (textNode) {
|
|
189
|
+
let parent = textNode.parentNode;
|
|
190
|
+
|
|
191
|
+
if (
|
|
192
|
+
parent &&
|
|
193
|
+
(parent.innerHTML.includes("<br") || parent.innerHTML.includes("<p"))
|
|
194
|
+
) {
|
|
195
|
+
const cleanText = parent.textContent;
|
|
196
|
+
|
|
197
|
+
if (MATH_PATTERN.test(cleanText)) {
|
|
198
|
+
parent.textContent = cleanText;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Рендеринг формул в элементе
|
|
206
|
+
* @param {HTMLElement} element
|
|
207
|
+
*/
|
|
208
|
+
function renderMath(element) {
|
|
209
|
+
if (!element) return;
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
// Сначала очищаем от HTML-тегов
|
|
213
|
+
cleanMathElements(element);
|
|
214
|
+
|
|
215
|
+
// Затем рендерим формулы
|
|
216
|
+
renderMathInElement(element, KATEX_CONFIG);
|
|
217
|
+
} catch (err) {
|
|
218
|
+
console.error("[KaTeX] Render error:", err);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Рендеринг всех постов (async)
|
|
224
|
+
*/
|
|
225
|
+
async function renderAllPosts() {
|
|
226
|
+
// Проверяем наличие формул
|
|
227
|
+
if (!hasMathContent()) {
|
|
228
|
+
console.log("[KaTeX] No math content found, skipping");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// Загружаем KaTeX если нужно
|
|
234
|
+
await loadKaTeX();
|
|
235
|
+
|
|
236
|
+
// Рендерим посты
|
|
237
|
+
const posts = document.querySelectorAll('[component="post/content"]');
|
|
238
|
+
posts.forEach(function (post) {
|
|
239
|
+
renderMath(post);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Рендерим превью
|
|
243
|
+
const preview = document.querySelector(".preview-container");
|
|
244
|
+
if (preview) {
|
|
245
|
+
renderMath(preview);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Рендерим заголовки
|
|
249
|
+
const titles = document.querySelectorAll('[component="topic/title"]');
|
|
250
|
+
titles.forEach(function (title) {
|
|
251
|
+
renderMath(title);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
console.log("[KaTeX] Rendered " + posts.length + " posts");
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error("[KaTeX] Failed to render:", err);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Инициализация
|
|
262
|
+
*/
|
|
263
|
+
function init() {
|
|
264
|
+
// Первый рендеринг
|
|
265
|
+
renderAllPosts();
|
|
266
|
+
|
|
267
|
+
// События NodeBB для динамического контента
|
|
268
|
+
|
|
269
|
+
// Когда загружаются новые посты (скролл, пагинация)
|
|
270
|
+
window.addEventListener("action:posts.loaded", function () {
|
|
271
|
+
setTimeout(function () {
|
|
272
|
+
renderAllPosts();
|
|
273
|
+
}, 50);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Когда открывается тема
|
|
277
|
+
window.addEventListener("action:topic.loaded", function () {
|
|
278
|
+
setTimeout(function () {
|
|
279
|
+
renderAllPosts();
|
|
280
|
+
}, 50);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Когда происходит навигация
|
|
284
|
+
window.addEventListener("action:ajaxify.end", function () {
|
|
285
|
+
setTimeout(function () {
|
|
286
|
+
renderAllPosts();
|
|
287
|
+
}, 100);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Когда обновляется превью в редакторе
|
|
291
|
+
window.addEventListener("action:composer.preview", async function () {
|
|
292
|
+
if (hasMathContent()) {
|
|
293
|
+
try {
|
|
294
|
+
await loadKaTeX();
|
|
295
|
+
const preview = document.querySelector(".preview-container");
|
|
296
|
+
if (preview) {
|
|
297
|
+
renderMath(preview);
|
|
298
|
+
}
|
|
299
|
+
} catch (err) {
|
|
300
|
+
console.error("[KaTeX] Preview render error:", err);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Запуск после загрузки DOM
|
|
307
|
+
if (document.readyState === "loading") {
|
|
308
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
309
|
+
} else {
|
|
310
|
+
init();
|
|
311
|
+
}
|
|
312
|
+
})();
|