@licium/editor-plugin-text-align-simpel 3.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/dist/toastui-editor-plugin-text-align-simpel.css +38 -0
- package/dist/toastui-editor-plugin-text-align-simpel.js +393 -0
- package/dist/toastui-editor-plugin-text-align.css +38 -0
- package/dist/toastui-editor-plugin-text-align.js +406 -0
- package/package.json +53 -0
- package/types/index.d.ts +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 NHN Cloud Corp.
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 3.1.0 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
.toastui-editor-toolbar-icons.alignLeft,
|
|
8
|
+
.toastui-editor-toolbar-icons.alignCenter,
|
|
9
|
+
.toastui-editor-toolbar-icons.alignRight {
|
|
10
|
+
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDk2IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzMzMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj4KICA8bGluZSB4MT0iOCIgeTE9IjYiIHgyPSIyNCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxMCIgeDI9IjIwIiB5Mj0iMTAiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxNCIgeDI9IjI0IiB5Mj0iMTQiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxOCIgeDI9IjIwIiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI0MCIgeTE9IjYiIHgyPSI1NiIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjQyIiB5MT0iMTAiIHgyPSI1NCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI0MCIgeTE9IjE0IiB4Mj0iNTYiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNDIiIHkxPSIxOCIgeDI9IjU0IiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI3MiIgeTE9IjYiIHgyPSI4OCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9Ijc2IiB5MT0iMTAiIHgyPSI4OCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI3MiIgeTE9IjE0IiB4Mj0iODgiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNzYiIHkxPSIxOCIgeDI9Ijg4IiB5Mj0iMTgiIC8+Cjwvc3ZnPg==);
|
|
11
|
+
background-size: 96px 24px;
|
|
12
|
+
background-repeat: no-repeat;
|
|
13
|
+
text-indent: -9999px;
|
|
14
|
+
/* Hide text fallback */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.toastui-editor-toolbar-icons.alignLeft {
|
|
18
|
+
background-position: 0 4px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.toastui-editor-toolbar-icons.alignCenter {
|
|
22
|
+
background-position: -32px 4px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.toastui-editor-toolbar-icons.alignRight {
|
|
26
|
+
background-position: -64px 4px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.toastui-editor-defaultUI-toolbar button.active {
|
|
30
|
+
background-color: #fca0704d;
|
|
31
|
+
color: #333;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignLeft,
|
|
35
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignCenter,
|
|
36
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignRight {
|
|
37
|
+
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDk2IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNlZWUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj4KICA8bGluZSB4MT0iOCIgeTE9IjYiIHgyPSIyNCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxMCIgeDI9IjIwIiB5Mj0iMTAiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxNCIgeDI9IjI0IiB5Mj0iMTQiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxOCIgeDI9IjIwIiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI0MCIgeTE9IjYiIHgyPSI1NiIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjQyIiB5MT0iMTAiIHgyPSI1NCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI0MCIgeTE9IjE0IiB4Mj0iNTYiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNDIiIHkxPSIxOCIgeDI9IjU0IiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI3MiIgeTE9IjYiIHgyPSI4OCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9Ijc2IiB5MT0iMTAiIHgyPSI4OCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI3MiIgeTE9IjE0IiB4Mj0iODgiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNzYiIHkxPSIxOCIgeDI9Ijg4IiB5Mj0iMTgiIC8+Cjwvc3ZnPg==);
|
|
38
|
+
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 3.1.0 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8
|
+
if(typeof exports === 'object' && typeof module === 'object')
|
|
9
|
+
module.exports = factory();
|
|
10
|
+
else if(typeof define === 'function' && define.amd)
|
|
11
|
+
define([], factory);
|
|
12
|
+
else if(typeof exports === 'object')
|
|
13
|
+
exports["toastui"] = factory();
|
|
14
|
+
else
|
|
15
|
+
root["toastui"] = root["toastui"] || {}, root["toastui"]["Editor"] = root["toastui"]["Editor"] || {}, root["toastui"]["Editor"]["plugin"] = root["toastui"]["Editor"]["plugin"] || {}, root["toastui"]["Editor"]["plugin"]["textAlignSimpel"] = factory();
|
|
16
|
+
})(self, function() {
|
|
17
|
+
return /******/ (function() { // webpackBootstrap
|
|
18
|
+
/******/ "use strict";
|
|
19
|
+
/******/ // The require scope
|
|
20
|
+
/******/ var __webpack_require__ = {};
|
|
21
|
+
/******/
|
|
22
|
+
/************************************************************************/
|
|
23
|
+
/******/ /* webpack/runtime/define property getters */
|
|
24
|
+
/******/ !function() {
|
|
25
|
+
/******/ // define getter functions for harmony exports
|
|
26
|
+
/******/ __webpack_require__.d = function(exports, definition) {
|
|
27
|
+
/******/ for(var key in definition) {
|
|
28
|
+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
29
|
+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
30
|
+
/******/ }
|
|
31
|
+
/******/ }
|
|
32
|
+
/******/ };
|
|
33
|
+
/******/ }();
|
|
34
|
+
/******/
|
|
35
|
+
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
36
|
+
/******/ !function() {
|
|
37
|
+
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
|
38
|
+
/******/ }();
|
|
39
|
+
/******/
|
|
40
|
+
/************************************************************************/
|
|
41
|
+
var __webpack_exports__ = {};
|
|
42
|
+
|
|
43
|
+
// EXPORTS
|
|
44
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
45
|
+
"default": function() { return /* binding */ textAlignPlugin; }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
;// CONCATENATED MODULE: ./src/i18n/langs.ts
|
|
49
|
+
function addLangs(i18n) {
|
|
50
|
+
i18n.setLanguage(['en', 'en-US'], {
|
|
51
|
+
alignLeft: 'Align left',
|
|
52
|
+
alignCenter: 'Align center',
|
|
53
|
+
alignRight: 'Align right',
|
|
54
|
+
});
|
|
55
|
+
i18n.setLanguage(['ar', 'ar-AR'], {
|
|
56
|
+
alignLeft: 'محاذاة لليسار',
|
|
57
|
+
alignCenter: 'محاذاة للوسط',
|
|
58
|
+
alignRight: 'محاذاة لليمين',
|
|
59
|
+
});
|
|
60
|
+
i18n.setLanguage(['cs', 'cs-CZ'], {
|
|
61
|
+
alignLeft: 'Zarovnat vlevo',
|
|
62
|
+
alignCenter: 'Zarovnat na střed',
|
|
63
|
+
alignRight: 'Zarovnat vpravo',
|
|
64
|
+
});
|
|
65
|
+
i18n.setLanguage(['de', 'de-DE'], {
|
|
66
|
+
alignLeft: 'Linksbündig',
|
|
67
|
+
alignCenter: 'Zentriert',
|
|
68
|
+
alignRight: 'Rechtsbündig',
|
|
69
|
+
});
|
|
70
|
+
i18n.setLanguage(['es', 'es-ES'], {
|
|
71
|
+
alignLeft: 'Alinear a la izquierda',
|
|
72
|
+
alignCenter: 'Alinear al centro',
|
|
73
|
+
alignRight: 'Alinear a la derecha',
|
|
74
|
+
});
|
|
75
|
+
i18n.setLanguage(['fi', 'fi-FI'], {
|
|
76
|
+
alignLeft: 'Tasaa vasemmalle',
|
|
77
|
+
alignCenter: 'Keskitä',
|
|
78
|
+
alignRight: 'Tasaa oikealle',
|
|
79
|
+
});
|
|
80
|
+
i18n.setLanguage(['fr', 'fr-FR'], {
|
|
81
|
+
alignLeft: 'Aligner à gauche',
|
|
82
|
+
alignCenter: 'Aligner au centre',
|
|
83
|
+
alignRight: 'Aligner à droite',
|
|
84
|
+
});
|
|
85
|
+
i18n.setLanguage(['gl', 'gl-ES'], {
|
|
86
|
+
alignLeft: 'Aliñar á esquerda',
|
|
87
|
+
alignCenter: 'Aliñar ao centro',
|
|
88
|
+
alignRight: 'Aliñar á dereita',
|
|
89
|
+
});
|
|
90
|
+
i18n.setLanguage(['hr', 'hr-HR'], {
|
|
91
|
+
alignLeft: 'Poravnaj lijevo',
|
|
92
|
+
alignCenter: 'Poravnaj središnje',
|
|
93
|
+
alignRight: 'Poravnaj desno',
|
|
94
|
+
});
|
|
95
|
+
i18n.setLanguage(['it', 'it-IT'], {
|
|
96
|
+
alignLeft: 'Allinea a sinistra',
|
|
97
|
+
alignCenter: 'Allinea al centro',
|
|
98
|
+
alignRight: 'Allinea a destra',
|
|
99
|
+
});
|
|
100
|
+
i18n.setLanguage(['ja', 'ja-JP'], {
|
|
101
|
+
alignLeft: '左揃え',
|
|
102
|
+
alignCenter: '中央揃え',
|
|
103
|
+
alignRight: '右揃え',
|
|
104
|
+
});
|
|
105
|
+
i18n.setLanguage(['ko', 'ko-KR'], {
|
|
106
|
+
alignLeft: '왼쪽 정렬',
|
|
107
|
+
alignCenter: '가운데 정렬',
|
|
108
|
+
alignRight: '오른쪽 정렬',
|
|
109
|
+
});
|
|
110
|
+
i18n.setLanguage(['nb', 'nb-NO'], {
|
|
111
|
+
alignLeft: 'Venstrejuster',
|
|
112
|
+
alignCenter: 'Midtstill',
|
|
113
|
+
alignRight: 'Høyrejuster',
|
|
114
|
+
});
|
|
115
|
+
i18n.setLanguage(['nl', 'nl-NL'], {
|
|
116
|
+
alignLeft: 'Links uitlijnen',
|
|
117
|
+
alignCenter: 'Centreren',
|
|
118
|
+
alignRight: 'Rechts uitlijnen',
|
|
119
|
+
});
|
|
120
|
+
i18n.setLanguage(['pl', 'pl-PL'], {
|
|
121
|
+
alignLeft: 'Wyrównaj do lewej',
|
|
122
|
+
alignCenter: 'Wyśrodkuj',
|
|
123
|
+
alignRight: 'Wyrównaj do prawej',
|
|
124
|
+
});
|
|
125
|
+
i18n.setLanguage(['pt', 'pt-BR'], {
|
|
126
|
+
alignLeft: 'Alinhar à esquerda',
|
|
127
|
+
alignCenter: 'Alinhar ao centro',
|
|
128
|
+
alignRight: 'Alinhar à direita',
|
|
129
|
+
});
|
|
130
|
+
i18n.setLanguage(['ru', 'ru-RU'], {
|
|
131
|
+
alignLeft: 'По левому краю',
|
|
132
|
+
alignCenter: 'По центру',
|
|
133
|
+
alignRight: 'По правому краю',
|
|
134
|
+
});
|
|
135
|
+
i18n.setLanguage(['sv', 'sv-SE'], {
|
|
136
|
+
alignLeft: 'Vänsterjustera',
|
|
137
|
+
alignCenter: 'Centrera',
|
|
138
|
+
alignRight: 'Högerjustera',
|
|
139
|
+
});
|
|
140
|
+
i18n.setLanguage(['tr', 'tr-TR'], {
|
|
141
|
+
alignLeft: 'Sola hizala',
|
|
142
|
+
alignCenter: 'Ortala',
|
|
143
|
+
alignRight: 'Sağa hizala',
|
|
144
|
+
});
|
|
145
|
+
i18n.setLanguage(['uk', 'uk-UA'], {
|
|
146
|
+
alignLeft: 'По лівому краю',
|
|
147
|
+
alignCenter: 'По центру',
|
|
148
|
+
alignRight: 'По правому краю',
|
|
149
|
+
});
|
|
150
|
+
i18n.setLanguage(['zh', 'zh-CN'], {
|
|
151
|
+
alignLeft: '左对齐',
|
|
152
|
+
alignCenter: '居中对齐',
|
|
153
|
+
alignRight: '右对齐',
|
|
154
|
+
});
|
|
155
|
+
i18n.setLanguage(['zh-TW'], {
|
|
156
|
+
alignLeft: '靠左對齊',
|
|
157
|
+
alignCenter: '置中對齊',
|
|
158
|
+
alignRight: '靠右對齊',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
;// CONCATENATED MODULE: ./src/index.ts
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
var PREFIX = 'toastui-editor-';
|
|
166
|
+
function createToolbarItemOption(text, commandName, i18n) {
|
|
167
|
+
return {
|
|
168
|
+
name: commandName,
|
|
169
|
+
command: commandName,
|
|
170
|
+
tooltip: i18n.get(commandName),
|
|
171
|
+
text: text,
|
|
172
|
+
className: PREFIX + "toolbar-icons " + commandName,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function textAlignPlugin(context, options) {
|
|
176
|
+
if (options === void 0) { options = {}; }
|
|
177
|
+
var i18n = context.i18n, eventEmitter = context.eventEmitter, _a = context.usageStatistics, usageStatistics = _a === void 0 ? true : _a;
|
|
178
|
+
addLangs(i18n);
|
|
179
|
+
// Active state listener
|
|
180
|
+
eventEmitter.listen('caretChange', function () {
|
|
181
|
+
updateToolbarState();
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
markdownCommands: {
|
|
185
|
+
alignLeft: function (payload, _a, dispatch) {
|
|
186
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
187
|
+
return execMarkdownAlign('left', selection, schema, tr, dispatch);
|
|
188
|
+
},
|
|
189
|
+
alignCenter: function (payload, _a, dispatch) {
|
|
190
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
191
|
+
return execMarkdownAlign('center', selection, schema, tr, dispatch);
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
wysiwygCommands: {
|
|
195
|
+
alignLeft: function (payload, _a, dispatch) {
|
|
196
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
197
|
+
return execWysiwygAlign('left', selection, schema, tr, dispatch);
|
|
198
|
+
},
|
|
199
|
+
alignCenter: function (payload, _a, dispatch) {
|
|
200
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
201
|
+
return execWysiwygAlign('center', selection, schema, tr, dispatch);
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
toolbarItems: [
|
|
205
|
+
{
|
|
206
|
+
groupIndex: 1,
|
|
207
|
+
itemIndex: 2,
|
|
208
|
+
item: createToolbarItemOption('', 'alignLeft', i18n),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
groupIndex: 1,
|
|
212
|
+
itemIndex: 3,
|
|
213
|
+
item: createToolbarItemOption('', 'alignCenter', i18n),
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
toHTMLRenderers: {
|
|
217
|
+
htmlInline: {
|
|
218
|
+
span: function (node, _a) {
|
|
219
|
+
var entering = _a.entering, origin = _a.origin;
|
|
220
|
+
var style = node.attrs ? node.attrs.style : null;
|
|
221
|
+
if (style && style.indexOf('text-align') > -1) {
|
|
222
|
+
return entering
|
|
223
|
+
? { type: 'openTag', tagName: 'span', attributes: { style: style } }
|
|
224
|
+
: { type: 'closeTag', tagName: 'span' };
|
|
225
|
+
}
|
|
226
|
+
if (origin) {
|
|
227
|
+
return origin();
|
|
228
|
+
}
|
|
229
|
+
return { type: 'html', content: node.literal || '' };
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function updateToolbarState() {
|
|
236
|
+
// 1. Reset all buttons
|
|
237
|
+
var buttons = document.querySelectorAll('.toastui-editor-toolbar-icons.alignLeft, .toastui-editor-toolbar-icons.alignCenter, .toastui-editor-toolbar-icons.alignRight');
|
|
238
|
+
buttons.forEach(function (btn) { return btn.classList.remove('active'); });
|
|
239
|
+
// 2. Determine active state
|
|
240
|
+
// Getting state from plugin context is hard.
|
|
241
|
+
// For Markdown: Parse current line of cursor?
|
|
242
|
+
// For WYSIWYG: Parse selection marks?
|
|
243
|
+
// Naive checker for demo quality:
|
|
244
|
+
var selection = window.getSelection();
|
|
245
|
+
if (!selection || selection.rangeCount === 0)
|
|
246
|
+
return;
|
|
247
|
+
var range = selection.getRangeAt(0);
|
|
248
|
+
var container = range.commonAncestorContainer;
|
|
249
|
+
if (container.nodeType === 3)
|
|
250
|
+
container = container.parentElement; // Text node -> Element
|
|
251
|
+
var el = container;
|
|
252
|
+
// Check for span with style
|
|
253
|
+
var activeAlign = null;
|
|
254
|
+
var current = el;
|
|
255
|
+
// Walk up a few levels to find span
|
|
256
|
+
while (current &&
|
|
257
|
+
current.classList &&
|
|
258
|
+
!current.classList.contains('ProseMirror') &&
|
|
259
|
+
!current.classList.contains('toastui-editor-contents')) {
|
|
260
|
+
if (current.tagName === 'SPAN' && current.style.textAlign) {
|
|
261
|
+
activeAlign = current.style.textAlign;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
current = current.parentElement;
|
|
265
|
+
}
|
|
266
|
+
if (!activeAlign) {
|
|
267
|
+
// Check inner text if in Markdown mode (Textarea)
|
|
268
|
+
// This is very hard because DOM is just text.
|
|
269
|
+
// We skip Markdown active state highlight for this iteration,
|
|
270
|
+
// focusing on WYSIWYG visual feedback.
|
|
271
|
+
}
|
|
272
|
+
if (activeAlign) {
|
|
273
|
+
var activeBtn = document.querySelector(".toastui-editor-toolbar-icons.align" + capitalize(activeAlign));
|
|
274
|
+
if (activeBtn)
|
|
275
|
+
activeBtn.classList.add('active');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function capitalize(s) {
|
|
279
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
280
|
+
}
|
|
281
|
+
function execMarkdownAlign(alignType, selection, schema, tr, dispatch) {
|
|
282
|
+
var doc = tr.doc;
|
|
283
|
+
var from = selection.from, to = selection.to;
|
|
284
|
+
// Always expand to full line(s) to avoid nesting inside words
|
|
285
|
+
var $from = doc.resolve(from);
|
|
286
|
+
var $to = doc.resolve(to);
|
|
287
|
+
// In Markdown mode (CodeMirror-like), we usually want to operate on lines.
|
|
288
|
+
// We can use doc.resolve(from).blockRange() -> this gives the text block (paragraph).
|
|
289
|
+
// This is safer than char-level selection for block alignment.
|
|
290
|
+
var fromLine = $from.pos - $from.parentOffset; // Start of line
|
|
291
|
+
var toLine = $to.pos + ($to.parent.content.size - $to.parentOffset); // End of line
|
|
292
|
+
// Wait, doc.resolve in Markdown mode... TUI's internal doc structure for Markdown is just a series of blocks?
|
|
293
|
+
// Let's rely on blockRange() which TUI implementation respects.
|
|
294
|
+
var blockRange = $from.blockRange($to);
|
|
295
|
+
var targetFrom = from;
|
|
296
|
+
var targetTo = to;
|
|
297
|
+
if (blockRange) {
|
|
298
|
+
targetFrom = blockRange.start + 1; // +1 to skip start token? No, text nodes.
|
|
299
|
+
targetTo = blockRange.end - 1;
|
|
300
|
+
// Actually, let's look at the Slice content.
|
|
301
|
+
// If we use blockRange, we get the whole "Paragraph" structure.
|
|
302
|
+
}
|
|
303
|
+
// Fallback: If no blockRange (rare), use raw selection.
|
|
304
|
+
// But to fix the "nesting" issue, we MUST select the whole line content including any existing HTML tags.
|
|
305
|
+
// In TUI Markdown, each line is likely a textblock.
|
|
306
|
+
// Let's try to grab the whole block content.
|
|
307
|
+
var resolvedFrom = doc.resolve(from);
|
|
308
|
+
var startPos = resolvedFrom.start();
|
|
309
|
+
var endPos = resolvedFrom.end();
|
|
310
|
+
targetFrom = startPos;
|
|
311
|
+
targetTo = endPos;
|
|
312
|
+
var slice = doc.slice(targetFrom, targetTo);
|
|
313
|
+
var textContent = slice.content.textBetween(0, slice.content.size, '\n');
|
|
314
|
+
// Looser regex to match existing tags
|
|
315
|
+
// Matches: <span ...> ... </span>
|
|
316
|
+
var regex = /^\s*<span\s+[^>]*style="[^"]*text-align:\s*(left|center|right)[^"]*"[^>]*>([\s\S]*?)<\/span>\s*$/i;
|
|
317
|
+
var match = textContent.match(regex);
|
|
318
|
+
var newText = textContent;
|
|
319
|
+
var currentAlign = null;
|
|
320
|
+
if (match) {
|
|
321
|
+
currentAlign = match[1].toLowerCase();
|
|
322
|
+
newText = match[2]; // Inner content
|
|
323
|
+
}
|
|
324
|
+
var finalWrapped = newText;
|
|
325
|
+
if (currentAlign === alignType) {
|
|
326
|
+
// Toggle off: Just return the inner text (unwrap)
|
|
327
|
+
// newText is already stripped of the span
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
// Apply new alignment
|
|
331
|
+
var style = "display: block; text-align: " + alignType;
|
|
332
|
+
finalWrapped = "<span style=\"" + style + "\">" + newText + "</span>";
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
tr.replaceWith(targetFrom, targetTo, schema.text(finalWrapped));
|
|
336
|
+
dispatch(tr);
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function execWysiwygAlign(alignType, selection, schema, tr, dispatch) {
|
|
344
|
+
var empty = selection.empty;
|
|
345
|
+
var styleBase = 'display: block; text-align: ';
|
|
346
|
+
var targetFrom = selection.from;
|
|
347
|
+
var targetTo = selection.to;
|
|
348
|
+
var markType = schema.marks.span;
|
|
349
|
+
if (!markType)
|
|
350
|
+
return false;
|
|
351
|
+
if (empty) {
|
|
352
|
+
var $from = selection.$from;
|
|
353
|
+
var blockRange = $from.blockRange();
|
|
354
|
+
if (blockRange) {
|
|
355
|
+
targetFrom = blockRange.start;
|
|
356
|
+
targetTo = blockRange.end;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
var existingMark = null;
|
|
360
|
+
var existingAlign = null;
|
|
361
|
+
tr.doc.nodesBetween(targetFrom, targetTo, function (node) {
|
|
362
|
+
if (existingMark)
|
|
363
|
+
return false;
|
|
364
|
+
node.marks.forEach(function (mark) {
|
|
365
|
+
if (mark.type === markType && mark.attrs.style && mark.attrs.style.indexOf(styleBase) > -1) {
|
|
366
|
+
existingMark = mark;
|
|
367
|
+
var match = mark.attrs.style.match(/text-align: (left|center|right)/);
|
|
368
|
+
if (match)
|
|
369
|
+
existingAlign = match[1];
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
return true;
|
|
373
|
+
});
|
|
374
|
+
if (existingMark) {
|
|
375
|
+
tr.removeMark(targetFrom, targetTo, existingMark);
|
|
376
|
+
}
|
|
377
|
+
if (existingAlign === alignType) {
|
|
378
|
+
dispatch(tr);
|
|
379
|
+
return true;
|
|
380
|
+
}
|
|
381
|
+
var style = "" + styleBase + alignType;
|
|
382
|
+
var attrs = { htmlAttrs: { style: style } };
|
|
383
|
+
var mark = markType.create(attrs);
|
|
384
|
+
tr.addMark(targetFrom, targetTo, mark);
|
|
385
|
+
dispatch(tr);
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
__webpack_exports__ = __webpack_exports__["default"];
|
|
390
|
+
/******/ return __webpack_exports__;
|
|
391
|
+
/******/ })()
|
|
392
|
+
;
|
|
393
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 3.2.9 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
.toastui-editor-toolbar-icons.alignLeft,
|
|
8
|
+
.toastui-editor-toolbar-icons.alignCenter,
|
|
9
|
+
.toastui-editor-toolbar-icons.alignRight {
|
|
10
|
+
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDk2IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzMzMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj4KICA8bGluZSB4MT0iOCIgeTE9IjYiIHgyPSIyNCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxMCIgeDI9IjIwIiB5Mj0iMTAiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxNCIgeDI9IjI0IiB5Mj0iMTQiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxOCIgeDI9IjIwIiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI0MCIgeTE9IjYiIHgyPSI1NiIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjQyIiB5MT0iMTAiIHgyPSI1NCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI0MCIgeTE9IjE0IiB4Mj0iNTYiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNDIiIHkxPSIxOCIgeDI9IjU0IiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI3MiIgeTE9IjYiIHgyPSI4OCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9Ijc2IiB5MT0iMTAiIHgyPSI4OCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI3MiIgeTE9IjE0IiB4Mj0iODgiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNzYiIHkxPSIxOCIgeDI9Ijg4IiB5Mj0iMTgiIC8+Cjwvc3ZnPg==);
|
|
11
|
+
background-size: 96px 24px;
|
|
12
|
+
background-repeat: no-repeat;
|
|
13
|
+
text-indent: -9999px;
|
|
14
|
+
/* Hide text fallback */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.toastui-editor-toolbar-icons.alignLeft {
|
|
18
|
+
background-position: 0 4px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.toastui-editor-toolbar-icons.alignCenter {
|
|
22
|
+
background-position: -32px 4px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.toastui-editor-toolbar-icons.alignRight {
|
|
26
|
+
background-position: -64px 4px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.toastui-editor-defaultUI-toolbar button.active {
|
|
30
|
+
background-color: #fca0704d;
|
|
31
|
+
color: #333;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignLeft,
|
|
35
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignCenter,
|
|
36
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.alignRight {
|
|
37
|
+
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDk2IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNlZWUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj4KICA8bGluZSB4MT0iOCIgeTE9IjYiIHgyPSIyNCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxMCIgeDI9IjIwIiB5Mj0iMTAiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxNCIgeDI9IjI0IiB5Mj0iMTQiIC8+CiAgPGxpbmUgeDE9IjgiIHkxPSIxOCIgeDI9IjIwIiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI0MCIgeTE9IjYiIHgyPSI1NiIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9IjQyIiB5MT0iMTAiIHgyPSI1NCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI0MCIgeTE9IjE0IiB4Mj0iNTYiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNDIiIHkxPSIxOCIgeDI9IjU0IiB5Mj0iMTgiIC8+CgogIDxsaW5lIHgxPSI3MiIgeTE9IjYiIHgyPSI4OCIgeTI9IjYiIC8+CiAgPGxpbmUgeDE9Ijc2IiB5MT0iMTAiIHgyPSI4OCIgeTI9IjEwIiAvPgogIDxsaW5lIHgxPSI3MiIgeTE9IjE0IiB4Mj0iODgiIHkyPSIxNCIgLz4KICA8bGluZSB4MT0iNzYiIHkxPSIxOCIgeDI9Ijg4IiB5Mj0iMTgiIC8+Cjwvc3ZnPg==);
|
|
38
|
+
}
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 3.2.9 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8
|
+
if(typeof exports === 'object' && typeof module === 'object')
|
|
9
|
+
module.exports = factory();
|
|
10
|
+
else if(typeof define === 'function' && define.amd)
|
|
11
|
+
define([], factory);
|
|
12
|
+
else if(typeof exports === 'object')
|
|
13
|
+
exports["toastui"] = factory();
|
|
14
|
+
else
|
|
15
|
+
root["toastui"] = root["toastui"] || {}, root["toastui"]["Editor"] = root["toastui"]["Editor"] || {}, root["toastui"]["Editor"]["plugin"] = root["toastui"]["Editor"]["plugin"] || {}, root["toastui"]["Editor"]["plugin"]["textAlign"] = factory();
|
|
16
|
+
})(self, function() {
|
|
17
|
+
return /******/ (function() { // webpackBootstrap
|
|
18
|
+
/******/ "use strict";
|
|
19
|
+
/******/ // The require scope
|
|
20
|
+
/******/ var __webpack_require__ = {};
|
|
21
|
+
/******/
|
|
22
|
+
/************************************************************************/
|
|
23
|
+
/******/ /* webpack/runtime/define property getters */
|
|
24
|
+
/******/ !function() {
|
|
25
|
+
/******/ // define getter functions for harmony exports
|
|
26
|
+
/******/ __webpack_require__.d = function(exports, definition) {
|
|
27
|
+
/******/ for(var key in definition) {
|
|
28
|
+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
29
|
+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
30
|
+
/******/ }
|
|
31
|
+
/******/ }
|
|
32
|
+
/******/ };
|
|
33
|
+
/******/ }();
|
|
34
|
+
/******/
|
|
35
|
+
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
36
|
+
/******/ !function() {
|
|
37
|
+
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
|
38
|
+
/******/ }();
|
|
39
|
+
/******/
|
|
40
|
+
/************************************************************************/
|
|
41
|
+
var __webpack_exports__ = {};
|
|
42
|
+
|
|
43
|
+
// EXPORTS
|
|
44
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
45
|
+
"default": function() { return /* binding */ textAlignPlugin; }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
;// CONCATENATED MODULE: ./src/i18n/langs.ts
|
|
49
|
+
function addLangs(i18n) {
|
|
50
|
+
i18n.setLanguage(['en', 'en-US'], {
|
|
51
|
+
alignLeft: 'Align left',
|
|
52
|
+
alignCenter: 'Align center',
|
|
53
|
+
alignRight: 'Align right',
|
|
54
|
+
});
|
|
55
|
+
i18n.setLanguage(['ar', 'ar-AR'], {
|
|
56
|
+
alignLeft: 'محاذاة لليسار',
|
|
57
|
+
alignCenter: 'محاذاة للوسط',
|
|
58
|
+
alignRight: 'محاذاة لليمين',
|
|
59
|
+
});
|
|
60
|
+
i18n.setLanguage(['cs', 'cs-CZ'], {
|
|
61
|
+
alignLeft: 'Zarovnat vlevo',
|
|
62
|
+
alignCenter: 'Zarovnat na střed',
|
|
63
|
+
alignRight: 'Zarovnat vpravo',
|
|
64
|
+
});
|
|
65
|
+
i18n.setLanguage(['de', 'de-DE'], {
|
|
66
|
+
alignLeft: 'Linksbündig',
|
|
67
|
+
alignCenter: 'Zentriert',
|
|
68
|
+
alignRight: 'Rechtsbündig',
|
|
69
|
+
});
|
|
70
|
+
i18n.setLanguage(['es', 'es-ES'], {
|
|
71
|
+
alignLeft: 'Alinear a la izquierda',
|
|
72
|
+
alignCenter: 'Alinear al centro',
|
|
73
|
+
alignRight: 'Alinear a la derecha',
|
|
74
|
+
});
|
|
75
|
+
i18n.setLanguage(['fi', 'fi-FI'], {
|
|
76
|
+
alignLeft: 'Tasaa vasemmalle',
|
|
77
|
+
alignCenter: 'Keskitä',
|
|
78
|
+
alignRight: 'Tasaa oikealle',
|
|
79
|
+
});
|
|
80
|
+
i18n.setLanguage(['fr', 'fr-FR'], {
|
|
81
|
+
alignLeft: 'Aligner à gauche',
|
|
82
|
+
alignCenter: 'Aligner au centre',
|
|
83
|
+
alignRight: 'Aligner à droite',
|
|
84
|
+
});
|
|
85
|
+
i18n.setLanguage(['gl', 'gl-ES'], {
|
|
86
|
+
alignLeft: 'Aliñar á esquerda',
|
|
87
|
+
alignCenter: 'Aliñar ao centro',
|
|
88
|
+
alignRight: 'Aliñar á dereita',
|
|
89
|
+
});
|
|
90
|
+
i18n.setLanguage(['hr', 'hr-HR'], {
|
|
91
|
+
alignLeft: 'Poravnaj lijevo',
|
|
92
|
+
alignCenter: 'Poravnaj središnje',
|
|
93
|
+
alignRight: 'Poravnaj desno',
|
|
94
|
+
});
|
|
95
|
+
i18n.setLanguage(['it', 'it-IT'], {
|
|
96
|
+
alignLeft: 'Allinea a sinistra',
|
|
97
|
+
alignCenter: 'Allinea al centro',
|
|
98
|
+
alignRight: 'Allinea a destra',
|
|
99
|
+
});
|
|
100
|
+
i18n.setLanguage(['ja', 'ja-JP'], {
|
|
101
|
+
alignLeft: '左揃え',
|
|
102
|
+
alignCenter: '中央揃え',
|
|
103
|
+
alignRight: '右揃え',
|
|
104
|
+
});
|
|
105
|
+
i18n.setLanguage(['ko', 'ko-KR'], {
|
|
106
|
+
alignLeft: '왼쪽 정렬',
|
|
107
|
+
alignCenter: '가운데 정렬',
|
|
108
|
+
alignRight: '오른쪽 정렬',
|
|
109
|
+
});
|
|
110
|
+
i18n.setLanguage(['nb', 'nb-NO'], {
|
|
111
|
+
alignLeft: 'Venstrejuster',
|
|
112
|
+
alignCenter: 'Midtstill',
|
|
113
|
+
alignRight: 'Høyrejuster',
|
|
114
|
+
});
|
|
115
|
+
i18n.setLanguage(['nl', 'nl-NL'], {
|
|
116
|
+
alignLeft: 'Links uitlijnen',
|
|
117
|
+
alignCenter: 'Centreren',
|
|
118
|
+
alignRight: 'Rechts uitlijnen',
|
|
119
|
+
});
|
|
120
|
+
i18n.setLanguage(['pl', 'pl-PL'], {
|
|
121
|
+
alignLeft: 'Wyrównaj do lewej',
|
|
122
|
+
alignCenter: 'Wyśrodkuj',
|
|
123
|
+
alignRight: 'Wyrównaj do prawej',
|
|
124
|
+
});
|
|
125
|
+
i18n.setLanguage(['pt', 'pt-BR'], {
|
|
126
|
+
alignLeft: 'Alinhar à esquerda',
|
|
127
|
+
alignCenter: 'Alinhar ao centro',
|
|
128
|
+
alignRight: 'Alinhar à direita',
|
|
129
|
+
});
|
|
130
|
+
i18n.setLanguage(['ru', 'ru-RU'], {
|
|
131
|
+
alignLeft: 'По левому краю',
|
|
132
|
+
alignCenter: 'По центру',
|
|
133
|
+
alignRight: 'По правому краю',
|
|
134
|
+
});
|
|
135
|
+
i18n.setLanguage(['sv', 'sv-SE'], {
|
|
136
|
+
alignLeft: 'Vänsterjustera',
|
|
137
|
+
alignCenter: 'Centrera',
|
|
138
|
+
alignRight: 'Högerjustera',
|
|
139
|
+
});
|
|
140
|
+
i18n.setLanguage(['tr', 'tr-TR'], {
|
|
141
|
+
alignLeft: 'Sola hizala',
|
|
142
|
+
alignCenter: 'Ortala',
|
|
143
|
+
alignRight: 'Sağa hizala',
|
|
144
|
+
});
|
|
145
|
+
i18n.setLanguage(['uk', 'uk-UA'], {
|
|
146
|
+
alignLeft: 'По лівому краю',
|
|
147
|
+
alignCenter: 'По центру',
|
|
148
|
+
alignRight: 'По правому краю',
|
|
149
|
+
});
|
|
150
|
+
i18n.setLanguage(['zh', 'zh-CN'], {
|
|
151
|
+
alignLeft: '左对齐',
|
|
152
|
+
alignCenter: '居中对齐',
|
|
153
|
+
alignRight: '右对齐',
|
|
154
|
+
});
|
|
155
|
+
i18n.setLanguage(['zh-TW'], {
|
|
156
|
+
alignLeft: '靠左對齊',
|
|
157
|
+
alignCenter: '置中對齊',
|
|
158
|
+
alignRight: '靠右對齊',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
;// CONCATENATED MODULE: ./src/index.ts
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
var PREFIX = 'toastui-editor-';
|
|
166
|
+
function createToolbarItemOption(text, commandName, i18n) {
|
|
167
|
+
return {
|
|
168
|
+
name: commandName,
|
|
169
|
+
command: commandName,
|
|
170
|
+
tooltip: i18n.get(commandName),
|
|
171
|
+
text: text,
|
|
172
|
+
className: PREFIX + "toolbar-icons " + commandName,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function textAlignPlugin(context, options) {
|
|
176
|
+
if (options === void 0) { options = {}; }
|
|
177
|
+
var i18n = context.i18n, eventEmitter = context.eventEmitter, _a = context.usageStatistics, usageStatistics = _a === void 0 ? true : _a;
|
|
178
|
+
addLangs(i18n);
|
|
179
|
+
// Active state listener
|
|
180
|
+
eventEmitter.listen('caretChange', function () {
|
|
181
|
+
updateToolbarState();
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
markdownCommands: {
|
|
185
|
+
alignLeft: function (payload, _a, dispatch) {
|
|
186
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
187
|
+
return execMarkdownAlign('left', selection, schema, tr, dispatch);
|
|
188
|
+
},
|
|
189
|
+
alignCenter: function (payload, _a, dispatch) {
|
|
190
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
191
|
+
return execMarkdownAlign('center', selection, schema, tr, dispatch);
|
|
192
|
+
},
|
|
193
|
+
alignRight: function (payload, _a, dispatch) {
|
|
194
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
195
|
+
return execMarkdownAlign('right', selection, schema, tr, dispatch);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
wysiwygCommands: {
|
|
199
|
+
alignLeft: function (payload, _a, dispatch) {
|
|
200
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
201
|
+
return execWysiwygAlign('left', selection, schema, tr, dispatch);
|
|
202
|
+
},
|
|
203
|
+
alignCenter: function (payload, _a, dispatch) {
|
|
204
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
205
|
+
return execWysiwygAlign('center', selection, schema, tr, dispatch);
|
|
206
|
+
},
|
|
207
|
+
alignRight: function (payload, _a, dispatch) {
|
|
208
|
+
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
209
|
+
return execWysiwygAlign('right', selection, schema, tr, dispatch);
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
toolbarItems: [
|
|
213
|
+
{
|
|
214
|
+
groupIndex: 1,
|
|
215
|
+
itemIndex: 2,
|
|
216
|
+
item: createToolbarItemOption('', 'alignLeft', i18n),
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
groupIndex: 1,
|
|
220
|
+
itemIndex: 3,
|
|
221
|
+
item: createToolbarItemOption('', 'alignCenter', i18n),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
groupIndex: 1,
|
|
225
|
+
itemIndex: 4,
|
|
226
|
+
item: createToolbarItemOption('', 'alignRight', i18n),
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
toHTMLRenderers: {
|
|
230
|
+
htmlInline: {
|
|
231
|
+
span: function (node, _a) {
|
|
232
|
+
var entering = _a.entering, origin = _a.origin;
|
|
233
|
+
var style = node.attrs ? node.attrs.style : null;
|
|
234
|
+
if (style && style.indexOf('text-align') > -1) {
|
|
235
|
+
return entering
|
|
236
|
+
? { type: 'openTag', tagName: 'span', attributes: { style: style } }
|
|
237
|
+
: { type: 'closeTag', tagName: 'span' };
|
|
238
|
+
}
|
|
239
|
+
if (origin) {
|
|
240
|
+
return origin();
|
|
241
|
+
}
|
|
242
|
+
return { type: 'html', content: node.literal || '' };
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function updateToolbarState() {
|
|
249
|
+
// 1. Reset all buttons
|
|
250
|
+
var buttons = document.querySelectorAll('.toastui-editor-toolbar-icons.alignLeft, .toastui-editor-toolbar-icons.alignCenter, .toastui-editor-toolbar-icons.alignRight');
|
|
251
|
+
buttons.forEach(function (btn) { return btn.classList.remove('active'); });
|
|
252
|
+
// 2. Determine active state
|
|
253
|
+
// Getting state from plugin context is hard.
|
|
254
|
+
// For Markdown: Parse current line of cursor?
|
|
255
|
+
// For WYSIWYG: Parse selection marks?
|
|
256
|
+
// Naive checker for demo quality:
|
|
257
|
+
var selection = window.getSelection();
|
|
258
|
+
if (!selection || selection.rangeCount === 0)
|
|
259
|
+
return;
|
|
260
|
+
var range = selection.getRangeAt(0);
|
|
261
|
+
var container = range.commonAncestorContainer;
|
|
262
|
+
if (container.nodeType === 3)
|
|
263
|
+
container = container.parentElement; // Text node -> Element
|
|
264
|
+
var el = container;
|
|
265
|
+
// Check for span with style
|
|
266
|
+
var activeAlign = null;
|
|
267
|
+
var current = el;
|
|
268
|
+
// Walk up a few levels to find span
|
|
269
|
+
while (current &&
|
|
270
|
+
current.classList &&
|
|
271
|
+
!current.classList.contains('ProseMirror') &&
|
|
272
|
+
!current.classList.contains('toastui-editor-contents')) {
|
|
273
|
+
if (current.tagName === 'SPAN' && current.style.textAlign) {
|
|
274
|
+
activeAlign = current.style.textAlign;
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
current = current.parentElement;
|
|
278
|
+
}
|
|
279
|
+
if (!activeAlign) {
|
|
280
|
+
// Check inner text if in Markdown mode (Textarea)
|
|
281
|
+
// This is very hard because DOM is just text.
|
|
282
|
+
// We skip Markdown active state highlight for this iteration,
|
|
283
|
+
// focusing on WYSIWYG visual feedback.
|
|
284
|
+
}
|
|
285
|
+
if (activeAlign) {
|
|
286
|
+
var activeBtn = document.querySelector(".toastui-editor-toolbar-icons.align" + capitalize(activeAlign));
|
|
287
|
+
if (activeBtn)
|
|
288
|
+
activeBtn.classList.add('active');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function capitalize(s) {
|
|
292
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
293
|
+
}
|
|
294
|
+
function execMarkdownAlign(alignType, selection, schema, tr, dispatch) {
|
|
295
|
+
var doc = tr.doc;
|
|
296
|
+
var from = selection.from, to = selection.to;
|
|
297
|
+
// Always expand to full line(s) to avoid nesting inside words
|
|
298
|
+
var $from = doc.resolve(from);
|
|
299
|
+
var $to = doc.resolve(to);
|
|
300
|
+
// In Markdown mode (CodeMirror-like), we usually want to operate on lines.
|
|
301
|
+
// We can use doc.resolve(from).blockRange() -> this gives the text block (paragraph).
|
|
302
|
+
// This is safer than char-level selection for block alignment.
|
|
303
|
+
var fromLine = $from.pos - $from.parentOffset; // Start of line
|
|
304
|
+
var toLine = $to.pos + ($to.parent.content.size - $to.parentOffset); // End of line
|
|
305
|
+
// Wait, doc.resolve in Markdown mode... TUI's internal doc structure for Markdown is just a series of blocks?
|
|
306
|
+
// Let's rely on blockRange() which TUI implementation respects.
|
|
307
|
+
var blockRange = $from.blockRange($to);
|
|
308
|
+
var targetFrom = from;
|
|
309
|
+
var targetTo = to;
|
|
310
|
+
if (blockRange) {
|
|
311
|
+
targetFrom = blockRange.start + 1; // +1 to skip start token? No, text nodes.
|
|
312
|
+
targetTo = blockRange.end - 1;
|
|
313
|
+
// Actually, let's look at the Slice content.
|
|
314
|
+
// If we use blockRange, we get the whole "Paragraph" structure.
|
|
315
|
+
}
|
|
316
|
+
// Fallback: If no blockRange (rare), use raw selection.
|
|
317
|
+
// But to fix the "nesting" issue, we MUST select the whole line content including any existing HTML tags.
|
|
318
|
+
// In TUI Markdown, each line is likely a textblock.
|
|
319
|
+
// Let's try to grab the whole block content.
|
|
320
|
+
var resolvedFrom = doc.resolve(from);
|
|
321
|
+
var startPos = resolvedFrom.start();
|
|
322
|
+
var endPos = resolvedFrom.end();
|
|
323
|
+
targetFrom = startPos;
|
|
324
|
+
targetTo = endPos;
|
|
325
|
+
var slice = doc.slice(targetFrom, targetTo);
|
|
326
|
+
var textContent = slice.content.textBetween(0, slice.content.size, '\n');
|
|
327
|
+
// Looser regex to match existing tags
|
|
328
|
+
// Matches: <span ...> ... </span>
|
|
329
|
+
var regex = /^\s*<span\s+[^>]*style="[^"]*text-align:\s*(left|center|right)[^"]*"[^>]*>([\s\S]*?)<\/span>\s*$/i;
|
|
330
|
+
var match = textContent.match(regex);
|
|
331
|
+
var newText = textContent;
|
|
332
|
+
var currentAlign = null;
|
|
333
|
+
if (match) {
|
|
334
|
+
currentAlign = match[1].toLowerCase();
|
|
335
|
+
newText = match[2]; // Inner content
|
|
336
|
+
}
|
|
337
|
+
var finalWrapped = newText;
|
|
338
|
+
if (currentAlign === alignType) {
|
|
339
|
+
// Toggle off: Just return the inner text (unwrap)
|
|
340
|
+
// newText is already stripped of the span
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
// Apply new alignment
|
|
344
|
+
var style = "display: block; text-align: " + alignType;
|
|
345
|
+
finalWrapped = "<span style=\"" + style + "\">" + newText + "</span>";
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
tr.replaceWith(targetFrom, targetTo, schema.text(finalWrapped));
|
|
349
|
+
dispatch(tr);
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
catch (e) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function execWysiwygAlign(alignType, selection, schema, tr, dispatch) {
|
|
357
|
+
var empty = selection.empty;
|
|
358
|
+
var styleBase = 'display: block; text-align: ';
|
|
359
|
+
var targetFrom = selection.from;
|
|
360
|
+
var targetTo = selection.to;
|
|
361
|
+
var markType = schema.marks.span;
|
|
362
|
+
if (!markType)
|
|
363
|
+
return false;
|
|
364
|
+
if (empty) {
|
|
365
|
+
var $from = selection.$from;
|
|
366
|
+
var blockRange = $from.blockRange();
|
|
367
|
+
if (blockRange) {
|
|
368
|
+
targetFrom = blockRange.start;
|
|
369
|
+
targetTo = blockRange.end;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
var existingMark = null;
|
|
373
|
+
var existingAlign = null;
|
|
374
|
+
tr.doc.nodesBetween(targetFrom, targetTo, function (node) {
|
|
375
|
+
if (existingMark)
|
|
376
|
+
return false;
|
|
377
|
+
node.marks.forEach(function (mark) {
|
|
378
|
+
if (mark.type === markType && mark.attrs.style && mark.attrs.style.indexOf(styleBase) > -1) {
|
|
379
|
+
existingMark = mark;
|
|
380
|
+
var match = mark.attrs.style.match(/text-align: (left|center|right)/);
|
|
381
|
+
if (match)
|
|
382
|
+
existingAlign = match[1];
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
return true;
|
|
386
|
+
});
|
|
387
|
+
if (existingMark) {
|
|
388
|
+
tr.removeMark(targetFrom, targetTo, existingMark);
|
|
389
|
+
}
|
|
390
|
+
if (existingAlign === alignType) {
|
|
391
|
+
dispatch(tr);
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
var style = "" + styleBase + alignType;
|
|
395
|
+
var attrs = { htmlAttrs: { style: style } };
|
|
396
|
+
var mark = markType.create(attrs);
|
|
397
|
+
tr.addMark(targetFrom, targetTo, mark);
|
|
398
|
+
dispatch(tr);
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
__webpack_exports__ = __webpack_exports__["default"];
|
|
403
|
+
/******/ return __webpack_exports__;
|
|
404
|
+
/******/ })()
|
|
405
|
+
;
|
|
406
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@licium/editor-plugin-text-align-simpel",
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "TOAST UI Editor : Text Align Simpel Plugin",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nhn",
|
|
7
|
+
"nhn cloud",
|
|
8
|
+
"toast",
|
|
9
|
+
"toastui",
|
|
10
|
+
"toast-ui",
|
|
11
|
+
"editor",
|
|
12
|
+
"plugin",
|
|
13
|
+
"text-align",
|
|
14
|
+
"align",
|
|
15
|
+
"simpel"
|
|
16
|
+
],
|
|
17
|
+
"main": "dist/toastui-editor-plugin-text-align-simpel.js",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/*.js",
|
|
20
|
+
"dist/*.css",
|
|
21
|
+
"types/index.d.ts"
|
|
22
|
+
],
|
|
23
|
+
"types": "types/index.d.ts",
|
|
24
|
+
"author": "NHN Cloud FE Development Lab <dl_javascript@nhn.com>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/natorus87/tui.editor.git",
|
|
29
|
+
"directory": "plugins/text-align"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/natorus87/tui.editor/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://ui.toast.com",
|
|
35
|
+
"browserslist": "last 2 versions, not ie <= 10",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"lint": "eslint .",
|
|
38
|
+
"test:types": "tsc",
|
|
39
|
+
"test": "jest --watch",
|
|
40
|
+
"test:ci": "jest",
|
|
41
|
+
"serve": "snowpack dev",
|
|
42
|
+
"serve:ie": "webpack serve",
|
|
43
|
+
"build:cdn": "webpack build --env cdn & webpack build --env cdn minify",
|
|
44
|
+
"build": "webpack build && npm run build:cdn"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"cross-env": "^6.0.3"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"gitHead": "bcd3c0e3ea68cab78c6fb7f894d8cbc4ad34f10c"
|
|
53
|
+
}
|