@nks-hub/texy-editor 0.1.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/LICENSE +21 -0
- package/README.md +260 -0
- package/dist/texy-editor.cjs +42 -0
- package/dist/texy-editor.cjs.map +1 -0
- package/dist/texy-editor.css +1 -0
- package/dist/texy-editor.js +1663 -0
- package/dist/texy-editor.js.map +1 -0
- package/dist/types/core/DialogManager.d.ts +22 -0
- package/dist/types/core/EventBus.d.ts +10 -0
- package/dist/types/core/KeyboardManager.d.ts +13 -0
- package/dist/types/core/Selection.d.ts +59 -0
- package/dist/types/core/TexyEditor.d.ts +71 -0
- package/dist/types/core/TexyFormatter.d.ts +53 -0
- package/dist/types/core/ToolbarBuilder.d.ts +17 -0
- package/dist/types/core/UndoManager.d.ts +17 -0
- package/dist/types/i18n/cs.d.ts +2 -0
- package/dist/types/i18n/en.d.ts +2 -0
- package/dist/types/i18n/index.d.ts +6 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/parser/TexyParser.d.ts +44 -0
- package/dist/types/parser/index.d.ts +2 -0
- package/dist/types/parser/plugins/bbcode.d.ts +15 -0
- package/dist/types/parser/plugins/image-embed.d.ts +20 -0
- package/dist/types/parser/plugins/index.d.ts +9 -0
- package/dist/types/parser/plugins/link-redirect.d.ts +18 -0
- package/dist/types/parser/plugins/smiley.d.ts +18 -0
- package/dist/types/parser/plugins/youtube.d.ts +23 -0
- package/dist/types/types.d.ts +279 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NKS Hub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# @nks-hub/texy-editor
|
|
2
|
+
|
|
3
|
+
[](https://github.com/nks-hub/texy-ts-editor/actions)
|
|
4
|
+
[](https://www.npmjs.com/package/@nks-hub/texy-editor)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
> Modern TypeScript Texy markup editor with configurable toolbar, client-side parser, live preview, theming, and plugin system. Zero jQuery dependency. Spiritual successor to [Texyla](https://github.com/niclem/texyla).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why Texy Editor?
|
|
12
|
+
|
|
13
|
+
[Texy](https://texy.info) is a powerful markup language created by [David Grudl](https://davidgrudl.com/) that goes beyond Markdown with underline headings, advanced image syntax, modifiers, typography rules, and more. The original [Texyla editor](https://github.com/niclem/texyla) provided a jQuery-based frontend for Texy, but hasn't been maintained since 2014.
|
|
14
|
+
|
|
15
|
+
This project is a **modern rewrite from scratch** — zero jQuery, pure TypeScript, with a client-side parser and extensible plugin system:
|
|
16
|
+
|
|
17
|
+
- **TypeScript-first** — Fully typed API, exported types for all options
|
|
18
|
+
- **Zero dependencies** — No jQuery, no external libraries
|
|
19
|
+
- **Client-side parser** — Live preview without server round-trips
|
|
20
|
+
- **Plugin system** — Extend with custom syntax (YouTube, smileys, BBCode, etc.)
|
|
21
|
+
- **Themeable** — Light/dark themes via CSS custom properties
|
|
22
|
+
- **Dual output** — ESM + CJS builds, tree-shakeable
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @nks-hub/texy-editor
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Attach to a Textarea
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { TexyEditor } from '@nks-hub/texy-editor';
|
|
38
|
+
import '@nks-hub/texy-editor/css';
|
|
39
|
+
|
|
40
|
+
const editor = new TexyEditor('#my-textarea', {
|
|
41
|
+
language: 'en',
|
|
42
|
+
theme: 'light',
|
|
43
|
+
livePreview: true,
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Standalone Parser (No UI)
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { TexyParser } from '@nks-hub/texy-editor';
|
|
51
|
+
|
|
52
|
+
const parser = new TexyParser();
|
|
53
|
+
const html = parser.parse('**bold** and *italic*');
|
|
54
|
+
// <p><strong>bold</strong> and <em>italic</em></p>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
| Feature | Description |
|
|
62
|
+
|---------|-------------|
|
|
63
|
+
| **Full Texy Syntax** | Bold, italic, headings, lists, tables, code blocks, images, links, blockquotes, modifiers |
|
|
64
|
+
| **Typography** | Smart dashes, ellipsis, arrows, symbols, Czech non-breaking spaces |
|
|
65
|
+
| **Live Preview** | Client-side rendering with configurable debounce |
|
|
66
|
+
| **Toolbar** | Configurable button groups, custom buttons, keyboard shortcuts |
|
|
67
|
+
| **Keyboard Shortcuts** | Ctrl+B, Ctrl+I, Tab indent, F11 fullscreen, customizable |
|
|
68
|
+
| **Undo/Redo** | Built-in history with configurable max steps |
|
|
69
|
+
| **i18n** | English and Czech built-in, extensible to any language |
|
|
70
|
+
| **Themes** | Light and dark presets, CSS custom properties for full control |
|
|
71
|
+
| **Plugin System** | Preprocess, inline, and postprocess hooks with placeholder protection |
|
|
72
|
+
| **Split View** | Side-by-side editor + preview mode |
|
|
73
|
+
| **Fullscreen** | Distraction-free editing mode |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Supported Texy Syntax
|
|
78
|
+
|
|
79
|
+
### Inline
|
|
80
|
+
|
|
81
|
+
| Syntax | Output |
|
|
82
|
+
|--------|--------|
|
|
83
|
+
| `**bold**` | **bold** |
|
|
84
|
+
| `*italic*` | *italic* |
|
|
85
|
+
| `` `code` `` | `code` |
|
|
86
|
+
| `--deleted--` | ~~deleted~~ |
|
|
87
|
+
| `++inserted++` | <u>inserted</u> |
|
|
88
|
+
| `^^super^^` | superscript |
|
|
89
|
+
| `__sub__` | subscript |
|
|
90
|
+
| `>>quoted<<` | quoted |
|
|
91
|
+
| `"text":https://url` | link |
|
|
92
|
+
| `[* image.jpg *]` | image |
|
|
93
|
+
| `word((title))` | abbreviation |
|
|
94
|
+
| `''noTexy zone''` | raw text |
|
|
95
|
+
|
|
96
|
+
### Block
|
|
97
|
+
|
|
98
|
+
| Syntax | Output |
|
|
99
|
+
|--------|--------|
|
|
100
|
+
| Underline heading (`===`) | `<h1>`–`<h4>` |
|
|
101
|
+
| Surrounded heading (`=== text ===`) | `<h1>`–`<h4>` |
|
|
102
|
+
| `- item` | unordered list |
|
|
103
|
+
| `1) item` | ordered list |
|
|
104
|
+
| `> quote` | blockquote |
|
|
105
|
+
| `/--code lang` ... `\--` | code block |
|
|
106
|
+
| `/--html` ... `\--` | raw HTML |
|
|
107
|
+
| `/--div .class` ... `\--` | div with modifier |
|
|
108
|
+
| `\| cell \| cell \|` | table |
|
|
109
|
+
| `---` or `***` | horizontal rule |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Plugins
|
|
114
|
+
|
|
115
|
+
Extend the parser with built-in or custom plugins.
|
|
116
|
+
|
|
117
|
+
### Built-in Plugins
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import {
|
|
121
|
+
TexyParser,
|
|
122
|
+
youtubePlugin,
|
|
123
|
+
smileyPlugin,
|
|
124
|
+
bbcodePlugin,
|
|
125
|
+
imageEmbedPlugin,
|
|
126
|
+
linkRedirectPlugin,
|
|
127
|
+
} from '@nks-hub/texy-editor';
|
|
128
|
+
|
|
129
|
+
const parser = new TexyParser({
|
|
130
|
+
plugins: [
|
|
131
|
+
youtubePlugin({ width: 560, height: 315 }),
|
|
132
|
+
smileyPlugin({ baseUrl: 'https://example.com/smileys' }),
|
|
133
|
+
bbcodePlugin(),
|
|
134
|
+
imageEmbedPlugin({ maxWidth: '400px' }),
|
|
135
|
+
linkRedirectPlugin({
|
|
136
|
+
redirectUrl: 'https://example.com/redirect',
|
|
137
|
+
excludeDomains: ['example.com'],
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Plugin | Syntax | Description |
|
|
144
|
+
|--------|--------|-------------|
|
|
145
|
+
| `youtubePlugin` | `[* youtube:ID *]` | YouTube video embeds |
|
|
146
|
+
| `smileyPlugin` | `*123*` | Numeric smiley/emoticon images |
|
|
147
|
+
| `bbcodePlugin` | `[b]`, `[i]`, `[u]`, `[s]`, `[url=]`, `[color=]` | BBCode tag support |
|
|
148
|
+
| `imageEmbedPlugin` | `"[* img *]":URL` | Linked image embeds |
|
|
149
|
+
| `linkRedirectPlugin` | — (postprocess) | Rewrite external links through redirect service |
|
|
150
|
+
|
|
151
|
+
### Custom Plugin
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import type { TexyParserPlugin } from '@nks-hub/texy-editor';
|
|
155
|
+
|
|
156
|
+
const mentionPlugin: TexyParserPlugin = {
|
|
157
|
+
name: 'mentions',
|
|
158
|
+
processInline(text, placeholder) {
|
|
159
|
+
return text.replace(/@([a-zA-Z0-9_]+)/g, (_m, user) =>
|
|
160
|
+
placeholder(`<a href="/profile/${user}">@${user}</a>`)
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const parser = new TexyParser({ plugins: [mentionPlugin] });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Plugin hooks:**
|
|
169
|
+
|
|
170
|
+
| Hook | Stage | Use case |
|
|
171
|
+
|------|-------|----------|
|
|
172
|
+
| `preprocess(text)` | Before parsing | Convert custom syntax to Texy or placeholders |
|
|
173
|
+
| `processInline(text, ph)` | During inline pass | Generate HTML with placeholder protection |
|
|
174
|
+
| `postprocess(html)` | After parsing | Transform final HTML output |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Editor Options
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const editor = new TexyEditor('#textarea', {
|
|
182
|
+
language: 'en', // 'en' | 'cs' | custom
|
|
183
|
+
theme: 'light', // 'light' | 'dark' | custom class
|
|
184
|
+
livePreview: true, // Client-side preview
|
|
185
|
+
livePreviewDelay: 300, // Debounce ms
|
|
186
|
+
splitView: true, // Side-by-side mode
|
|
187
|
+
fullscreen: true, // Enable F11 fullscreen
|
|
188
|
+
autoResize: true, // Auto-grow textarea
|
|
189
|
+
maxUndoSteps: 50, // Undo history limit
|
|
190
|
+
previewPath: '/api/preview', // Server-side preview URL
|
|
191
|
+
toolbar: ['bold', 'italic', null, 'link', 'image'],
|
|
192
|
+
shortcuts: { bold: 'Ctrl+B' },
|
|
193
|
+
plugins: [],
|
|
194
|
+
cssVars: { '--texy-accent': '#0066cc' },
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Build Outputs
|
|
201
|
+
|
|
202
|
+
| File | Format | Size | Use Case |
|
|
203
|
+
|------|--------|------|----------|
|
|
204
|
+
| `dist/texy-editor.js` | ESM | ~66 KB | Modern bundlers (Vite, webpack, Rollup) |
|
|
205
|
+
| `dist/texy-editor.cjs` | CJS | ~47 KB | Node.js / `require()` |
|
|
206
|
+
| `dist/texy-editor.css` | CSS | ~10 KB | Base stylesheet with theme support |
|
|
207
|
+
| `dist/types/` | `.d.ts` | — | TypeScript type declarations |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Install dependencies
|
|
215
|
+
npm install
|
|
216
|
+
|
|
217
|
+
# Dev server with playground
|
|
218
|
+
npm run dev
|
|
219
|
+
|
|
220
|
+
# Run tests (229 tests)
|
|
221
|
+
npm test
|
|
222
|
+
|
|
223
|
+
# Type checking
|
|
224
|
+
npm run typecheck
|
|
225
|
+
|
|
226
|
+
# Production build
|
|
227
|
+
npm run build
|
|
228
|
+
|
|
229
|
+
# Watch mode
|
|
230
|
+
npm run test:watch
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Requirements
|
|
236
|
+
|
|
237
|
+
- **Node.js**: 18+ recommended
|
|
238
|
+
- **TypeScript**: 5.0+ (for TypeScript projects)
|
|
239
|
+
- **Browsers**: Modern browsers with ES6 support
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT License — see [LICENSE](LICENSE) file for details.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Links
|
|
250
|
+
|
|
251
|
+
- [Texy Markup Language](https://texy.info) — The original Texy PHP library by David Grudl
|
|
252
|
+
- [Texyla](https://github.com/niclem/texyla) — The original jQuery-based Texy editor (archived)
|
|
253
|
+
- [Nette Framework](https://nette.org) — PHP framework commonly used with Texy
|
|
254
|
+
- [GitHub Repository](https://github.com/nks-hub/texy-ts-editor)
|
|
255
|
+
- [npm Package](https://www.npmjs.com/package/@nks-hub/texy-editor)
|
|
256
|
+
- [Issue Tracker](https://github.com/nks-hub/texy-ts-editor/issues)
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
**Built for Texy** — A modern successor to Texyla, built from scratch in TypeScript.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";var S=Object.defineProperty;var E=(a,t,e)=>t in a?S(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var h=(a,t,e)=>E(a,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class f{constructor(t){this.textarea=t}get lf(){const t=this.textarea.value;return t.includes(`\r
|
|
2
|
+
`)?`\r
|
|
3
|
+
`:t.includes("\r")?"\r":`
|
|
4
|
+
`}getState(){const{selectionStart:t,selectionEnd:e,value:i}=this.textarea;return{start:t,end:e,text:i.substring(t,e),before:i.substring(0,t),after:i.substring(e)}}text(){return this.getState().text}length(){return this.textarea.selectionEnd-this.textarea.selectionStart}isCursor(){return this.textarea.selectionStart===this.textarea.selectionEnd}select(t,e){this.textarea.focus(),this.textarea.setSelectionRange(t,t+e)}setCursor(t){this.select(t,0)}replace(t){const e=this.getState(),i=this.textarea.scrollTop;this.textarea.value=e.before+t+e.after,this.select(e.start,t.length),this.textarea.scrollTop=i,this.dispatchInput()}tag(t,e){const i=this.getState(),n=this.textarea.scrollTop,s=i.before+t+i.text+e+i.after;this.textarea.value=s,this.isCursorAt(i)?this.setCursor(i.start+t.length):this.select(i.start+t.length,i.text.length),this.textarea.scrollTop=n,this.dispatchInput()}phrase(t,e){this.trimSelect(),this.tag(t,e??t)}trimSelect(){const t=this.getState(),e=t.text.replace(/\s+$/,"");e.length<t.text.length&&this.select(t.start,e.length)}selectBlock(){const{value:t}=this.textarea;let e=this.textarea.selectionStart,i=this.textarea.selectionEnd;for(;e>0&&t[e-1]!==`
|
|
5
|
+
`;)e--;for(;i<t.length&&t[i]!==`
|
|
6
|
+
`;)i++;this.select(e,i-e)}getValue(){return this.textarea.value}setValue(t){this.textarea.value=t,this.dispatchInput()}focus(){this.textarea.focus()}getElement(){return this.textarea}isCursorAt(t){return t.start===t.end}dispatchInput(){this.textarea.dispatchEvent(new Event("input",{bubbles:!0}))}}class b{constructor(t){this.selection=t}bold(){this.selection.trimSelect();const t=this.selection.text();t.match(/^\*\*.*\*\*$/)?this.selection.replace(t.substring(2,t.length-2)):this.selection.tag("**","**")}italic(){this.selection.trimSelect();const t=this.selection.text();t.match(/^\*\*\*.*\*\*\*$/)||t.match(/^\*[^*]+\*$/)?this.selection.replace(t.substring(1,t.length-1)):this.selection.tag("*","*")}deleted(){this.toggleInline("--")}inserted(){this.toggleInline("++")}superscript(){this.toggleInline("^^")}subscript(){this.toggleInline("__")}inlineCode(){this.toggleInline("`")}noTexy(){this.selection.phrase("''","''")}quoted(){this.selection.phrase(">>","<<")}link(t,e){if(t)if(e)this.selection.replace(`"${e}":${t}`);else if(this.selection.isCursor()){this.selection.replace(`"":${t}`);const i=this.selection.getState();this.selection.setCursor(i.start+1)}else this.selection.phrase('"',`":${t}`)}acronym(t){if(!t)return;this.selection.text().match(/^[\p{L}\p{N}]{2,}$/u)?this.selection.tag("",`((${t}))`):this.selection.phrase('"',`"((${t}))`)}image(t,e,i,n){let s="";i==="<>"&&(s+=this.selection.lf+".<>"+this.selection.lf,i="*"),s+="[* "+t+" ",e&&(s+=`.( ${e}) `),s+=(i||"*")+"]",n&&(s+=" *** "+n),this.selection.replace(s)}heading(t){const i={1:"#",2:"*",3:"=",4:"-"}[t],n=this.selection.lf;if(this.selection.selectBlock(),this.selection.isCursor())return;const s=this.selection.text(),r=i.repeat(Math.max(3,s.length));this.selection.tag("",n+r)}headingWithPrompt(t,e){if(!e)return;const n={1:"#",2:"*",3:"=",4:"-"}[t],s=this.selection.lf,r=n.repeat(Math.max(3,e.length));this.selection.tag(e+s+r+s,"")}unorderedList(){this.applyList("ul")}orderedList(){this.applyList("ol")}orderedListRoman(){this.applyList("romans")}orderedListRomanSmall(){this.applyList("smallRomans")}orderedListAlpha(){this.applyList("bigAlphabet")}orderedListAlphaSmall(){this.applyList("smallAlphabet")}blockquote(){this.applyList("bq")}indent(){this.applyList("indent")}unindent(){this.selection.selectBlock();const t=this.selection.lf,i=this.selection.text().split(t).map(n=>{const s=n[0];return s===" "||s===" "?n.substring(1):n});this.selection.replace(i.join(t))}alignLeft(){this.insertAlignment("<")}alignRight(){this.insertAlignment(">")}alignCenter(){this.insertAlignment("<>")}alignJustify(){this.insertAlignment("=")}codeBlock(t){const e=this.selection.lf,i=t?" "+t:"";this.selection.tag(`/--code${i}${e}`,`${e}\\--`)}htmlBlock(){const t=this.selection.lf;this.selection.tag(`/--html${t}`,`${t}\\--`)}divBlock(t){const e=this.selection.lf,i=t?` ${t}`:"";this.selection.tag(`/--div${i}${e}`,`${e}\\--`)}textBlock(){const t=this.selection.lf;this.selection.tag(`/--text${t}`,`${t}\\--`)}commentBlock(){const t=this.selection.lf;this.selection.tag(`/--comment${t}`,`${t}\\--`)}horizontalRule(){const t=this.selection.lf,e=`${t}${t}-------------------${t}${t}`;this.selection.isCursor()?this.selection.tag(e,""):this.selection.replace(e)}table(t,e,i){const n=this.selection.lf;let s=n;for(let r=0;r<e;r++){if(i==="top"&&r===1){s+="|";for(let o=0;o<t;o++)s+="--------";s+=n}for(let o=0;o<t;o++)i==="left"&&o===0?s+="|* ":s+="| ";s+="|"+n}s+=n,this.selection.replace(s)}colorModifier(t){this.selection.phrase('"',`" .{color: ${t}}`)}classModifier(t){this.selection.phrase('"',`" .[${t}]`)}insertSymbol(t){this.selection.isCursor()?this.selection.tag(t,""):this.selection.replace(t)}toggleInline(t){this.selection.trimSelect();const e=this.selection.text(),i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");new RegExp(`^${i}.*${i}$`).test(e)?this.selection.replace(e.substring(t.length,e.length-t.length)):this.selection.tag(t,t)}applyList(t){this.selection.selectBlock();const e=this.selection.lf,i=this.selection.text().split(e),n=this.selection.isCursor()?3:i.length,s=[];for(let r=1;r<=n;r++){const o=this.getBullet(t,r),l=this.selection.isCursor()?"":i[r-1];s.push(o+" "+l)}if(this.selection.isCursor()){const r=s[0],o=s.slice(1).join(e);this.selection.tag(r,e+o)}else this.selection.replace(s.join(e))}getBullet(t,e){switch(t){case"ul":return"-";case"ol":return e+")";case"bq":return">";case"indent":return"";case"romans":return this.toRoman(e)+")";case"smallRomans":return this.toRoman(e).toLowerCase()+")";case"smallAlphabet":return this.toLetter(e)+")";case"bigAlphabet":return this.toLetter(e).toUpperCase()+")";default:return"-"}}toRoman(t){t=Math.min(t,5999);const e=["","M","MM","MMM","MMMM","MMMMM"],i=["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"],n=["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"],s=["","I","II","III","IV","V","VI","VII","VIII","IX"],r=Math.floor(t/1e3),o=Math.floor(t%1e3/100),l=Math.floor(t%100/10),c=t%10;return e[r]+i[o]+n[l]+s[c]}toLetter(t){return"abcdefghijklmnopqrstuvwxyz"[Math.max(0,Math.min(t,26)-1)]}insertAlignment(t){const e=this.selection.getValue(),i=this.selection.getState().start,n=this.selection.lf,s=n+n,r="."+t+n,o=e.substring(0,i).lastIndexOf(s);if(o===-1)this.selection.setValue(r+e),this.selection.setCursor(i+r.length);else{const l=o+s.length;this.selection.setValue(e.substring(0,l)+r+e.substring(l)),this.selection.setCursor(i+r.length)}}}class k{constructor(){h(this,"listeners",new Map)}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var i;(i=this.listeners.get(t))==null||i.delete(e)}emit(t,e){var i;(i=this.listeners.get(t))==null||i.forEach(n=>{try{n(e)}catch(s){console.error(`[TexyEditor] Event handler error for "${t}":`,s)}})}removeAll(){this.listeners.clear()}}class v{constructor(t=100){h(this,"stack",[]);h(this,"pointer",-1);h(this,"maxSteps");this.maxSteps=t}push(t){this.stack=this.stack.slice(0,this.pointer+1),this.stack.push(t),this.stack.length>this.maxSteps&&this.stack.shift(),this.pointer=this.stack.length-1}undo(){return this.pointer<=0?null:(this.pointer--,this.stack[this.pointer])}redo(){return this.pointer>=this.stack.length-1?null:(this.pointer++,this.stack[this.pointer])}canUndo(){return this.pointer>0}canRedo(){return this.pointer<this.stack.length-1}clear(){this.stack=[],this.pointer=-1}}const A={bold:"Ctrl+B",italic:"Ctrl+I",link:"Ctrl+K",undo:"Ctrl+Z",redo:"Ctrl+Shift+Z",submit:"Ctrl+S",fullscreen:"F11",indent:"Tab",unindent:"Shift+Tab"};class w{constructor(t,e){h(this,"bindings",[]);h(this,"boundHandler",null);this.textarea=t,this.customShortcuts=e}register(t,e){var s;const i=((s=this.customShortcuts)==null?void 0:s[t])??A[t];if(!i)return;const n=this.parseShortcut(i);n&&(n.handler=e,this.bindings.push(n))}attach(){this.boundHandler=t=>this.handleKeydown(t),this.textarea.addEventListener("keydown",this.boundHandler)}detach(){this.boundHandler&&(this.textarea.removeEventListener("keydown",this.boundHandler),this.boundHandler=null),this.bindings=[]}handleKeydown(t){for(const e of this.bindings){const i=t.ctrlKey===e.ctrl||t.metaKey===e.ctrl,n=t.shiftKey===e.shift,s=t.altKey===e.alt,r=t.key.toLowerCase()===e.key.toLowerCase();if(i&&n&&s&&r){t.preventDefault(),t.stopPropagation(),e.handler();return}}}parseShortcut(t){const e=t.split("+").map(i=>i.trim());return e.length===0?null:{key:e[e.length-1],ctrl:e.some(i=>i.toLowerCase()==="ctrl"),shift:e.some(i=>i.toLowerCase()==="shift"),alt:e.some(i=>i.toLowerCase()==="alt"),handler:()=>{}}}}const B={bold:'<path d="M6 4h5a3 3 0 0 1 0 6H6zm0 6h6a3 3 0 0 1 0 6H6z" stroke="currentColor" stroke-width="2" fill="none"/>',italic:'<path d="M10 4h4M8 20h4M14 4l-4 16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>',deleted:'<path d="M6 12h12M7 6h10a2 2 0 0 1 0 4H7M7 14h10a2 2 0 0 1 0 4H7" stroke="currentColor" stroke-width="1.5" fill="none"/>',inserted:'<path d="M6 18h12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M8 4v10M16 4v10" stroke="currentColor" stroke-width="1.5" fill="none"/>',superscript:'<path d="M4 18l6-10 6 10M15 4h4l-4 5h4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',subscript:'<path d="M4 4l6 10 6-10M15 16h4l-4 5h4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',code:'<path d="M8 7l-4 5 4 5M16 7l4 5-4 5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',codeBlock:'<rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M8 9l-2 3 2 3M16 9l2 3-2 3" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',heading1:'<path d="M4 6v12M12 6v12M4 12h8M17 8v10M15 8h4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>',heading2:'<path d="M4 6v12M12 6v12M4 12h8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M15 9a2 2 0 0 1 4 0c0 2-4 3-4 5h4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',heading3:'<path d="M4 6v12M12 6v12M4 12h8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M15 8h3l-2 3 2 0a2 2 0 0 1-3 2" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',heading4:'<path d="M4 6v12M12 6v12M4 12h8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M15 8v5h4M19 8v8" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/>',link:'<path d="M10 14a3.5 3.5 0 0 0 5-5l-1-1M14 10a3.5 3.5 0 0 0-5 5l1 1" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>',image:'<rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5" fill="none"/><circle cx="8.5" cy="10" r="1.5" fill="currentColor"/><path d="M21 15l-5-5L5 19" stroke="currentColor" stroke-width="1.5" fill="none"/>',ul:'<path d="M9 6h11M9 12h11M9 18h11" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="4.5" cy="6" r="1.5" fill="currentColor"/><circle cx="4.5" cy="12" r="1.5" fill="currentColor"/><circle cx="4.5" cy="18" r="1.5" fill="currentColor"/>',ol:'<path d="M10 6h10M10 12h10M10 18h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><text x="4" y="8" font-size="8" fill="currentColor" font-family="sans-serif">1</text><text x="4" y="14" font-size="8" fill="currentColor" font-family="sans-serif">2</text><text x="4" y="20" font-size="8" fill="currentColor" font-family="sans-serif">3</text>',blockquote:'<path d="M6 10c0-3 2-5 5-5M13 10c0-3 2-5 5-5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M6 14c0 3 2 5 5 5M13 14c0 3 2 5 5 5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>',hr:'<path d="M3 12h18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3"/>',table:'<rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M3 10h18M3 16h18M10 4v16" stroke="currentColor" stroke-width="1.5"/>',color:'<circle cx="12" cy="12" r="8" stroke="currentColor" stroke-width="1.5" fill="none"/><circle cx="12" cy="12" r="3" fill="currentColor"/>',symbol:'<text x="6" y="17" font-size="16" fill="currentColor" font-family="serif">Ω</text>',acronym:'<path d="M4 16h4l2-6 2 6h4" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round"/><path d="M6 13h4" stroke="currentColor" stroke-width="1.5"/><path d="M16 8a2 2 0 1 0 4 0 2 2 0 0 0-4 0" stroke="currentColor" stroke-width="1.5" fill="none"/>',alignLeft:'<path d="M4 6h16M4 10h10M4 14h16M4 18h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',alignRight:'<path d="M4 6h16M10 10h10M4 14h16M10 18h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',alignCenter:'<path d="M4 6h16M7 10h10M4 14h16M7 18h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',alignJustify:'<path d="M4 6h16M4 10h16M4 14h16M4 18h16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>',indent:'<path d="M12 6h8M12 12h8M12 18h8M4 8l4 4-4 4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',unindent:'<path d="M12 6h8M12 12h8M12 18h8M8 8l-4 4 4 4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',undo:'<path d="M4 8h12a4 4 0 0 1 0 8H8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M7 5l-3 3 3 3" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',redo:'<path d="M20 8H8a4 4 0 0 0 0 8h8" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M17 5l3 3-3 3" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',fullscreen:'<path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>',preview:'<path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z" stroke="currentColor" stroke-width="1.5" fill="none"/><circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="1.5" fill="none"/>',edit:'<path d="M14 3l3 3L7 16l-4 1 1-4L14 3z" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linejoin="round"/>',splitView:'<rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M12 4v16" stroke="currentColor" stroke-width="1.5"/>',upload:'<path d="M12 16V4M8 8l4-4 4 4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 14v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>'};function H(a){const t=B[a];return t?`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" class="te-icon">${t}</svg>`:""}class y{constructor(t,e){h(this,"toolbar");h(this,"bottomBar");this.strings=t,this.actionHandler=e}build(t){this.toolbar=document.createElement("div"),this.toolbar.className="te-toolbar",this.toolbar.setAttribute("role","toolbar"),this.toolbar.setAttribute("aria-label","Editor toolbar");for(const e of t){const i=this.renderItem(e);i&&this.toolbar.appendChild(i)}return this.toolbar}buildBottomBar(t,e,i){this.bottomBar=document.createElement("div"),this.bottomBar.className="te-bottom-bar";const n=document.createElement("div");n.className="te-bottom-left";for(const l of t)n.appendChild(this.createButton(l));this.bottomBar.appendChild(n);const s=document.createElement("div");s.className="te-bottom-right";const r=document.createElement("div");r.className="te-bottom-right-edit";for(const l of e)r.appendChild(this.createButton(l));s.appendChild(r);const o=document.createElement("div");o.className="te-bottom-right-preview",o.style.display="none";for(const l of i)o.appendChild(this.createButton(l));return s.appendChild(o),this.bottomBar.appendChild(s),this.bottomBar}renderItem(t){return t===null?this.createSeparator():typeof t=="string"?this.createButton(t):this.isGroup(t)?this.createDropdown(t):this.isCustomButton(t)?this.createCustomButton(t):null}createButton(t){const e=document.createElement("button");e.type="button",e.className=`te-btn te-btn-${t}`,e.setAttribute("data-action",t);const i=this.strings[t]??t;e.setAttribute("aria-label",i),e.setAttribute("title",i);const n=H(t);return n?e.innerHTML=n:e.textContent=i,e.addEventListener("click",s=>{s.preventDefault(),this.actionHandler(t)}),e}createCustomButton(t){const e=document.createElement("button");return e.type="button",e.className=`te-btn te-btn-custom te-btn-${t.name}`,e.setAttribute("aria-label",t.label),e.setAttribute("title",t.label),t.icon?e.innerHTML=t.icon:e.textContent=t.label,e.addEventListener("click",i=>{i.preventDefault(),this.actionHandler(t.name)}),e}createSeparator(){const t=document.createElement("span");return t.className="te-separator",t.setAttribute("role","separator"),t.setAttribute("aria-orientation","vertical"),t}createDropdown(t){const e=document.createElement("div");e.className="te-dropdown";const i=document.createElement("button");i.type="button",i.className="te-btn te-dropdown-trigger",i.setAttribute("aria-haspopup","true"),i.setAttribute("aria-expanded","false"),i.textContent=t.label??"...";const n=document.createElement("div");n.className="te-dropdown-menu",n.setAttribute("role","menu");for(const s of t.items){const r=this.createButton(s);r.setAttribute("role","menuitem"),n.appendChild(r)}return i.addEventListener("click",s=>{s.preventDefault(),s.stopPropagation();const r=e.classList.toggle("te-dropdown-open");i.setAttribute("aria-expanded",String(r))}),document.addEventListener("click",()=>{e.classList.remove("te-dropdown-open"),i.setAttribute("aria-expanded","false")}),e.appendChild(i),e.appendChild(n),e}isGroup(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="group"}isCustomButton(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="button"}}class C{constructor(t,e){h(this,"openDialogs",new Map);this.container=t,this.strings=e}open(t,e){this.close(t);const i=document.createElement("dialog");i.className="te-dialog",e.width&&(i.style.width=e.width+"px");const n=document.createElement("div");n.className="te-dialog-header";const s=document.createElement("h3");s.className="te-dialog-title",s.textContent=e.title,n.appendChild(s);const r=document.createElement("button");r.type="button",r.className="te-dialog-close",r.setAttribute("aria-label",this.strings.close),r.innerHTML="×",r.addEventListener("click",()=>this.close(t)),n.appendChild(r),i.appendChild(n);const o=document.createElement("div");o.className="te-dialog-body",o.appendChild(e.content),i.appendChild(o);const l=document.createElement("div");l.className="te-dialog-footer";const c=document.createElement("button");c.type="button",c.className="te-btn te-dialog-cancel",c.textContent=this.strings.cancel,c.addEventListener("click",()=>{var p;(p=e.onCancel)==null||p.call(e),this.close(t)}),l.appendChild(c);const u=document.createElement("button");u.type="button",u.className="te-btn te-dialog-submit",u.textContent=this.strings.ok,u.addEventListener("click",()=>{e.onSubmit(),this.close(t)}),l.appendChild(u),i.appendChild(l),i.addEventListener("cancel",p=>{var g;p.preventDefault(),(g=e.onCancel)==null||g.call(e),this.close(t)}),this.container.appendChild(i),this.openDialogs.set(t,i),i.showModal();const d=i.querySelector("input, select, textarea");return d==null||d.focus(),i}close(t){const e=this.openDialogs.get(t);e&&(e.close(),e.remove(),this.openDialogs.delete(t))}closeAll(){for(const[t]of this.openDialogs)this.close(t)}isOpen(t){return this.openDialogs.has(t)}}class M{constructor(t={}){h(this,"options");h(this,"plugins");this.options={rules:t.rules??[],plugins:t.plugins??[],enableTypography:t.enableTypography??!0,enableAutolinks:t.enableAutolinks??!0},this.plugins=this.options.plugins}addPlugin(t){this.plugins.push(t)}removePlugin(t){this.plugins=this.plugins.filter(e=>e.name!==t)}getPlugins(){return this.plugins}parse(t){if(!t.trim())return"";let e=t.replace(/\r\n/g,`
|
|
7
|
+
`).replace(/\r/g,`
|
|
8
|
+
`);for(const s of this.plugins)s.preprocess&&(e=s.preprocess(e));const i=this.options.rules.filter(s=>s.block).sort((s,r)=>s.priority-r.priority);for(const s of i)e=s.block(e);let n=this.parseBlocks(e);for(const s of this.plugins)s.postprocess&&(n=s.postprocess(n));return n}parseBlocks(t){const e=[],i=this.splitBlockSegments(t);for(const n of i){const s=n.trim();if(!s)continue;const r=this.tryCommentBlock(s)??this.tryCodeBlock(s)??this.tryHtmlBlock(s)??this.tryDivBlock(s)??this.tryTextBlock(s)??this.tryTable(s)??this.tryHeading(s)??this.tryHorizontalRule(s)??this.tryBlockquote(s)??this.tryList(s)??this.tryParagraph(s);r&&e.push(r)}return e.join(`
|
|
9
|
+
`)}splitBlockSegments(t){const e=[],i=t.split(`
|
|
10
|
+
`);let n=[],s=!1;for(const r of i)if(!s&&/^\/--/.test(r)){if(n.length>0){const o=n.join(`
|
|
11
|
+
`);e.push(...this.splitParagraphs(o)),n=[]}s=!0,n.push(r)}else s&&/^\\--/.test(r)?(n.push(r),e.push(n.join(`
|
|
12
|
+
`)),n=[],s=!1):n.push(r);if(n.length>0){const r=n.join(`
|
|
13
|
+
`);s?e.push(r):e.push(...this.splitParagraphs(r))}return e}splitParagraphs(t){return t.split(/\n{2,}/).filter(e=>e.trim())}tryCommentBlock(t){return t.match(/^\/--comment[ \t]*\n([\s\S]*?)(?:\n\\--|$)/)?"<!-- comment -->":null}tryCodeBlock(t){const e=t.match(/^\/--code[ \t]*(\S*)[ \t]*\n([\s\S]*?)(?:\n\\--|$)/);if(!e)return null;const i=e[1],n=this.escapeHtml(e[2]);return`<pre><code${i?` class="language-${this.escapeHtml(i)}"`:""}>${n}</code></pre>`}tryHtmlBlock(t){const e=t.match(/^\/--html[ \t]*\n([\s\S]*?)(?:\n\\--|$)/);return e?e[1]:null}tryDivBlock(t){const e=t.match(/^\/--div[ \t]*(.*?)[ \t]*\n([\s\S]*?)(?:\n\\--|$)/);if(!e)return null;const i=e[1],n=this.parseBlocks(e[2]);return`<div${i?this.parseModifierAttrs(i):""}>
|
|
14
|
+
${n}
|
|
15
|
+
</div>`}tryTextBlock(t){const e=t.match(/^\/--text[ \t]*\n([\s\S]*?)(?:\n\\--|$)/);return e?`<pre>${this.escapeHtml(e[1])}</pre>`:null}tryTable(t){const e=t.split(`
|
|
16
|
+
`);if(!e[0].match(/^\|/))return null;const i=o=>/^\|/.test(o.trim())||/^\|[-=]+/.test(o.trim());if(!e.every(o=>!o.trim()||i(o)))return null;let n=`<table>
|
|
17
|
+
`,s=!1,r=!1;for(const o of e){const l=o.trim();if(!l)continue;if(/^\|[-=]+/.test(l)){s&&!r&&(n+=`</thead>
|
|
18
|
+
<tbody>
|
|
19
|
+
`,r=!0);continue}const c=this.parseTableRow(l);if(!c)continue;c.some(d=>d.isHeader)&&!r&&!s&&(n+=`<thead>
|
|
20
|
+
`,s=!0),n+="<tr>";for(const d of c){const p=d.isHeader?"th":"td",g=this.parseInline(d.content.trim());n+=`<${p}>${g}</${p}>`}n+=`</tr>
|
|
21
|
+
`}return s&&!r&&(n+=`</thead>
|
|
22
|
+
`),r&&(n+=`</tbody>
|
|
23
|
+
`),n+="</table>",n}parseTableRow(t){let e=t.trim();return e.startsWith("|")?(e=e.substring(1),e.endsWith("|")&&(e=e.substring(0,e.length-1)),e.split("|").map(n=>{const s=n.trim();return s.startsWith("*")?{content:s.substring(1).trim(),isHeader:!0}:{content:s,isHeader:!1}})):null}tryHeading(t){const e=t.split(`
|
|
24
|
+
`),i={"#":1,"*":2,"=":3,"-":4},n=e[0].match(/^(#{3,}|\*{3,}|={3,}|-{3,})\s+(.+?)\s+\1\s*$/);if(n){const s=n[1][0],r=i[s];if(r){const o=this.parseInline(n[2]),l=e.slice(1).join(`
|
|
25
|
+
`).trim();let c=`<h${r}>${o}</h${r}>`;return l&&(c+=`
|
|
26
|
+
`+this.parseBlocks(l)),c}}if(e.length>=2){const s=e[0],o=e[1].match(/^(#{3,}|\*{3,}|={3,}|-{3,})\s*$/);if(o&&s.trim()){const l=o[1][0],c=i[l];if(c){const u=this.parseInline(s.trim()),d=e.slice(2).join(`
|
|
27
|
+
`).trim();let p=`<h${c}>${u}</h${c}>`;return d&&(p+=`
|
|
28
|
+
`+this.parseBlocks(d)),p}}}return null}tryHorizontalRule(t){return/^-{3,}\s*$/.test(t.trim())&&!t.includes(`
|
|
29
|
+
`)||/^\*{3,}\s*$/.test(t.trim())&&!t.includes(`
|
|
30
|
+
`)?"<hr>":null}tryBlockquote(t){const e=t.split(`
|
|
31
|
+
`);if(!e[0].match(/^>\s/)||!e.every(r=>/^>\s?/.test(r)||!r.trim()))return null;const n=e.map(r=>r.replace(/^>\s?/,"")).join(`
|
|
32
|
+
`);return`<blockquote>
|
|
33
|
+
${this.parseBlocks(n)}
|
|
34
|
+
</blockquote>`}tryList(t){const e=t.split(`
|
|
35
|
+
`);if(/^[-*+]\s/.test(e[0]))return this.parseListItems(e,/^[-*+]\s/,"ul");if(/^(\d+[).]|[a-z][).]|[A-Z][).]|[IVXLCDM]+[).]|[ivxlcdm]+[).])\s/.test(e[0])){const i=e[0];let n="";return/^\d/.test(i)?n="":/^[ivxlcdm]+\)/i.test(i)&&/^[IV]/.test(i)?n=' type="I"':/^[ivxlcdm]+\)/.test(i)?n=' type="i"':/^[A-Z]\)/.test(i)?n=' type="A"':/^[a-z]\)/.test(i)&&(n=' type="a"'),this.parseListItems(e,/^(?:\d+[).]|[a-zA-Z][).]|[IVXLCDM]+[).]|[ivxlcdm]+[).])\s/,"ol",n)}return null}parseListItems(t,e,i,n=""){const s=[];let r=[];for(const l of t)e.test(l)?(r.length>0&&s.push(r.join(`
|
|
36
|
+
`)),r=[l.replace(e,"")]):/^\s+/.test(l)&&r.length>0?r.push(l.replace(/^\s+/,"")):!l.trim()&&r.length>0?r.push(""):r.push(l);r.length>0&&s.push(r.join(`
|
|
37
|
+
`));let o=`<${i}${n}>
|
|
38
|
+
`;for(const l of s){const c=l.trim(),u=this.tryList(c);u&&c!==l.trim()?o+=`<li>${u}</li>
|
|
39
|
+
`:o+=`<li>${this.parseInline(c)}</li>
|
|
40
|
+
`}return o+=`</${i}>`,o}tryParagraph(t){const e=t.match(/^\.([\<\>\=]+)\n([\s\S]+)$/);if(e){const n=this.parseAlignModifier(e[1]),s=this.parseInline(e[2].trim());return`<p${n}>${s}</p>`}return`<p>${this.parseInline(t)}</p>`}parseAlignModifier(t){switch(t){case"<":return' style="text-align:left"';case">":return' style="text-align:right"';case"<>":return' style="text-align:center"';case"=":return' style="text-align:justify"';default:return""}}parseInline(t){const e=new Map;let i=0;const n=o=>{const l=`\0PH${i++}\0`;return e.set(l,o),l};let s=t;s=s.replace(/''(.+?)''/g,(o,l)=>n(l)),s=s.replace(/`([^`]+)`/g,(o,l)=>n(`<code>${this.escapeHtml(l)}</code>`)),s=s.replace(/\[\*\s+(\S+?)(?:\s+\.\(([^)]*)\))?\s*([<>*]?)\s*\]/g,(o,l,c,u)=>{let d="";u==="<"?d=' style="float:left"':u===">"&&(d=' style="float:right"');const p=c?` alt="${this.escapeHtml(c)}"`:' alt=""';return n(`<img src="${this.escapeHtml(l)}"${p}${d}>`)});const r=this.options.rules.filter(o=>o.inline).sort((o,l)=>o.priority-l.priority);for(const o of r)s=o.inline(s);for(const o of this.plugins)o.processInline&&(s=o.processInline(s,n));s=s.replace(/"([^"]+?)":((?:https?:\/\/|ftp:\/\/|mailto:)\S+)/g,(o,l,c)=>n(`<a href="${this.escapeHtml(c)}">${this.escapeHtml(l)}</a>`)),s=s.replace(/"([^"]+?)":(\S+)/g,(o,l,c)=>n(`<a href="${this.escapeHtml(c)}">${this.escapeHtml(l)}</a>`)),s=s.replace(/(\w+)\(\(([^)]+)\)\)/g,(o,l,c)=>n(`<abbr title="${this.escapeHtml(c)}">${this.escapeHtml(l)}</abbr>`)),s=s.replace(/"(.+?)"\s*\.\{([^}]+)\}/g,(o,l,c)=>n(`<span style="${this.escapeHtml(c)}">${this.escapeHtml(l)}</span>`)),s=s.replace(/"(.+?)"\s*\.\[([^\]]+)\]/g,(o,l,c)=>n(`<span class="${this.escapeHtml(c)}">${this.escapeHtml(l)}</span>`)),this.options.enableTypography&&(s=this.applyTypography(s)),s=this.escapeHtmlPreservingPlaceholders(s,e),s=s.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),s=s.replace(new RegExp("(?<!\\*)\\*([^*]+?)\\*(?!\\*)","g"),"<em>$1</em>"),s=s.replace(/--(.+?)--/g,"<del>$1</del>"),s=s.replace(/\+\+(.+?)\+\+/g,"<ins>$1</ins>"),s=s.replace(/\^\^(.+?)\^\^/g,"<sup>$1</sup>"),s=s.replace(/__(.+?)__/g,"<sub>$1</sub>"),s=s.replace(/>>(.+?)<</g,"<q>$1</q>"),this.options.enableAutolinks&&(s=s.replace(new RegExp('(?<![&"=\\/])(?:https?:\\/\\/|www\\.)[^\\s<>&]+',"g"),o=>`<a href="${o.startsWith("www.")?`https://${o}`:o}">${o}</a>`)),s=s.replace(/\n/g,`<br>
|
|
41
|
+
`);for(const[o,l]of e)s=s.replace(o,l);return s}escapeHtmlPreservingPlaceholders(t,e){const i=[];let n=t;for(;n.length>0;){const s=n.indexOf("\0PH");if(s===-1){i.push(this.escapeHtml(n));break}s>0&&i.push(this.escapeHtml(n.substring(0,s)));const r=n.indexOf("\0",s+1);if(r===-1){i.push(this.escapeHtml(n.substring(s)));break}const o=n.substring(s,r+1);e.has(o)?i.push(o):i.push(this.escapeHtml(n.substring(s,r+1))),n=n.substring(r+1)}return i.join("")}applyTypography(t){return t=t.replace(/<->/g,"↔"),t=t.replace(/<=>/g,"⇔"),t=t.replace(/-->/g,"→"),t=t.replace(/<--/g,"←"),t=t.replace(/==>/g,"⇒"),t=t.replace(/<== /g,"⇐ "),t=t.replace(/---/g,"—"),t=t.replace(/(\w)--(\w)/g,"$1–$2"),t=t.replace(/\s--\s/g," – "),t=t.replace(/\.\.\./g,"…"),t=t.replace(/\(tm\)/gi,"™"),t=t.replace(/\(c\)/gi,"©"),t=t.replace(/\(r\)/gi,"®"),t=t.replace(/(\d)\s*x\s*(\d)/g,"$1×$2"),t=t.replace(/\b([ksvzuoiaKSVZUOIA]) /g,"$1 "),t}parseModifierAttrs(t){const e=[],i=t.match(/\{([^}]+)\}/);i&&e.push(`style="${this.escapeHtml(i[1])}"`);const n=t.match(/\[([^\]]+)\]/);n&&e.push(`class="${this.escapeHtml(n[1])}"`);const s=t.match(/#([a-zA-Z][\w-]*)/);s&&e.push(`id="${this.escapeHtml(s[1])}"`);const r=t.match(/\(([^)]+)\)/);return r&&e.push(`title="${this.escapeHtml(r[1])}"`),e.length>0?" "+e.join(" "):""}escapeHtml(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}}function T(a={}){const t=a.width??560,e=a.height??315,i=a.allowFullscreen!==!1,n=a.wrapperClass??"texy-youtube";return{name:"youtube",preprocess(s){return s=s.replace(/\[\*\s+youtube:([a-zA-Z0-9_-]+)\s*\*?\]/g,"{{youtube:$1}}"),s=s.replace(/\[\*\s+(https?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)[^\s]*)\s*\*?\]/g,(r,o,l)=>`{{youtube:${l}}}`),s=s.replace(/\[\*\s+https?:\/\/(?:www\.)?youtube\.com\/shorts\/([a-zA-Z0-9_-]+)[^\s]*\s*\*?\]/g,"{{youtube:$1}}"),s=s.replace(/\[\*\s+https?:\/\/youtu\.be\/([a-zA-Z0-9_-]+)[^\s]*\s*\*?\]/g,"{{youtube:$1}}"),s},processInline(s,r){return s.replace(/\{\{youtube:([a-zA-Z0-9_-]+)\}\}/g,(o,l)=>{const u=`<div class="${n}"><iframe width="${t}" height="${e}" src="https://www.youtube.com/embed/${l}" frameborder="0"${i?" allowfullscreen":""}></iframe></div>`;return r(u)})}}}function I(a){const t=a.baseUrl.replace(/\/$/,""),e=a.format??"gif",i=a.ariaLabels??{},n=a.className??"smiley";return{name:"smiley",processInline(s,r){return s.replace(new RegExp("(?<!\\*)\\*(\\d{1,6})\\*(?!\\*)","g"),(o,l)=>{const c=i[l]??"smiley",u=`<img src="${t}/${l}.${e}" alt="${c}" class="${n}">`;return r(u)})}}}function P(a){const t=a.redirectUrl,e=a.excludeDomains??[],i=a.targetBlank!==!1,n=a.noopener!==!1;return{name:"link-redirect",postprocess(s){return s.replace(/<a\s+href="(https?:\/\/[^"]+)"/g,(r,o)=>{try{const u=new URL(o).hostname;if(e.some(d=>u===d||u.endsWith("."+d)))return r}catch{return r}const l=encodeURIComponent(o),c=[`href="${t}?url=${l}"`];return i&&c.push('target="_blank"'),n&&c.push('rel="noopener noreferrer"'),`<a ${c.join(" ")}`})}}}function D(){return{name:"bbcode",processInline(a,t){return a=a.replace(/\[b\]([\s\S]*?)\[\/b\]/gi,(e,i)=>t(`<strong>${i}</strong>`)),a=a.replace(/\[i\]([\s\S]*?)\[\/i\]/gi,(e,i)=>t(`<em>${i}</em>`)),a=a.replace(/\[u\]([\s\S]*?)\[\/u\]/gi,(e,i)=>t(`<u>${i}</u>`)),a=a.replace(/\[s\]([\s\S]*?)\[\/s\]/gi,(e,i)=>t(`<del>${i}</del>`)),a=a.replace(/\[url=([^\]]+)\]([\s\S]*?)\[\/url\]/gi,(e,i,n)=>t(`<a href="${i}">${n}</a>`)),a=a.replace(/\[color=([^\]]+)\]([\s\S]*?)\[\/color\]/gi,(e,i,n)=>t(`<span style="color:${i}">${n}</span>`)),a}}}function N(a={}){const t=a.maxWidth??"300px",e=a.className??"texy-image",i=a.enableLinkedImages!==!1;return{name:"image-embed",preprocess(n){return i&&(n=n.replace(/"\[\*\s+(\S+?)(?:\s+\.\(([^)]*)\))?\s*\*?\]"\s*:\s*(\S+)/g,(s,r,o,l)=>{const c=o?`|alt:${o}`:"";return`{{imglink:${r}${c}|${l}}}`})),n},processInline(n,s){return n=n.replace(/\{\{imglink:(\S+?)(?:\|alt:([^|]*))?\|(\S+)\}\}/g,(r,o,l,c)=>{const u=l?` alt="${l}"`:' alt=""',d=`<a href="${c}"><img src="${o}"${u} class="${e}" style="max-width:${t}"></a>`;return s(d)}),n}}}const $={bold:"Tučně",italic:"Kurzíva",deleted:"Přeškrtnuté",inserted:"Podtržené",superscript:"Horní index",subscript:"Dolní index",code:"Kód",codeBlock:"Blok kódu",heading1:"Nadpis 1",heading2:"Nadpis 2",heading3:"Nadpis 3",heading4:"Nadpis 4",link:"Odkaz",linkUrl:"URL odkazu",linkText:"Text odkazu",image:"Obrázek",imageUrl:"URL obrázku",imageAlt:"Popis obrázku",imageAlign:"Zarovnání",unorderedList:"Odrážky",orderedList:"Číslovaný seznam",blockquote:"Citace",horizontalRule:"Vodorovná čára",table:"Tabulka",tableRows:"Řádky",tableCols:"Sloupce",color:"Barva textu",symbol:"Speciální znak",acronym:"Zkratka",acronymTitle:"Význam zkratky",alignLeft:"Zarovnat vlevo",alignRight:"Zarovnat vpravo",alignCenter:"Zarovnat na střed",alignJustify:"Zarovnat do bloku",indent:"Odsadit",unindent:"Zrušit odsazení",fullscreen:"Celá obrazovka",preview:"Náhled",edit:"Upravit",splitView:"Rozdělený pohled",undo:"Zpět",redo:"Vpřed",upload:"Nahrát soubor",uploadDragDrop:"Přetáhněte soubor sem nebo klikněte",previewEmpty:"Zadejte text pro zobrazení náhledu.",previewLoading:"Načítání náhledu…",headingPrompt:"Text nadpisu",ok:"OK",cancel:"Zrušit",close:"Zavřít"},x={bold:"Bold",italic:"Italic",deleted:"Strikethrough",inserted:"Underline",superscript:"Superscript",subscript:"Subscript",code:"Inline code",codeBlock:"Code block",heading1:"Heading 1",heading2:"Heading 2",heading3:"Heading 3",heading4:"Heading 4",link:"Link",linkUrl:"Link URL",linkText:"Link text",image:"Image",imageUrl:"Image URL",imageAlt:"Image description",imageAlign:"Alignment",unorderedList:"Bullet list",orderedList:"Numbered list",blockquote:"Blockquote",horizontalRule:"Horizontal rule",table:"Table",tableRows:"Rows",tableCols:"Columns",color:"Text color",symbol:"Special character",acronym:"Acronym",acronymTitle:"Acronym meaning",alignLeft:"Align left",alignRight:"Align right",alignCenter:"Align center",alignJustify:"Justify",indent:"Indent",unindent:"Outdent",fullscreen:"Fullscreen",preview:"Preview",edit:"Edit",splitView:"Split view",undo:"Undo",redo:"Redo",upload:"Upload file",uploadDragDrop:"Drag & drop a file here or click",previewEmpty:"Enter some text to see preview.",previewLoading:"Loading preview…",headingPrompt:"Heading text",ok:"OK",cancel:"Cancel",close:"Close"},m={cs:$,en:x};function L(a){return m[a]??m.en}function R(a,t){m[a]=t}const V=["bold","italic",null,"ul","ol",null,"link","image",null,"blockquote","code","codeBlock",null,"heading1","heading2","heading3",null,"hr","table",null,"color","symbol"],z={language:"cs",defaultView:"edit",width:"100%",livePreview:!0,livePreviewDelay:400,theme:"light",splitView:!1,fullscreen:!1,autoResize:!0,maxUndoSteps:100,texyCfg:""};class U{constructor(t,e={}){h(this,"container");h(this,"textarea");h(this,"editDiv");h(this,"previewDiv");h(this,"previewContent");h(this,"selection");h(this,"formatter");h(this,"events");h(this,"undoManager");h(this,"keyboard");h(this,"toolbarBuilder");h(this,"dialogManager");h(this,"strings");h(this,"options");h(this,"currentView","edit");h(this,"isFullscreen",!1);h(this,"parser");h(this,"plugins",[]);h(this,"previewDebounceTimer",null);h(this,"lastPreviewedValue","");h(this,"destroyed",!1);h(this,"actions",{});if(typeof t=="string"){const i=document.querySelector(t);if(!i)throw new Error(`TexyEditor: textarea "${t}" not found`);this.textarea=i}else this.textarea=t;if(!this.textarea.dataset.texyEditor){if(this.textarea.dataset.texyEditor="true",this.options={...z,...e},this.strings=L(this.options.language??"cs"),this.selection=new f(this.textarea),this.formatter=new b(this.selection),this.events=new k,this.undoManager=new v(this.options.maxUndoSteps),this.keyboard=new w(this.textarea,this.options.shortcuts),this.parser=new M,this.registerActions(),this.toolbarBuilder=new y(this.strings,i=>this.execAction(i)),this.buildDOM(),this.applyTheme(),this.options.cssVars)for(const[i,n]of Object.entries(this.options.cssVars))this.container.style.setProperty(i,n);if(this.setupKeyboard(),this.options.autoResize&&this.setupAutoResize(),this.setupUndoTracking(),this.currentView=this.options.defaultView??"edit",this.options.plugins)for(const i of this.options.plugins)this.loadPlugin(i);this.undoManager.push({value:this.textarea.value,cursorStart:0,cursorEnd:0})}}getValue(){return this.textarea.value}setValue(t){this.textarea.value=t,this.textarea.dispatchEvent(new Event("input",{bubbles:!0}))}getSelection(){return this.selection.text()}replaceSelection(t){this.selection.replace(t)}wrapSelection(t,e){this.selection.tag(t,e)}insertAtCursor(t){this.selection.isCursor()?this.selection.tag(t,""):this.selection.replace(t)}focus(){this.textarea.focus()}setView(t){this.currentView=t,this.updateView(),this.events.emit("view:change",{mode:t})}getView(){return this.currentView}execAction(t){const e=this.actions[t];e&&(e(),this.events.emit("toolbar:action",{button:t}))}on(t,e){this.events.on(t,e)}off(t,e){this.events.off(t,e)}undo(){const t=this.undoManager.undo();t&&(this.textarea.value=t.value,this.selection.select(t.cursorStart,t.cursorEnd-t.cursorStart),this.events.emit("undo",void 0))}redo(){const t=this.undoManager.redo();t&&(this.textarea.value=t.value,this.selection.select(t.cursorStart,t.cursorEnd-t.cursorStart),this.events.emit("redo",void 0))}openWindow(t){}closeWindow(t){this.dialogManager.close(t)}toggleFullscreen(){this.isFullscreen=!this.isFullscreen,this.container.classList.toggle("te-fullscreen",this.isFullscreen),this.events.emit("fullscreen:toggle",{active:this.isFullscreen})}getTextarea(){return this.textarea}getContainer(){return this.container}getStrings(){return this.strings}getDialogManager(){return this.dialogManager}getFormatter(){return this.formatter}getSelectionManager(){return this.selection}destroy(){var e;if(this.destroyed)return;this.destroyed=!0;for(const i of this.plugins)(e=i.destroy)==null||e.call(i);this.keyboard.detach(),this.dialogManager.closeAll();const t=this.container.parentNode;t&&(t.insertBefore(this.textarea,this.container),t.removeChild(this.container)),delete this.textarea.dataset.texyEditor,this.events.emit("destroy",void 0),this.events.removeAll()}buildDOM(){var n;this.container=document.createElement("div"),this.container.className="te-editor",this.options.width&&(this.container.style.width=this.options.width),this.options.ariaLabel&&this.container.setAttribute("aria-label",this.options.ariaLabel);const t=this.options.toolbar??V,e=this.toolbarBuilder.build(t);this.container.appendChild(e),this.editDiv=document.createElement("div"),this.editDiv.className="te-edit-area",this.container.appendChild(this.editDiv),this.previewDiv=document.createElement("div"),this.previewDiv.className="te-preview-area",this.previewDiv.style.display="none",this.previewContent=document.createElement("div"),this.previewContent.className="te-preview-content",this.previewDiv.appendChild(this.previewContent),this.container.appendChild(this.previewDiv);const i=this.toolbarBuilder.buildBottomBar(this.options.bottomLeftToolbar??["edit","preview","splitView"],this.options.bottomRightEditToolbar??["undo","redo"],this.options.bottomRightPreviewToolbar??[]);this.container.appendChild(i),this.dialogManager=new C(this.container,this.strings),(n=this.textarea.parentNode)==null||n.insertBefore(this.container,this.textarea),this.editDiv.appendChild(this.textarea),this.textarea.classList.add("te-textarea")}applyTheme(){const t=this.options.theme??"light";this.container.classList.add(`te-theme-${t}`),this.container.setAttribute("data-te-theme",t)}updateView(){const t=this.currentView==="edit",e=this.currentView==="preview",i=this.currentView==="split";this.editDiv.style.display=t||i?"":"none",this.previewDiv.style.display=e||i?"":"none",this.container.classList.toggle("te-view-edit",t),this.container.classList.toggle("te-view-preview",e),this.container.classList.toggle("te-view-split",i),this.container.querySelectorAll(".te-bottom-left .te-btn").forEach(n=>{const s=n.dataset.action;n.classList.toggle("te-btn-active",s===this.currentView)}),t||this.renderPreview()}renderPreview(){const t=this.textarea.value;if(!t.trim()){this.previewContent.innerHTML=`<p class="te-preview-empty">${this.strings.previewEmpty}</p>`;return}t!==this.lastPreviewedValue&&(this.lastPreviewedValue=t,this.options.previewPath?(this.previewContent.innerHTML=`<p class="te-preview-loading">${this.strings.previewLoading}</p>`,this.fetchServerPreview(t)):this.options.livePreview&&(this.previewContent.innerHTML=`<div class="te-preview-rendered">${this.parser.parse(t)}</div>`))}async fetchServerPreview(t){try{const i=await(await fetch(this.options.previewPath,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`texy=${encodeURIComponent(t)}&cfg=${encodeURIComponent(this.options.texyCfg??"")}`})).text();this.previewContent.innerHTML=i,this.events.emit("preview:render",{html:i})}catch{this.previewContent.innerHTML='<p class="te-preview-error">Preview loading failed.</p>'}}registerActions(){this.actions={bold:()=>this.formatter.bold(),italic:()=>this.formatter.italic(),deleted:()=>this.formatter.deleted(),inserted:()=>this.formatter.inserted(),superscript:()=>this.formatter.superscript(),subscript:()=>this.formatter.subscript(),code:()=>this.formatter.inlineCode(),codeBlock:()=>this.formatter.codeBlock(),heading1:()=>this.handleHeading(1),heading2:()=>this.handleHeading(2),heading3:()=>this.handleHeading(3),heading4:()=>this.handleHeading(4),link:()=>this.handleLink(),image:()=>this.handleImage(),ul:()=>this.formatter.unorderedList(),ol:()=>this.formatter.orderedList(),blockquote:()=>this.formatter.blockquote(),hr:()=>this.formatter.horizontalRule(),table:()=>this.handleTable(),color:()=>this.handleColor(),symbol:()=>this.handleSymbol(),acronym:()=>this.handleAcronym(),alignLeft:()=>this.formatter.alignLeft(),alignRight:()=>this.formatter.alignRight(),alignCenter:()=>this.formatter.alignCenter(),alignJustify:()=>this.formatter.alignJustify(),indent:()=>this.formatter.indent(),unindent:()=>this.formatter.unindent(),undo:()=>this.undo(),redo:()=>this.redo(),fullscreen:()=>this.toggleFullscreen(),edit:()=>this.setView("edit"),preview:()=>this.setView("preview"),splitView:()=>this.setView("split")}}handleHeading(t){if(this.selection.isCursor()){const e=prompt(this.strings.headingPrompt,"");e&&this.formatter.headingWithPrompt(t,e)}else this.formatter.heading(t)}handleLink(){const t=document.createElement("div");t.className="te-dialog-form";const e=this.createFormField(t,this.strings.linkUrl,"url","https://"),i=this.createFormField(t,this.strings.linkText,"text",this.selection.text());this.dialogManager.open("link",{title:this.strings.link,width:400,content:t,onSubmit:()=>{this.formatter.link(e.value,i.value||void 0),this.focus()}})}handleImage(){const t=document.createElement("div");t.className="te-dialog-form";const e=this.createFormField(t,this.strings.imageUrl,"url",""),i=this.createFormField(t,this.strings.imageAlt,"text",""),n=document.createElement("label");n.className="te-form-label",n.textContent=this.strings.imageAlign,t.appendChild(n);const s=document.createElement("select");s.className="te-form-input";for(const[r,o]of[["*","---"],["<","← "+this.strings.alignLeft],[">",this.strings.alignRight+" →"],["<>","↔ "+this.strings.alignCenter]]){const l=document.createElement("option");l.value=r,l.textContent=o,s.appendChild(l)}t.appendChild(s),this.dialogManager.open("image",{title:this.strings.image,width:420,content:t,onSubmit:()=>{const r=s.value;this.formatter.image(e.value,i.value||void 0,r),this.focus()}})}handleTable(){const t=document.createElement("div");t.className="te-dialog-form";const e=this.createFormField(t,this.strings.tableCols,"number","3"),i=this.createFormField(t,this.strings.tableRows,"number","3");this.dialogManager.open("table",{title:this.strings.table,width:320,content:t,onSubmit:()=>{const n=parseInt(e.value)||3,s=parseInt(i.value)||3;this.formatter.table(n,s,"top"),this.focus()}})}handleColor(){const t=["red","blue","green","orange","purple","brown","navy","teal","gray","black","#e74c3c","#3498db","#2ecc71","#f39c12","#9b59b6","#1abc9c","#e67e22","#95a5a6","#34495e","#d35400"],e=document.createElement("div");e.className="te-color-grid";for(const i of t){const n=document.createElement("button");n.type="button",n.className="te-color-swatch",n.style.backgroundColor=i,n.setAttribute("data-color",i),n.setAttribute("title",i),n.addEventListener("click",()=>{this.formatter.colorModifier(i),this.dialogManager.close("color"),this.focus()}),e.appendChild(n)}this.dialogManager.open("color",{title:this.strings.color,width:300,content:e,onSubmit:()=>{}})}handleSymbol(){const t=["&","@","§","©","®","™","°","±","×","÷","€","£","¥","¢","‰","†","‡","¶","•","…","←","→","↑","↓","↔","⇒","⇐","⇔","≈","≠","≤","≥","∞","∑","∏","∫","√","∂","∆","∇","α","β","γ","δ","ε","π","σ","τ","φ","ω","♠","♣","♥","♦","★","☆","✓","✗","♪","♫"],e=document.createElement("div");e.className="te-symbol-grid";for(const i of t){const n=document.createElement("button");n.type="button",n.className="te-symbol-btn",n.textContent=i,n.setAttribute("title",i),n.addEventListener("click",()=>{this.formatter.insertSymbol(i),this.dialogManager.close("symbol"),this.focus()}),e.appendChild(n)}this.dialogManager.open("symbol",{title:this.strings.symbol,width:400,content:e,onSubmit:()=>{}})}handleAcronym(){const t=prompt(this.strings.acronymTitle,"");t&&this.formatter.acronym(t)}setupKeyboard(){this.keyboard.register("bold",()=>this.execAction("bold")),this.keyboard.register("italic",()=>this.execAction("italic")),this.keyboard.register("link",()=>this.execAction("link")),this.keyboard.register("undo",()=>this.undo()),this.keyboard.register("redo",()=>this.redo()),this.keyboard.register("fullscreen",()=>this.toggleFullscreen()),this.keyboard.register("indent",()=>this.formatter.indent()),this.keyboard.register("unindent",()=>this.formatter.unindent()),this.keyboard.attach()}setupUndoTracking(){let t=null;this.textarea.addEventListener("input",()=>{t&&clearTimeout(t),t=setTimeout(()=>{this.undoManager.push({value:this.textarea.value,cursorStart:this.textarea.selectionStart,cursorEnd:this.textarea.selectionEnd})},300),this.events.emit("change",{value:this.textarea.value}),this.currentView!=="edit"&&this.options.livePreview&&(this.previewDebounceTimer&&clearTimeout(this.previewDebounceTimer),this.previewDebounceTimer=setTimeout(()=>this.renderPreview(),this.options.livePreviewDelay??400))})}setupAutoResize(){const t=()=>{this.textarea.style.height="auto",this.textarea.style.height=this.textarea.scrollHeight+"px"};this.textarea.addEventListener("input",t),requestAnimationFrame(t)}loadPlugin(t){t.init(this),this.plugins.push(t),this.events.emit("plugin:init",{name:t.name})}createFormField(t,e,i,n){const s=document.createElement("div");s.className="te-form-group";const r=document.createElement("label");r.className="te-form-label",r.textContent=e,s.appendChild(r);const o=document.createElement("input");return o.type=i,o.className="te-form-input",o.value=n,s.appendChild(o),t.appendChild(s),o}}exports.DialogManager=C;exports.EventBus=k;exports.KeyboardManager=w;exports.Selection=f;exports.TexyEditor=U;exports.TexyFormatter=b;exports.TexyParser=M;exports.ToolbarBuilder=y;exports.UndoManager=v;exports.bbcodePlugin=D;exports.cs=$;exports.en=x;exports.getStrings=L;exports.imageEmbedPlugin=N;exports.linkRedirectPlugin=P;exports.registerLanguage=R;exports.smileyPlugin=I;exports.youtubePlugin=T;
|
|
42
|
+
//# sourceMappingURL=texy-editor.cjs.map
|