@licium/editor-plugin-details 1.0.2 → 1.0.13
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/dist/cdn/toastui-editor-plugin-details.css +42 -0
- package/dist/cdn/toastui-editor-plugin-details.js +683 -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 +144 -101
- package/package.json +1 -1
- package/src/css/plugin.css +23 -0
- package/src/index.ts +185 -128
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 1.0.12 | Mon Jan 05 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 r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t={};e.d(t,{default:function(){return r}});var n=function(){return n=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;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 r(e,t){void 0===t&&(t={});var r=e.i18n,o=e.eventEmitter;!function(e){e.setLanguage(["en","en-US"],{details:"Collapsible Block",summary:"Summary header",content:"Hidden content"}),e.setLanguage(["de","de-DE"],{details:"Aufklappbarer Block",summary:"Klick mich zum Aufklappen",content:"Hier steht der versteckte Inhalt"})}(r);var a=function(e){return{name:"details",tooltip:e.get("details"),className:"toastui-editor-toolbar-icons details",command:"details"}}(r);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 r=n.getCurrentModeEditor();if(r&&r.view){for(var o=r.view,a=o.state,i=a.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 c=i.node(s),d=i.before(s)+c.nodeSize,u=i.after(),p=u>=d-1;if(console.log("[Details Plugin] Inside details:",{key:t.key,isAtEnd:p,afterPara:u,nodeEnd:d,parentType:i.parent.type.name,parentEmpty:0===i.parent.content.size}),p){var f=a.tr,m=a.schema,y=a.selection.constructor;if("Enter"===t.key){if("paragraph"!==i.parent.type.name||0!==i.parent.content.size)return;var g=i.index(s),v=c.child(g-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 h=i.before();f.delete(h,u);var w=m.nodes.paragraph.createAndFill(),k=d-(u-h);f.insert(k,w),y.near&&f.setSelection(y.near(f.doc.resolve(k+1))),o.dispatch(f)}if("ArrowDown"===t.key){if(i.parentOffset!==i.parent.content.size)return;console.log("[Details Plugin] EXITING via ArrowDown!"),t.preventDefault(),d<a.doc.content.size?y.near&&(f.setSelection(y.near(f.doc.resolve(d))),o.dispatch(f)):(w=m.nodes.paragraph.createAndFill(),f.insert(d,w),y.near&&f.setSelection(y.near(f.doc.resolve(d+1))),o.dispatch(f))}}}}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,a=t.selection,i=t.schema,s=a.content(),l=s.content.textBetween(0,s.content.size,"\n")||r.get("content"),c=""+("<details>\n<summary>"+r.get("summary")+"</summary>\n")+l+"\n</details>";return o.replaceSelectionWith(i.text(c)),n(o),!0}},wysiwygNodeViews:{details:function(e,t,r){var o=document.createElement("details"),a=e.attrs.htmlAttrs||{};return null!==a.open&&void 0!==a.open&&(o.open=!0),o.addEventListener("click",(function(o){var i=o.target;if("SUMMARY"===i.tagName||i.closest("summary")){o.preventDefault();var s=r();if("number"==typeof s){var l=null!==a.open&&void 0!==a.open,c=n({},a);l?delete c.open:c.open="";var d=n(n({},e.attrs),{htmlAttrs:c});t.dispatch(t.state.tr.setNodeMarkup(s,null,d))}}})),{dom:o,contentDOM:o}}},wysiwygCommands:{details:function(e,t,n){var o=t.tr,a=t.schema,i=r.get("summary"),s=r.get("content"),l=a.nodes,c=l.details,d=l.summary,u=l.paragraph;if(c&&d&&u){var p=d.create({},a.text(i)),f=u.create({},a.text(s)),m=c.create({},[p,f]);return o.replaceSelectionWith(m),n(o),!0}return!1}},toolbarItems:[{groupIndex:4,itemIndex:3,item:a}]}}return t=t.default}()}));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* TOAST UI Editor : Text Align Plugin
|
|
3
|
+
* @version 1.0.12 | Tue Jan 06 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 1.0.
|
|
3
|
+
* @version 1.0.12 | Tue Jan 06 2026
|
|
4
4
|
* @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -465,6 +465,7 @@ function addLangs(i18n) {
|
|
|
465
465
|
;// CONCATENATED MODULE: ./src/index.ts
|
|
466
466
|
|
|
467
467
|
|
|
468
|
+
|
|
468
469
|
var PREFIX = 'toastui-editor-';
|
|
469
470
|
function createToolbarItemOption(i18n) {
|
|
470
471
|
return {
|
|
@@ -474,16 +475,140 @@ function createToolbarItemOption(i18n) {
|
|
|
474
475
|
command: 'details',
|
|
475
476
|
};
|
|
476
477
|
}
|
|
478
|
+
function handleDetailsExit(context, event) {
|
|
479
|
+
var instance = context.instance;
|
|
480
|
+
if (!instance) {
|
|
481
|
+
console.log('[Details Plugin] No instance found');
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
var editor = instance.getCurrentModeEditor();
|
|
485
|
+
if (!editor || !editor.view) {
|
|
486
|
+
console.log('[Details Plugin] No editor view found');
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
var view = editor.view;
|
|
490
|
+
var state = view.state;
|
|
491
|
+
var selection = state.selection;
|
|
492
|
+
var $from = selection.$from;
|
|
493
|
+
// Find details node in ancestry
|
|
494
|
+
var detailsDepth = -1;
|
|
495
|
+
for (var d = $from.depth; d > 0; d -= 1) {
|
|
496
|
+
if ($from.node(d).type.name === 'details') {
|
|
497
|
+
detailsDepth = d;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (detailsDepth < 0) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
var detailsNode = $from.node(detailsDepth);
|
|
505
|
+
var nodeStart = $from.before(detailsDepth);
|
|
506
|
+
var nodeEnd = nodeStart + detailsNode.nodeSize;
|
|
507
|
+
var afterPara = $from.after();
|
|
508
|
+
var isAtEnd = afterPara >= nodeEnd - 1;
|
|
509
|
+
console.log('[Details Plugin] Inside details:', {
|
|
510
|
+
key: event.key,
|
|
511
|
+
isAtEnd: isAtEnd,
|
|
512
|
+
afterPara: afterPara,
|
|
513
|
+
nodeEnd: nodeEnd,
|
|
514
|
+
parentType: $from.parent.type.name,
|
|
515
|
+
parentEmpty: $from.parent.content.size === 0,
|
|
516
|
+
});
|
|
517
|
+
if (!isAtEnd) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
var tr = state.tr, schema = state.schema;
|
|
521
|
+
var SelectionClass = state.selection.constructor;
|
|
522
|
+
// Enter on empty paragraph
|
|
523
|
+
if (event.key === 'Enter') {
|
|
524
|
+
var isEmptyPara = $from.parent.type.name === 'paragraph' && $from.parent.content.size === 0;
|
|
525
|
+
if (!isEmptyPara) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
// Check previous node to see if it's also an empty paragraph
|
|
529
|
+
// $from.index(0) gives the index in the parent details node
|
|
530
|
+
var index = $from.index(detailsDepth);
|
|
531
|
+
var prevNode = detailsNode.child(index - 1);
|
|
532
|
+
var isPrevEmptyPara = prevNode && prevNode.type.name === 'paragraph' && prevNode.content.size === 0;
|
|
533
|
+
if (!isPrevEmptyPara) {
|
|
534
|
+
console.log('[Details Plugin] Allowing one empty line. Not exiting yet.');
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
console.log('[Details Plugin] EXITING via Double Enter (Two empty paras)!');
|
|
538
|
+
event.preventDefault();
|
|
539
|
+
var beforePara = $from.before();
|
|
540
|
+
// delete the current empty para and the previous one?
|
|
541
|
+
// Usually "Exit" means: Lift the current empty para out.
|
|
542
|
+
// But if we have TWO empty paras, maybe we want to keep one inside?
|
|
543
|
+
// Let's stick to: If two empty paras, we treat it as an exit signal.
|
|
544
|
+
// We should probably remove the *current* empty para and move the cursor out.
|
|
545
|
+
tr.delete(beforePara, afterPara);
|
|
546
|
+
var p = schema.nodes.paragraph.createAndFill();
|
|
547
|
+
var insertPos = nodeEnd - (afterPara - beforePara);
|
|
548
|
+
tr.insert(insertPos, p);
|
|
549
|
+
if (SelectionClass.near) {
|
|
550
|
+
tr.setSelection(SelectionClass.near(tr.doc.resolve(insertPos + 1)));
|
|
551
|
+
}
|
|
552
|
+
view.dispatch(tr);
|
|
553
|
+
}
|
|
554
|
+
// ArrowDown at end of content
|
|
555
|
+
if (event.key === 'ArrowDown') {
|
|
556
|
+
var atEndOfParent = $from.parentOffset === $from.parent.content.size;
|
|
557
|
+
if (!atEndOfParent) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
console.log('[Details Plugin] EXITING via ArrowDown!');
|
|
561
|
+
event.preventDefault();
|
|
562
|
+
if (nodeEnd < state.doc.content.size) {
|
|
563
|
+
if (SelectionClass.near) {
|
|
564
|
+
tr.setSelection(SelectionClass.near(tr.doc.resolve(nodeEnd)));
|
|
565
|
+
view.dispatch(tr);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
var p = schema.nodes.paragraph.createAndFill();
|
|
570
|
+
tr.insert(nodeEnd, p);
|
|
571
|
+
if (SelectionClass.near) {
|
|
572
|
+
tr.setSelection(SelectionClass.near(tr.doc.resolve(nodeEnd + 1)));
|
|
573
|
+
}
|
|
574
|
+
view.dispatch(tr);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
477
578
|
function detailsPlugin(context, options) {
|
|
478
579
|
if (options === void 0) { options = {}; }
|
|
479
580
|
var i18n = context.i18n, eventEmitter = context.eventEmitter;
|
|
480
581
|
addLangs(i18n);
|
|
481
582
|
var toolbarItem = createToolbarItemOption(i18n);
|
|
583
|
+
// Hook into the global keydown event for exit behavior
|
|
584
|
+
eventEmitter.listen('keydown', function (editorType, event) {
|
|
585
|
+
console.log('[Details Plugin] keydown via eventEmitter!', { editorType: editorType, key: event.key });
|
|
586
|
+
if (editorType !== 'wysiwyg') {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (event.key !== 'Enter' && event.key !== 'ArrowDown') {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
handleDetailsExit(context, event);
|
|
593
|
+
});
|
|
482
594
|
return {
|
|
595
|
+
toHTMLRenderers: {
|
|
596
|
+
htmlBlock: {
|
|
597
|
+
renderer: function (node) {
|
|
598
|
+
var isDetails = /<(\/)?(details|summary)/i.test(node.literal || '');
|
|
599
|
+
return isDetails
|
|
600
|
+
? [{ type: 'html', content: node.literal || '' }]
|
|
601
|
+
: [
|
|
602
|
+
{ type: 'openTag', tagName: 'div', outerNewLine: true },
|
|
603
|
+
{ type: 'html', content: node.literal || '' },
|
|
604
|
+
{ type: 'closeTag', tagName: 'div', outerNewLine: true },
|
|
605
|
+
];
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
},
|
|
483
609
|
markdownCommands: {
|
|
484
610
|
details: function (payload, _a, dispatch) {
|
|
485
611
|
var tr = _a.tr, selection = _a.selection, schema = _a.schema;
|
|
486
|
-
var from = selection.from, to = selection.to;
|
|
487
612
|
var slice = selection.content();
|
|
488
613
|
var textContent = slice.content.textBetween(0, slice.content.size, '\n') || i18n.get('content');
|
|
489
614
|
var summaryText = i18n.get('summary');
|
|
@@ -495,25 +620,14 @@ function detailsPlugin(context, options) {
|
|
|
495
620
|
return true;
|
|
496
621
|
},
|
|
497
622
|
},
|
|
498
|
-
toHTMLRenderers: {
|
|
499
|
-
htmlBlock: {
|
|
500
|
-
details: function (node) { return [
|
|
501
|
-
{ type: 'openTag', tagName: 'details', outerNewLine: true },
|
|
502
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
503
|
-
{ type: 'closeTag', tagName: 'details', outerNewLine: true },
|
|
504
|
-
]; },
|
|
505
|
-
summary: function (node) { return [
|
|
506
|
-
{ type: 'openTag', tagName: 'summary', outerNewLine: true },
|
|
507
|
-
{ type: 'html', content: node.childrenHTML || '' },
|
|
508
|
-
{ type: 'closeTag', tagName: 'summary', outerNewLine: true },
|
|
509
|
-
]; },
|
|
510
|
-
},
|
|
511
|
-
},
|
|
512
623
|
wysiwygNodeViews: {
|
|
513
624
|
details: function (node, view, getPos) {
|
|
514
625
|
var dom = document.createElement('details');
|
|
515
|
-
var htmlAttrs = node.attrs.htmlAttrs;
|
|
516
|
-
|
|
626
|
+
var htmlAttrs = (node.attrs && node.attrs.htmlAttrs) || {};
|
|
627
|
+
var isOpenAttr = node.attrs.open; // Core definition uses direct attribute
|
|
628
|
+
// Check both direct attribute (priority) and htmlAttrs (legacy/plugin)
|
|
629
|
+
var isOpen = isOpenAttr === true || (htmlAttrs && htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined');
|
|
630
|
+
if (isOpen) {
|
|
517
631
|
dom.open = true;
|
|
518
632
|
}
|
|
519
633
|
dom.addEventListener('click', function (e) {
|
|
@@ -522,87 +636,16 @@ function detailsPlugin(context, options) {
|
|
|
522
636
|
e.preventDefault();
|
|
523
637
|
var pos = getPos();
|
|
524
638
|
if (typeof pos === 'number') {
|
|
525
|
-
var
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
});
|
|
530
|
-
// Simplified keydown handler with better logic
|
|
531
|
-
dom.addEventListener('keydown', function (e) {
|
|
532
|
-
var state = view.state;
|
|
533
|
-
var selection = state.selection;
|
|
534
|
-
var pos = getPos();
|
|
535
|
-
if (typeof pos !== 'number') {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
// Get fresh node
|
|
539
|
-
var currentNode = state.doc.nodeAt(pos);
|
|
540
|
-
if (!currentNode || currentNode.type.name !== 'details') {
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
// Calculate end position
|
|
544
|
-
var endPos = pos + currentNode.nodeSize;
|
|
545
|
-
// Get TextSelection constructor
|
|
546
|
-
var SelectionCtor = state.selection.constructor;
|
|
547
|
-
// Handle Enter key
|
|
548
|
-
if (e.key === 'Enter') {
|
|
549
|
-
var $from = selection.$from;
|
|
550
|
-
// Check if we're in an empty paragraph
|
|
551
|
-
if ($from.parent.type.name === 'paragraph' && $from.parent.content.size === 0) {
|
|
552
|
-
// Get position after this paragraph
|
|
553
|
-
var afterPara = $from.after();
|
|
554
|
-
// Check if this empty paragraph is the last thing in the details block
|
|
555
|
-
// endPos - 1 is the position just before the closing tag
|
|
556
|
-
if (afterPara >= endPos - 1) {
|
|
557
|
-
e.preventDefault();
|
|
558
|
-
e.stopPropagation();
|
|
559
|
-
var tr = state.tr, schema = state.schema;
|
|
560
|
-
// Delete the empty paragraph
|
|
561
|
-
var beforePara = $from.before();
|
|
562
|
-
tr.delete(beforePara, afterPara);
|
|
563
|
-
// Insert new paragraph after the details block
|
|
564
|
-
var p = schema.nodes.paragraph.createAndFill();
|
|
565
|
-
var insertPos = endPos - (afterPara - beforePara);
|
|
566
|
-
tr.insert(insertPos, p);
|
|
567
|
-
// Move cursor into new paragraph
|
|
568
|
-
if (SelectionCtor && SelectionCtor.near) {
|
|
569
|
-
tr.setSelection(SelectionCtor.near(tr.doc.resolve(insertPos + 1)));
|
|
570
|
-
}
|
|
571
|
-
view.dispatch(tr);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
// Handle ArrowDown key
|
|
576
|
-
if (e.key === 'ArrowDown') {
|
|
577
|
-
var $from = selection.$from;
|
|
578
|
-
// Check if cursor is at the end of its parent node
|
|
579
|
-
var atEndOfParent = $from.parentOffset === $from.parent.content.size;
|
|
580
|
-
if (!atEndOfParent) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
// Check if parent is the last child in details
|
|
584
|
-
var afterPara = $from.after();
|
|
585
|
-
if (afterPara >= endPos - 1) {
|
|
586
|
-
e.preventDefault();
|
|
587
|
-
e.stopPropagation();
|
|
588
|
-
var tr = state.tr, schema = state.schema;
|
|
589
|
-
// Try to move to position after details block
|
|
590
|
-
if (endPos < state.doc.content.size) {
|
|
591
|
-
// There's content after, just move there
|
|
592
|
-
if (SelectionCtor && SelectionCtor.near) {
|
|
593
|
-
tr.setSelection(SelectionCtor.near(tr.doc.resolve(endPos)));
|
|
594
|
-
view.dispatch(tr);
|
|
595
|
-
}
|
|
639
|
+
var isOpen_1 = htmlAttrs.open !== null && typeof htmlAttrs.open !== 'undefined';
|
|
640
|
+
var newHtmlAttrs = __assign({}, htmlAttrs);
|
|
641
|
+
if (isOpen_1) {
|
|
642
|
+
delete newHtmlAttrs.open;
|
|
596
643
|
}
|
|
597
644
|
else {
|
|
598
|
-
|
|
599
|
-
var p = schema.nodes.paragraph.createAndFill();
|
|
600
|
-
tr.insert(endPos, p);
|
|
601
|
-
if (SelectionCtor && SelectionCtor.near) {
|
|
602
|
-
tr.setSelection(SelectionCtor.near(tr.doc.resolve(endPos + 1)));
|
|
603
|
-
}
|
|
604
|
-
view.dispatch(tr);
|
|
645
|
+
newHtmlAttrs.open = '';
|
|
605
646
|
}
|
|
647
|
+
var newAttrs = __assign(__assign({}, node.attrs), { htmlAttrs: newHtmlAttrs });
|
|
648
|
+
view.dispatch(view.state.tr.setNodeMarkup(pos, null, newAttrs));
|
|
606
649
|
}
|
|
607
650
|
}
|
|
608
651
|
});
|
|
@@ -611,15 +654,15 @@ function detailsPlugin(context, options) {
|
|
|
611
654
|
},
|
|
612
655
|
wysiwygCommands: {
|
|
613
656
|
details: function (payload, _a, dispatch) {
|
|
614
|
-
var tr = _a.tr,
|
|
657
|
+
var tr = _a.tr, schema = _a.schema;
|
|
615
658
|
var summaryText = i18n.get('summary');
|
|
616
659
|
var contentText = i18n.get('content');
|
|
617
660
|
var _b = schema.nodes, details = _b.details, summary = _b.summary, paragraph = _b.paragraph;
|
|
618
661
|
if (details && summary && paragraph) {
|
|
619
662
|
var summaryNode = summary.create({}, schema.text(summaryText));
|
|
620
663
|
var contentNode = paragraph.create({}, schema.text(contentText));
|
|
621
|
-
var
|
|
622
|
-
tr.replaceSelectionWith(
|
|
664
|
+
var detailsNode = details.create({}, [summaryNode, contentNode]);
|
|
665
|
+
tr.replaceSelectionWith(detailsNode);
|
|
623
666
|
dispatch(tr);
|
|
624
667
|
return true;
|
|
625
668
|
}
|
|
@@ -628,8 +671,8 @@ function detailsPlugin(context, options) {
|
|
|
628
671
|
},
|
|
629
672
|
toolbarItems: [
|
|
630
673
|
{
|
|
631
|
-
groupIndex:
|
|
632
|
-
itemIndex:
|
|
674
|
+
groupIndex: 4,
|
|
675
|
+
itemIndex: 3,
|
|
633
676
|
item: toolbarItem,
|
|
634
677
|
},
|
|
635
678
|
],
|
package/package.json
CHANGED
package/src/css/plugin.css
CHANGED
|
@@ -7,7 +7,30 @@
|
|
|
7
7
|
text-indent: -9999px !important;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
details {
|
|
11
|
+
display: block;
|
|
12
|
+
background-color: #f7f7f7;
|
|
13
|
+
border: 1px solid #e1e1e1;
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
margin: 10px 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
summary {
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
font-weight: bold;
|
|
22
|
+
margin-bottom: 5px;
|
|
23
|
+
outline: none;
|
|
24
|
+
}
|
|
25
|
+
|
|
10
26
|
/* Dark Mode */
|
|
11
27
|
.toastui-editor-dark .toastui-editor-toolbar-icons.details {
|
|
12
28
|
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 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'/%3E%3Cpath d='M9 10L12 13 15 10' stroke='%23eee'/%3E%3C/svg%3E") !important;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.toastui-editor-dark details {
|
|
32
|
+
background-color: #282a36;
|
|
33
|
+
/* Darker background for contrast against editor bg */
|
|
34
|
+
border-color: #44475a;
|
|
35
|
+
color: #f8f8f2;
|
|
13
36
|
}
|