@@ -24,6 +24,11 @@ class ImportExportControls {
2424 constructor ( ) {
2525 this . previewRowLimit = 10 ;
2626 this . textEditMode = 'preview' ;
27+ this . defaultOptionsPanelWidthPx = 272 ;
28+ this . minOptionsPanelWidthPx = 180 ;
29+ this . maxOptionsPanelWidthPx = 520 ;
30+ this . currentOptionsPanelWidthPx = null ;
31+ this . _activeSplitDrag = null ;
2732 }
2833
2934 addHTMLtoGui ( parentelement ) {
@@ -293,6 +298,7 @@ class ImportExportControls {
293298
294299 const edit_area = document . querySelector ( 'div.edit-area' ) ;
295300 const optionsparent = document . querySelector ( 'div.options-parent' ) ;
301+ const splitter = document . querySelector ( 'div.options-preview-splitter' ) ;
296302 const text_area = document . getElementById ( 'markdown' ) ;
297303
298304 edit_area . style . width = '100%' ;
@@ -308,6 +314,9 @@ class ImportExportControls {
308314 console . log ( 'undefined panel type for ' + type ) ;
309315 edit_area . style . display = 'block' ;
310316 optionsparent . style . display = 'none' ;
317+ if ( splitter ) {
318+ splitter . style . display = 'none' ;
319+ }
311320 text_area . style . width = '100%' ;
312321 text_area . style . height = '100%' ;
313322 return ;
@@ -318,7 +327,7 @@ class ImportExportControls {
318327 text_area . style . width = '100%' ;
319328 text_area . style . height = '100%' ;
320329
321- optionsparent . style . width = '17em' ;
330+ this . _setOptionsPanelWidth ( optionsparent , this . _getInitialOptionsPanelWidthPx ( ) ) ;
322331 optionsparent . style . height = '100%' ;
323332
324333 optionsparent . innerHTML = '' ;
@@ -337,6 +346,7 @@ class ImportExportControls {
337346 }
338347
339348 optionsparent . style . display = 'block' ;
349+ this . _configureOptionsPreviewSplitter ( edit_area , optionsparent , splitter , text_area ) ;
340350 }
341351
342352 setOptionsApplyDirtyState ( optionsparent , isDirty ) {
@@ -476,6 +486,109 @@ class ImportExportControls {
476486 }
477487 importButton . disabled = this . isPreviewTextMode ( ) ;
478488 }
489+
490+ _configureOptionsPreviewSplitter ( editArea , optionsParent , splitter , textArea ) {
491+ if ( ! splitter || ! editArea || ! optionsParent || ! textArea ) {
492+ return ;
493+ }
494+
495+ splitter . style . display = 'block' ;
496+ textArea . style . flex = '1 1 auto' ;
497+
498+ if ( splitter . dataset . splitterInitialised === 'true' ) {
499+ return ;
500+ }
501+
502+ splitter . dataset . splitterInitialised = 'true' ;
503+ splitter . addEventListener ( 'pointerdown' , ( event ) => this . _beginSplitterDrag ( event , editArea , optionsParent ) ) ;
504+ }
505+
506+ _beginSplitterDrag ( event , editArea , optionsParent ) {
507+ if ( ! event || event . button > 0 ) {
508+ return ;
509+ }
510+
511+ const pointerId = event . pointerId ;
512+ const startX = event . clientX ;
513+ const startWidth = this . _readOptionsPanelWidthPx ( optionsParent ) ;
514+
515+ this . _activeSplitDrag = {
516+ pointerId,
517+ startX,
518+ startWidth,
519+ editArea,
520+ optionsParent,
521+ } ;
522+
523+ event . preventDefault ( ) ;
524+ document . body . classList . add ( 'is-resizing-split' ) ;
525+
526+ const onMove = ( moveEvent ) => this . _handleSplitterDragMove ( moveEvent ) ;
527+ const onEnd = ( endEvent ) => this . _endSplitterDrag ( endEvent , onMove , onEnd ) ;
528+ document . addEventListener ( 'pointermove' , onMove ) ;
529+ document . addEventListener ( 'pointerup' , onEnd ) ;
530+ document . addEventListener ( 'pointercancel' , onEnd ) ;
531+ }
532+
533+ _handleSplitterDragMove ( event ) {
534+ const dragState = this . _activeSplitDrag ;
535+ if ( ! dragState || event . pointerId !== dragState . pointerId ) {
536+ return ;
537+ }
538+
539+ event . preventDefault ( ) ;
540+ const deltaX = event . clientX - dragState . startX ;
541+ const requestedWidth = dragState . startWidth + deltaX ;
542+ const boundedWidth = this . _clampOptionsPanelWidth ( requestedWidth , dragState . editArea ) ;
543+ this . _setOptionsPanelWidth ( dragState . optionsParent , boundedWidth ) ;
544+ }
545+
546+ _endSplitterDrag ( event , onMove , onEnd ) {
547+ if ( ! this . _activeSplitDrag ) {
548+ return ;
549+ }
550+ if ( event && event . pointerId !== this . _activeSplitDrag . pointerId ) {
551+ return ;
552+ }
553+
554+ document . removeEventListener ( 'pointermove' , onMove ) ;
555+ document . removeEventListener ( 'pointerup' , onEnd ) ;
556+ document . removeEventListener ( 'pointercancel' , onEnd ) ;
557+ document . body . classList . remove ( 'is-resizing-split' ) ;
558+ this . _activeSplitDrag = null ;
559+ }
560+
561+ _setOptionsPanelWidth ( optionsParent , widthPx ) {
562+ const safeWidth = Math . round ( widthPx ) ;
563+ optionsParent . style . width = `${ safeWidth } px` ;
564+ optionsParent . style . minWidth = `${ safeWidth } px` ;
565+ optionsParent . style . maxWidth = `${ safeWidth } px` ;
566+ optionsParent . style . flex = '0 0 auto' ;
567+ this . currentOptionsPanelWidthPx = safeWidth ;
568+ }
569+
570+ _readOptionsPanelWidthPx ( optionsParent ) {
571+ const parsed = Number . parseFloat ( optionsParent ?. style ?. width || '' ) ;
572+ if ( Number . isFinite ( parsed ) ) {
573+ return parsed ;
574+ }
575+ return this . _getInitialOptionsPanelWidthPx ( ) ;
576+ }
577+
578+ _getInitialOptionsPanelWidthPx ( ) {
579+ if ( Number . isFinite ( this . currentOptionsPanelWidthPx ) ) {
580+ return this . currentOptionsPanelWidthPx ;
581+ }
582+ return this . defaultOptionsPanelWidthPx ;
583+ }
584+
585+ _clampOptionsPanelWidth ( widthPx , editArea ) {
586+ const editWidth = editArea ?. getBoundingClientRect ?. ( ) . width || 0 ;
587+ const maxByContainer =
588+ editWidth > 0 ? Math . max ( this . minOptionsPanelWidthPx , editWidth - 220 ) : this . maxOptionsPanelWidthPx ;
589+ const maxAllowed = Math . min ( this . maxOptionsPanelWidthPx , maxByContainer ) ;
590+ return Math . min ( Math . max ( widthPx , this . minOptionsPanelWidthPx ) , maxAllowed ) ;
591+ }
479592}
480593
481594export { ImportExportControls } ;
0 commit comments