@licium/editor-plugin-details 1.0.3 → 3.2.10
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/cdn/toastui-editor-plugin-details.css +42 -0
- package/dist/cdn/toastui-editor-plugin-details.js +786 -0
- package/dist/cdn/toastui-editor-plugin-details.min.css +6 -0
- package/dist/cdn/toastui-editor-plugin-details.min.js +7 -0
- package/dist/toastui-editor-plugin-details.css +42 -0
- package/dist/toastui-editor-plugin-details.js +147 -21
- package/package.json +4 -3
- package/src/i18n/langs.ts +120 -0
- package/src/index.ts +55 -21
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 1.0.13 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/.toastui-editor-toolbar-icons.details{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23333' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m19 21-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'/%3E%3Cpath d='m9 10 3 3 3-3'/%3E%3C/svg%3E")!important;background-position:50%!important;background-repeat:no-repeat!important;background-size:24px 24px!important;text-indent:-9999px!important}details{background-color:#f7f7f7;border:1px solid #e1e1e1;border-radius:4px;display:block;margin:10px 0;padding:10px}summary{cursor:pointer;font-weight:700;margin-bottom:5px;outline:none}.toastui-editor-dark .toastui-editor-toolbar-icons.details{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23eee' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m19 21-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'/%3E%3Cpath d='m9 10 3 3 3-3'/%3E%3C/svg%3E")!important}.toastui-editor-dark details{background-color:#282a36;border-color:#44475a;color:#f8f8f2}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 1.0.13 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.toastui=t():(e.toastui=e.toastui||{},e.toastui.Editor=e.toastui.Editor||{},e.toastui.Editor.plugin=e.toastui.Editor.plugin||{},e.toastui.Editor.plugin.details=t())}(self,(function(){return function(){"use strict";var e={d:function(t,n){for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t={};e.d(t,{default:function(){return a}});var n=function(){return n=Object.assign||function(e){for(var t,n=1,a=arguments.length;n<a;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},n.apply(this,arguments)};Object.create;Object.create;"function"==typeof SuppressedError&&SuppressedError;function a(e,t){void 0===t&&(t={});var a=e.i18n,o=e.eventEmitter;!function(e){e.setLanguage(["en","en-US"],{details:"Collapsible Block",summary:"Summary header",content:"Hidden content"}),e.setLanguage(["ar","ar-AR"],{details:"كتلة قابلة للطي",summary:"عنوان الملخص",content:"المحتوى المخفي"}),e.setLanguage(["cs","cs-CZ"],{details:"Sbalitelný blok",summary:"Záhlaví shrnutí",content:"Skrytý obsah"}),e.setLanguage(["de","de-DE"],{details:"Aufklappbarer Block",summary:"Klick mich zum Aufklappen",content:"Hier steht der versteckte Inhalt"}),e.setLanguage(["es","es-ES"],{details:"Bloque plegable",summary:"Encabezado del resumen",content:"Contenido oculto"}),e.setLanguage(["fi","fi-FI"],{details:"Kokoontaitettava lohko",summary:"Yhteenveto",content:"Piilotettu sisältö"}),e.setLanguage(["fr","fr-FR"],{details:"Bloc pliable",summary:"Titre du résumé",content:"Contenu masqué"}),e.setLanguage(["gl","gl-ES"],{details:"Bloque pregable",summary:"Cabeceira do resumo",content:"Contido oculto"}),e.setLanguage(["hr","hr-HR"],{details:"Sklopivi blok",summary:"Naslov sažetka",content:"Skriveni sadržaj"}),e.setLanguage(["it","it-IT"],{details:"Blocco comprimibile",summary:"Intestazione riepilogo",content:"Contenuto nascosto"}),e.setLanguage(["ja","ja-JP"],{details:"折りたたみブロック",summary:"要約ヘッダー",content:"隠しコンテンツ"}),e.setLanguage(["ko","ko-KR"],{details:"접이식 블록",summary:"요약 헤더",content:"숨겨진 콘텐츠"}),e.setLanguage(["nb","nb-NO"],{details:"Sammenleggbar blokk",summary:"Sammendrag overskrift",content:"Skjult innhold"}),e.setLanguage(["nl","nl-NL"],{details:"Inklapbaar blok",summary:"Samenvatting kop",content:"Verborgen inhoud"}),e.setLanguage(["pl","pl-PL"],{details:"Blok zwijany",summary:"Nagłówek podsumowania",content:"Ukryta treść"}),e.setLanguage(["pt","pt-BR"],{details:"Bloco recolhível",summary:"Cabeçalho de resumo",content:"Conteúdo oculto"}),e.setLanguage(["ru","ru-RU"],{details:"Сворачиваемый блок",summary:"Заголовок резюме",content:"Скрытый контент"}),e.setLanguage(["sv","sv-SE"],{details:"Hopfällbart block",summary:"Sammanfattning rubrik",content:"Dolt innehåll"}),e.setLanguage(["tr","tr-TR"],{details:"Daraltılabilir blok",summary:"Özet başlığı",content:"Gizli içerik"}),e.setLanguage(["uk","uk-UA"],{details:"Згортаємий блок",summary:"Заголовок резюме",content:"Прихований вміст"}),e.setLanguage(["zh","zh-CN"],{details:"可折叠块",summary:"摘要标题",content:"隐藏内容"}),e.setLanguage(["zh-TW"],{details:"可折疊區塊",summary:"摘要標題",content:"隱藏內容"})}(a);var r=function(e){return{name:"details",tooltip:e.get("details"),className:"toastui-editor-toolbar-icons details",command:"details"}}(a);return o.listen("keydown",(function(t,n){console.log("[Details Plugin] keydown via eventEmitter!",{editorType:t,key:n.key}),"wysiwyg"===t&&("Enter"!==n.key&&"ArrowDown"!==n.key||function(e,t){var n=e.instance;if(n){var a=n.getCurrentModeEditor();if(a&&a.view){for(var o=a.view,r=o.state,i=r.selection.$from,s=-1,l=i.depth;l>0;l-=1)if("details"===i.node(l).type.name){s=l;break}if(!(s<0)){var u=i.node(s),c=i.before(s)+u.nodeSize,d=i.after(),m=d>=c-1;if(console.log("[Details Plugin] Inside details:",{key:t.key,isAtEnd:m,afterPara:d,nodeEnd:c,parentType:i.parent.type.name,parentEmpty:0===i.parent.content.size}),m){var g=r.tr,p=r.schema,y=r.selection.constructor;if("Enter"===t.key){if("paragraph"!==i.parent.type.name||0!==i.parent.content.size)return;var f=i.index(s),v=u.child(f-1);if(!v||"paragraph"!==v.type.name||0!==v.content.size)return void console.log("[Details Plugin] Allowing one empty line. Not exiting yet.");console.log("[Details Plugin] EXITING via Double Enter (Two empty paras)!"),t.preventDefault();var k=i.before();g.delete(k,d);var h=p.nodes.paragraph.createAndFill(),b=c-(d-k);g.insert(b,h),y.near&&g.setSelection(y.near(g.doc.resolve(b+1))),o.dispatch(g)}if("ArrowDown"===t.key){if(i.parentOffset!==i.parent.content.size)return;console.log("[Details Plugin] EXITING via ArrowDown!"),t.preventDefault(),c<r.doc.content.size?y.near&&(g.setSelection(y.near(g.doc.resolve(c))),o.dispatch(g)):(h=p.nodes.paragraph.createAndFill(),g.insert(c,h),y.near&&g.setSelection(y.near(g.doc.resolve(c+1))),o.dispatch(g))}}}}else console.log("[Details Plugin] No editor view found")}else console.log("[Details Plugin] No instance found")}(e,n))})),{toHTMLRenderers:{htmlBlock:{renderer:function(e){return/<(\/)?(details|summary)/i.test(e.literal||"")?[{type:"html",content:e.literal||""}]:[{type:"openTag",tagName:"div",outerNewLine:!0},{type:"html",content:e.literal||""},{type:"closeTag",tagName:"div",outerNewLine:!0}]}}},markdownCommands:{details:function(e,t,n){var o=t.tr,r=t.selection,i=t.schema,s=r.content(),l=s.content.textBetween(0,s.content.size,"\n")||a.get("content"),u=""+("<details>\n<summary>"+a.get("summary")+"</summary>\n")+l+"\n</details>";return o.replaceSelectionWith(i.text(u)),n(o),!0}},wysiwygNodeViews:{details:function(e,t,a){var o=document.createElement("details"),r=e.attrs&&e.attrs.htmlAttrs||{};return(!0===e.attrs.open||r&&null!==r.open&&void 0!==r.open)&&(o.open=!0),o.addEventListener("click",(function(o){var i=o.target;if("SUMMARY"===i.tagName||i.closest("summary")){o.preventDefault();var s=a();if("number"==typeof s){var l=null!==r.open&&void 0!==r.open,u=n({},r);l?delete u.open:u.open="";var c=n(n({},e.attrs),{htmlAttrs:u});t.dispatch(t.state.tr.setNodeMarkup(s,null,c))}}})),{dom:o,contentDOM:o}}},wysiwygCommands:{details:function(e,t,n){var o=t.tr,r=t.schema,i=a.get("summary"),s=a.get("content"),l=r.nodes,u=l.details,c=l.summary,d=l.paragraph;if(u&&c&&d){var m=c.create({},r.text(i)),g=d.create({},r.text(s)),p=u.create({},[m,g]);return o.replaceSelectionWith(p),n(o),!0}return!1}},toolbarItems:[{groupIndex:4,itemIndex:3,item:r}]}}return t=t.default}()}));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 3.2.10 | Thu Jan 08 2026
|
|
4
|
+
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
/* Light Mode */
|
|
8
|
+
.toastui-editor-toolbar-icons.details {
|
|
9
|
+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23333%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z%27/%3E%3Cpath d=%27M9 10L12 13 15 10%27 stroke=%27%23333%27/%3E%3C/svg%3E") !important;
|
|
10
|
+
background-size: 24px 24px !important;
|
|
11
|
+
background-repeat: no-repeat !important;
|
|
12
|
+
background-position: center center !important;
|
|
13
|
+
text-indent: -9999px !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
details {
|
|
17
|
+
display: block;
|
|
18
|
+
background-color: #f7f7f7;
|
|
19
|
+
border: 1px solid #e1e1e1;
|
|
20
|
+
border-radius: 4px;
|
|
21
|
+
padding: 10px;
|
|
22
|
+
margin: 10px 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
summary {
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
font-weight: bold;
|
|
28
|
+
margin-bottom: 5px;
|
|
29
|
+
outline: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Dark Mode */
|
|
33
|
+
.toastui-editor-dark .toastui-editor-toolbar-icons.details {
|
|
34
|
+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23eee%27 stroke-width=%272%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z%27/%3E%3Cpath d=%27M9 10L12 13 15 10%27 stroke=%27%23eee%27/%3E%3C/svg%3E") !important;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.toastui-editor-dark details {
|
|
38
|
+
background-color: #282a36;
|
|
39
|
+
/* Darker background for contrast against editor bg */
|
|
40
|
+
border-color: #44475a;
|
|
41
|
+
color: #f8f8f2;
|
|
42
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* TOAST UI Editor : Text Align Plugin
|
|
3
|
-
* @version
|
|
3
|
+
* @version 3.2.10 | Thu Jan 08 2026
|
|
4
4
|
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -455,16 +455,117 @@ function addLangs(i18n) {
|
|
|
455
455
|
summary: 'Summary header',
|
|
456
456
|
content: 'Hidden content',
|
|
457
457
|
});
|
|
458
|
+
i18n.setLanguage(['ar', 'ar-AR'], {
|
|
459
|
+
details: 'كتلة قابلة للطي',
|
|
460
|
+
summary: 'عنوان الملخص',
|
|
461
|
+
content: 'المحتوى المخفي',
|
|
462
|
+
});
|
|
463
|
+
i18n.setLanguage(['cs', 'cs-CZ'], {
|
|
464
|
+
details: 'Sbalitelný blok',
|
|
465
|
+
summary: 'Záhlaví shrnutí',
|
|
466
|
+
content: 'Skrytý obsah',
|
|
467
|
+
});
|
|
458
468
|
i18n.setLanguage(['de', 'de-DE'], {
|
|
459
469
|
details: 'Aufklappbarer Block',
|
|
460
470
|
summary: 'Klick mich zum Aufklappen',
|
|
461
471
|
content: 'Hier steht der versteckte Inhalt',
|
|
462
472
|
});
|
|
473
|
+
i18n.setLanguage(['es', 'es-ES'], {
|
|
474
|
+
details: 'Bloque plegable',
|
|
475
|
+
summary: 'Encabezado del resumen',
|
|
476
|
+
content: 'Contenido oculto',
|
|
477
|
+
});
|
|
478
|
+
i18n.setLanguage(['fi', 'fi-FI'], {
|
|
479
|
+
details: 'Kokoontaitettava lohko',
|
|
480
|
+
summary: 'Yhteenveto',
|
|
481
|
+
content: 'Piilotettu sisältö',
|
|
482
|
+
});
|
|
483
|
+
i18n.setLanguage(['fr', 'fr-FR'], {
|
|
484
|
+
details: 'Bloc pliable',
|
|
485
|
+
summary: 'Titre du résumé',
|
|
486
|
+
content: 'Contenu masqué',
|
|
487
|
+
});
|
|
488
|
+
i18n.setLanguage(['gl', 'gl-ES'], {
|
|
489
|
+
details: 'Bloque pregable',
|
|
490
|
+
summary: 'Cabeceira do resumo',
|
|
491
|
+
content: 'Contido oculto',
|
|
492
|
+
});
|
|
493
|
+
i18n.setLanguage(['hr', 'hr-HR'], {
|
|
494
|
+
details: 'Sklopivi blok',
|
|
495
|
+
summary: 'Naslov sažetka',
|
|
496
|
+
content: 'Skriveni sadržaj',
|
|
497
|
+
});
|
|
498
|
+
i18n.setLanguage(['it', 'it-IT'], {
|
|
499
|
+
details: 'Blocco comprimibile',
|
|
500
|
+
summary: 'Intestazione riepilogo',
|
|
501
|
+
content: 'Contenuto nascosto',
|
|
502
|
+
});
|
|
503
|
+
i18n.setLanguage(['ja', 'ja-JP'], {
|
|
504
|
+
details: '折りたたみブロック',
|
|
505
|
+
summary: '要約ヘッダー',
|
|
506
|
+
content: '隠しコンテンツ',
|
|
507
|
+
});
|
|
508
|
+
i18n.setLanguage(['ko', 'ko-KR'], {
|
|
509
|
+
details: '접이식 블록',
|
|
510
|
+
summary: '요약 헤더',
|
|
511
|
+
content: '숨겨진 콘텐츠',
|
|
512
|
+
});
|
|
513
|
+
i18n.setLanguage(['nb', 'nb-NO'], {
|
|
514
|
+
details: 'Sammenleggbar blokk',
|
|
515
|
+
summary: 'Sammendrag overskrift',
|
|
516
|
+
content: 'Skjult innhold',
|
|
517
|
+
});
|
|
518
|
+
i18n.setLanguage(['nl', 'nl-NL'], {
|
|
519
|
+
details: 'Inklapbaar blok',
|
|
520
|
+
summary: 'Samenvatting kop',
|
|
521
|
+
content: 'Verborgen inhoud',
|
|
522
|
+
});
|
|
523
|
+
i18n.setLanguage(['pl', 'pl-PL'], {
|
|
524
|
+
details: 'Blok zwijany',
|
|
525
|
+
summary: 'Nagłówek podsumowania',
|
|
526
|
+
content: 'Ukryta treść',
|
|
527
|
+
});
|
|
528
|
+
i18n.setLanguage(['pt', 'pt-BR'], {
|
|
529
|
+
details: 'Bloco recolhível',
|
|
530
|
+
summary: 'Cabeçalho de resumo',
|
|
531
|
+
content: 'Conteúdo oculto',
|
|
532
|
+
});
|
|
533
|
+
i18n.setLanguage(['ru', 'ru-RU'], {
|
|
534
|
+
details: 'Сворачиваемый блок',
|
|
535
|
+
summary: 'Заголовок резюме',
|
|
536
|
+
content: 'Скрытый контент',
|
|
537
|
+
});
|
|
538
|
+
i18n.setLanguage(['sv', 'sv-SE'], {
|
|
539
|
+
details: 'Hopfällbart block',
|
|
540
|
+
summary: 'Sammanfattning rubrik',
|
|
541
|
+
content: 'Dolt innehåll',
|
|
542
|
+
});
|
|
543
|
+
i18n.setLanguage(['tr', 'tr-TR'], {
|
|
544
|
+
details: 'Daraltılabilir blok',
|
|
545
|
+
summary: 'Özet başlığı',
|
|
546
|
+
content: 'Gizli içerik',
|
|
547
|
+
});
|
|
548
|
+
i18n.setLanguage(['uk', 'uk-UA'], {
|
|
549
|
+
details: 'Згортаємий блок',
|
|
550
|
+
summary: 'Заголовок резюме',
|
|
551
|
+
content: 'Прихований вміст',
|
|
552
|
+
});
|
|
553
|
+
i18n.setLanguage(['zh', 'zh-CN'], {
|
|
554
|
+
details: '可折叠块',
|
|
555
|
+
summary: '摘要标题',
|
|
556
|
+
content: '隐藏内容',
|
|
557
|
+
});
|
|
558
|
+
i18n.setLanguage(['zh-TW'], {
|
|
559
|
+
details: '可折疊區塊',
|
|
560
|
+
summary: '摘要標題',
|
|
561
|
+
content: '隱藏內容',
|
|
562
|
+
});
|
|
463
563
|
}
|
|
464
564
|
|
|
465
565
|
;// CONCATENATED MODULE: ./src/index.ts
|
|
466
566
|
|
|
467
567
|
|
|
568
|
+
|
|
468
569
|
var PREFIX = 'toastui-editor-';
|
|
469
570
|
function createToolbarItemOption(i18n) {
|
|
470
571
|
return {
|
|
@@ -524,9 +625,23 @@ function handleDetailsExit(context, event) {
|
|
|
524
625
|
if (!isEmptyPara) {
|
|
525
626
|
return;
|
|
526
627
|
}
|
|
527
|
-
|
|
628
|
+
// Check previous node to see if it's also an empty paragraph
|
|
629
|
+
// $from.index(0) gives the index in the parent details node
|
|
630
|
+
var index = $from.index(detailsDepth);
|
|
631
|
+
var prevNode = detailsNode.child(index - 1);
|
|
632
|
+
var isPrevEmptyPara = prevNode && prevNode.type.name === 'paragraph' && prevNode.content.size === 0;
|
|
633
|
+
if (!isPrevEmptyPara) {
|
|
634
|
+
console.log('[Details Plugin] Allowing one empty line. Not exiting yet.');
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
console.log('[Details Plugin] EXITING via Double Enter (Two empty paras)!');
|
|
528
638
|
event.preventDefault();
|
|
529
639
|
var beforePara = $from.before();
|
|
640
|
+
// delete the current empty para and the previous one?
|
|
641
|
+
// Usually "Exit" means: Lift the current empty para out.
|
|
642
|
+
// But if we have TWO empty paras, maybe we want to keep one inside?
|
|
643
|
+
// Let's stick to: If two empty paras, we treat it as an exit signal.
|
|
644
|
+
// We should probably remove the *current* empty para and move the cursor out.
|
|
530
645
|
tr.delete(beforePara, afterPara);
|
|
531
646
|
var p = schema.nodes.paragraph.createAndFill();
|
|
532
647
|
var insertPos = nodeEnd - (afterPara - beforePara);
|
|
@@ -577,6 +692,20 @@ function detailsPlugin(context, options) {
|
|
|
577
692
|
handleDetailsExit(context, event);
|
|
578
693
|
});
|
|
579
694
|
return {
|
|
695
|
+
toHTMLRenderers: {
|
|
696
|
+
htmlBlock: {
|
|
697
|
+
renderer: function (node) {
|
|
698
|
+
var isDetails = /<(\/)?(details|summary)/i.test(node.literal || '');
|
|
699
|
+
return isDetails
|
|
700
|
+
? [{ type: 'html', content: node.literal || '' }]
|
|
701
|
+
: [
|
|
702
|
+
{ type: 'openTag', tagName: 'div', outerNewLine: true },
|
|
703
|
+
{ type: 'html', content: node.literal || '' },
|
|
704
|
+
{ type: 'closeTag', tagName: 'div', outerNewLine: true },
|
|
705
|
+
];
|
|
706
|
+
},
|
|
707
|
+
},
|
|
708
|
+
},
|
|
580
709
|
markdownCommands: {
|
|
581
710
|
details: function (payload, _a, dispatch) {
|
|
582
711
|
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
@@ -591,25 +720,14 @@ function detailsPlugin(context, options) {
|
|
|
591
720
|
return true;
|
|
592
721
|
},
|
|
593
722
|
},
|
|
594
|
-
toHTMLRenderers: {
|
|
595
|
-
htmlBlock: {
|
|
596
|
-
details: function (node) { return [
|
|
597
|
-
{ type: 'openTag', tagName: 'details', outerNewLine: true },
|
|
598
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
599
|
-
{ type: 'closeTag', tagName: 'details', outerNewLine: true },
|
|
600
|
-
]; },
|
|
601
|
-
summary: function (node) { return [
|
|
602
|
-
{ type: 'openTag', tagName: 'summary', outerNewLine: true },
|
|
603
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
604
|
-
{ type: 'closeTag', tagName: 'summary', outerNewLine: true },
|
|
605
|
-
]; },
|
|
606
|
-
},
|
|
607
|
-
},
|
|
608
723
|
wysiwygNodeViews: {
|
|
609
724
|
details: function (node, view, getPos) {
|
|
610
725
|
var dom = document.createElement('details');
|
|
611
|
-
var htmlAttrs = node.attrs.htmlAttrs;
|
|
612
|
-
|
|
726
|
+
var htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
|
|
727
|
+
var isOpenAttr = node.attrs.open; // Core definition uses direct attribute
|
|
728
|
+
// Check both direct attribute (priority) and htmlAttrs (legacy/plugin)
|
|
729
|
+
var isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
|
|
730
|
+
if (isOpen) {
|
|
613
731
|
dom.open = true;
|
|
614
732
|
}
|
|
615
733
|
dom.addEventListener('click', function (e) {
|
|
@@ -618,7 +736,15 @@ function detailsPlugin(context, options) {
|
|
|
618
736
|
e.preventDefault();
|
|
619
737
|
var pos = getPos();
|
|
620
738
|
if (typeof pos === 'number') {
|
|
621
|
-
var
|
|
739
|
+
var isOpen_1 = htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined';
|
|
740
|
+
var newHtmlAttrs = __assign({}, htmlAttrs);
|
|
741
|
+
if (isOpen_1) {
|
|
742
|
+
delete newHtmlAttrs.open;
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
newHtmlAttrs.open = '';
|
|
746
|
+
}
|
|
747
|
+
var newAttrs = __assign(__assign({}, node.attrs), { htmlAttrs: newHtmlAttrs });
|
|
622
748
|
view.dispatch(view.state.tr.setNodeMarkup(pos, null, newAttrs));
|
|
623
749
|
}
|
|
624
750
|
}
|
|
@@ -645,8 +771,8 @@ function detailsPlugin(context, options) {
|
|
|
645
771
|
},
|
|
646
772
|
toolbarItems: [
|
|
647
773
|
{
|
|
648
|
-
groupIndex:
|
|
649
|
-
itemIndex:
|
|
774
|
+
groupIndex: 4,
|
|
775
|
+
itemIndex: 3,
|
|
650
776
|
item: toolbarItem,
|
|
651
777
|
},
|
|
652
778
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@licium/editor-plugin-details",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.2.10",
|
|
4
4
|
"description": "Details/Summary plugin for Toast UI Editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nhn",
|
|
@@ -47,5 +47,6 @@
|
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
50
|
-
}
|
|
51
|
-
|
|
50
|
+
},
|
|
51
|
+
"gitHead": "f5c5e17205373f73a607b05d989c4b06768752dd"
|
|
52
|
+
}
|
package/src/i18n/langs.ts
CHANGED
|
@@ -7,9 +7,129 @@ export function addLangs(i18n: I18n) {
|
|
|
7
7
|
content: 'Hidden content',
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
i18n.setLanguage(['ar', 'ar-AR'], {
|
|
11
|
+
details: 'كتلة قابلة للطي',
|
|
12
|
+
summary: 'عنوان الملخص',
|
|
13
|
+
content: 'المحتوى المخفي',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
i18n.setLanguage(['cs', 'cs-CZ'], {
|
|
17
|
+
details: 'Sbalitelný blok',
|
|
18
|
+
summary: 'Záhlaví shrnutí',
|
|
19
|
+
content: 'Skrytý obsah',
|
|
20
|
+
});
|
|
21
|
+
|
|
10
22
|
i18n.setLanguage(['de', 'de-DE'], {
|
|
11
23
|
details: 'Aufklappbarer Block',
|
|
12
24
|
summary: 'Klick mich zum Aufklappen',
|
|
13
25
|
content: 'Hier steht der versteckte Inhalt',
|
|
14
26
|
});
|
|
27
|
+
|
|
28
|
+
i18n.setLanguage(['es', 'es-ES'], {
|
|
29
|
+
details: 'Bloque plegable',
|
|
30
|
+
summary: 'Encabezado del resumen',
|
|
31
|
+
content: 'Contenido oculto',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
i18n.setLanguage(['fi', 'fi-FI'], {
|
|
35
|
+
details: 'Kokoontaitettava lohko',
|
|
36
|
+
summary: 'Yhteenveto',
|
|
37
|
+
content: 'Piilotettu sisältö',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
i18n.setLanguage(['fr', 'fr-FR'], {
|
|
41
|
+
details: 'Bloc pliable',
|
|
42
|
+
summary: 'Titre du résumé',
|
|
43
|
+
content: 'Contenu masqué',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
i18n.setLanguage(['gl', 'gl-ES'], {
|
|
47
|
+
details: 'Bloque pregable',
|
|
48
|
+
summary: 'Cabeceira do resumo',
|
|
49
|
+
content: 'Contido oculto',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
i18n.setLanguage(['hr', 'hr-HR'], {
|
|
53
|
+
details: 'Sklopivi blok',
|
|
54
|
+
summary: 'Naslov sažetka',
|
|
55
|
+
content: 'Skriveni sadržaj',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
i18n.setLanguage(['it', 'it-IT'], {
|
|
59
|
+
details: 'Blocco comprimibile',
|
|
60
|
+
summary: 'Intestazione riepilogo',
|
|
61
|
+
content: 'Contenuto nascosto',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
i18n.setLanguage(['ja', 'ja-JP'], {
|
|
65
|
+
details: '折りたたみブロック',
|
|
66
|
+
summary: '要約ヘッダー',
|
|
67
|
+
content: '隠しコンテンツ',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
i18n.setLanguage(['ko', 'ko-KR'], {
|
|
71
|
+
details: '접이식 블록',
|
|
72
|
+
summary: '요약 헤더',
|
|
73
|
+
content: '숨겨진 콘텐츠',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
i18n.setLanguage(['nb', 'nb-NO'], {
|
|
77
|
+
details: 'Sammenleggbar blokk',
|
|
78
|
+
summary: 'Sammendrag overskrift',
|
|
79
|
+
content: 'Skjult innhold',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
i18n.setLanguage(['nl', 'nl-NL'], {
|
|
83
|
+
details: 'Inklapbaar blok',
|
|
84
|
+
summary: 'Samenvatting kop',
|
|
85
|
+
content: 'Verborgen inhoud',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
i18n.setLanguage(['pl', 'pl-PL'], {
|
|
89
|
+
details: 'Blok zwijany',
|
|
90
|
+
summary: 'Nagłówek podsumowania',
|
|
91
|
+
content: 'Ukryta treść',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
i18n.setLanguage(['pt', 'pt-BR'], {
|
|
95
|
+
details: 'Bloco recolhível',
|
|
96
|
+
summary: 'Cabeçalho de resumo',
|
|
97
|
+
content: 'Conteúdo oculto',
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
i18n.setLanguage(['ru', 'ru-RU'], {
|
|
101
|
+
details: 'Сворачиваемый блок',
|
|
102
|
+
summary: 'Заголовок резюме',
|
|
103
|
+
content: 'Скрытый контент',
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
i18n.setLanguage(['sv', 'sv-SE'], {
|
|
107
|
+
details: 'Hopfällbart block',
|
|
108
|
+
summary: 'Sammanfattning rubrik',
|
|
109
|
+
content: 'Dolt innehåll',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
i18n.setLanguage(['tr', 'tr-TR'], {
|
|
113
|
+
details: 'Daraltılabilir blok',
|
|
114
|
+
summary: 'Özet başlığı',
|
|
115
|
+
content: 'Gizli içerik',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
i18n.setLanguage(['uk', 'uk-UA'], {
|
|
119
|
+
details: 'Згортаємий блок',
|
|
120
|
+
summary: 'Заголовок резюме',
|
|
121
|
+
content: 'Прихований вміст',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
i18n.setLanguage(['zh', 'zh-CN'], {
|
|
125
|
+
details: '可折叠块',
|
|
126
|
+
summary: '摘要标题',
|
|
127
|
+
content: '隐藏内容',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
i18n.setLanguage(['zh-TW'], {
|
|
131
|
+
details: '可折疊區塊',
|
|
132
|
+
summary: '摘要標題',
|
|
133
|
+
content: '隱藏內容',
|
|
134
|
+
});
|
|
15
135
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import type { PluginContext, PluginInfo, I18n, MdNode } from '@licium/editor';
|
|
2
3
|
import { PluginOptions } from '@t/index';
|
|
3
4
|
import { addLangs } from './i18n/langs';
|
|
5
|
+
import './css/plugin.css';
|
|
4
6
|
|
|
5
7
|
const PREFIX = 'toastui-editor-';
|
|
6
8
|
|
|
@@ -77,11 +79,28 @@ function handleDetailsExit(context: PluginContext, event: KeyboardEvent): void {
|
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
// Check previous node to see if it's also an empty paragraph
|
|
83
|
+
// $from.index(0) gives the index in the parent details node
|
|
84
|
+
const index = $from.index(detailsDepth);
|
|
85
|
+
const prevNode = detailsNode.child(index - 1);
|
|
86
|
+
const isPrevEmptyPara = prevNode && prevNode.type.name === 'paragraph' && prevNode.content.size === 0;
|
|
87
|
+
|
|
88
|
+
if (!isPrevEmptyPara) {
|
|
89
|
+
console.log('[Details Plugin] Allowing one empty line. Not exiting yet.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log('[Details Plugin] EXITING via Double Enter (Two empty paras)!');
|
|
81
94
|
event.preventDefault();
|
|
82
95
|
|
|
83
96
|
const beforePara = $from.before();
|
|
84
97
|
|
|
98
|
+
// delete the current empty para and the previous one?
|
|
99
|
+
// Usually "Exit" means: Lift the current empty para out.
|
|
100
|
+
// But if we have TWO empty paras, maybe we want to keep one inside?
|
|
101
|
+
// Let's stick to: If two empty paras, we treat it as an exit signal.
|
|
102
|
+
// We should probably remove the *current* empty para and move the cursor out.
|
|
103
|
+
|
|
85
104
|
tr.delete(beforePara, afterPara);
|
|
86
105
|
|
|
87
106
|
const p = schema.nodes.paragraph.createAndFill()!;
|
|
@@ -152,6 +171,20 @@ export default function detailsPlugin(
|
|
|
152
171
|
});
|
|
153
172
|
|
|
154
173
|
return {
|
|
174
|
+
toHTMLRenderers: {
|
|
175
|
+
htmlBlock: {
|
|
176
|
+
renderer: (node) => {
|
|
177
|
+
const isDetails = /<(\/)?(details|summary)/i.test(node.literal || '');
|
|
178
|
+
return isDetails
|
|
179
|
+
? [{ type: 'html', content: node.literal || '' }]
|
|
180
|
+
: [
|
|
181
|
+
{ type: 'openTag', tagName: 'div', outerNewLine: true },
|
|
182
|
+
{ type: 'html', content: node.literal || '' },
|
|
183
|
+
{ type: 'closeTag', tagName: 'div', outerNewLine: true },
|
|
184
|
+
];
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
155
188
|
markdownCommands: {
|
|
156
189
|
details: (payload, { tr, selection, schema }, dispatch) => {
|
|
157
190
|
const slice = selection.content();
|
|
@@ -168,26 +201,18 @@ export default function detailsPlugin(
|
|
|
168
201
|
return true;
|
|
169
202
|
},
|
|
170
203
|
},
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
details: (node) => [
|
|
174
|
-
{ type: 'openTag', tagName: 'details', outerNewLine: true },
|
|
175
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
176
|
-
{ type: 'closeTag', tagName: 'details', outerNewLine: true },
|
|
177
|
-
],
|
|
178
|
-
summary: (node) => [
|
|
179
|
-
{ type: 'openTag', tagName: 'summary', outerNewLine: true },
|
|
180
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
181
|
-
{ type: 'closeTag', tagName: 'summary', outerNewLine: true },
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
},
|
|
204
|
+
|
|
205
|
+
|
|
185
206
|
wysiwygNodeViews: {
|
|
186
207
|
details: (node, view, getPos) => {
|
|
187
208
|
const dom = document.createElement('details');
|
|
188
|
-
const
|
|
209
|
+
const htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
|
|
210
|
+
const isOpenAttr = node.attrs.open; // Core definition uses direct attribute
|
|
211
|
+
|
|
212
|
+
// Check both direct attribute (priority) and htmlAttrs (legacy/plugin)
|
|
213
|
+
const isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
|
|
189
214
|
|
|
190
|
-
if (
|
|
215
|
+
if (isOpen) {
|
|
191
216
|
dom.open = true;
|
|
192
217
|
}
|
|
193
218
|
|
|
@@ -200,9 +225,18 @@ export default function detailsPlugin(
|
|
|
200
225
|
const pos = getPos();
|
|
201
226
|
|
|
202
227
|
if (typeof pos === 'number') {
|
|
228
|
+
const isOpen = htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined';
|
|
229
|
+
const newHtmlAttrs = { ...htmlAttrs };
|
|
230
|
+
|
|
231
|
+
if (isOpen) {
|
|
232
|
+
delete newHtmlAttrs.open;
|
|
233
|
+
} else {
|
|
234
|
+
newHtmlAttrs.open = '';
|
|
235
|
+
}
|
|
236
|
+
|
|
203
237
|
const newAttrs = {
|
|
204
238
|
...node.attrs,
|
|
205
|
-
htmlAttrs:
|
|
239
|
+
htmlAttrs: newHtmlAttrs,
|
|
206
240
|
};
|
|
207
241
|
|
|
208
242
|
view.dispatch(view.state.tr.setNodeMarkup(pos, null, newAttrs));
|
|
@@ -235,8 +269,8 @@ export default function detailsPlugin(
|
|
|
235
269
|
},
|
|
236
270
|
toolbarItems: [
|
|
237
271
|
{
|
|
238
|
-
groupIndex:
|
|
239
|
-
itemIndex:
|
|
272
|
+
groupIndex: 4,
|
|
273
|
+
itemIndex: 3,
|
|
240
274
|
item: toolbarItem,
|
|
241
275
|
},
|
|
242
276
|
],
|