@@ -24,6 +24,12 @@ 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 . minPreviewPanelWidthPx = 220 ;
31+ this . currentOptionsPanelWidthPx = null ;
32+ this . _activeSplitDrag = null ;
2733 }
2834
2935 addHTMLtoGui ( parentelement ) {
@@ -293,6 +299,7 @@ class ImportExportControls {
293299
294300 const edit_area = document . querySelector ( 'div.edit-area' ) ;
295301 const optionsparent = document . querySelector ( 'div.options-parent' ) ;
302+ const splitter = document . querySelector ( 'div.options-preview-splitter' ) ;
296303 const text_area = document . getElementById ( 'markdown' ) ;
297304
298305 edit_area . style . width = '100%' ;
@@ -308,6 +315,9 @@ class ImportExportControls {
308315 console . log ( 'undefined panel type for ' + type ) ;
309316 edit_area . style . display = 'block' ;
310317 optionsparent . style . display = 'none' ;
318+ if ( splitter ) {
319+ splitter . style . display = 'none' ;
320+ }
311321 text_area . style . width = '100%' ;
312322 text_area . style . height = '100%' ;
313323 return ;
@@ -318,7 +328,8 @@ class ImportExportControls {
318328 text_area . style . width = '100%' ;
319329 text_area . style . height = '100%' ;
320330
321- optionsparent . style . width = '17em' ;
331+ const initialWidth = this . _clampOptionsPanelWidth ( this . _getInitialOptionsPanelWidthPx ( ) , edit_area ) ;
332+ this . _setOptionsPanelWidth ( optionsparent , initialWidth ) ;
322333 optionsparent . style . height = '100%' ;
323334
324335 optionsparent . innerHTML = '' ;
@@ -337,6 +348,7 @@ class ImportExportControls {
337348 }
338349
339350 optionsparent . style . display = 'block' ;
351+ this . _configureOptionsPreviewSplitter ( edit_area , optionsparent , splitter , text_area ) ;
340352 }
341353
342354 setOptionsApplyDirtyState ( optionsparent , isDirty ) {
@@ -476,6 +488,165 @@ class ImportExportControls {
476488 }
477489 importButton . disabled = this . isPreviewTextMode ( ) ;
478490 }
491+
492+ _configureOptionsPreviewSplitter ( editArea , optionsParent , splitter , textArea ) {
493+ if ( ! splitter || ! editArea || ! optionsParent || ! textArea ) {
494+ return ;
495+ }
496+
497+ splitter . style . display = 'block' ;
498+ textArea . style . flex = '1 1 auto' ;
499+ this . _updateSplitterAriaValues ( splitter , optionsParent , editArea ) ;
500+
501+ if ( splitter . dataset . splitterInitialised === 'true' ) {
502+ return ;
503+ }
504+
505+ splitter . dataset . splitterInitialised = 'true' ;
506+ splitter . addEventListener ( 'pointerdown' , ( event ) => this . _beginSplitterDrag ( event , editArea , optionsParent ) ) ;
507+ splitter . addEventListener ( 'keydown' , ( event ) =>
508+ this . _handleSplitterKeyDown ( event , optionsParent , editArea , splitter )
509+ ) ;
510+ }
511+
512+ _beginSplitterDrag ( event , editArea , optionsParent ) {
513+ if ( ! event || event . button > 0 ) {
514+ return ;
515+ }
516+ if ( this . _activeSplitDrag ) {
517+ return ;
518+ }
519+
520+ const pointerId = event . pointerId ;
521+ const startX = event . clientX ;
522+ const startWidth = this . _readOptionsPanelWidthPx ( optionsParent ) ;
523+
524+ this . _activeSplitDrag = {
525+ pointerId,
526+ startX,
527+ startWidth,
528+ editArea,
529+ optionsParent,
530+ } ;
531+
532+ event . preventDefault ( ) ;
533+ document . body . classList . add ( 'is-resizing-split' ) ;
534+
535+ const onMove = ( moveEvent ) => this . _handleSplitterDragMove ( moveEvent ) ;
536+ const onEnd = ( endEvent ) => this . _endSplitterDrag ( endEvent , onMove , onEnd ) ;
537+ document . addEventListener ( 'pointermove' , onMove ) ;
538+ document . addEventListener ( 'pointerup' , onEnd ) ;
539+ document . addEventListener ( 'pointercancel' , onEnd ) ;
540+ }
541+
542+ _handleSplitterDragMove ( event ) {
543+ const dragState = this . _activeSplitDrag ;
544+ if ( ! dragState || event . pointerId !== dragState . pointerId ) {
545+ return ;
546+ }
547+
548+ event . preventDefault ( ) ;
549+ const deltaX = event . clientX - dragState . startX ;
550+ const requestedWidth = dragState . startWidth + deltaX ;
551+ const boundedWidth = this . _clampOptionsPanelWidth ( requestedWidth , dragState . editArea ) ;
552+ this . _setOptionsPanelWidth ( dragState . optionsParent , boundedWidth ) ;
553+ const splitter = document . querySelector ( 'div.options-preview-splitter' ) ;
554+ if ( splitter ) {
555+ this . _updateSplitterAriaValues ( splitter , dragState . optionsParent , dragState . editArea ) ;
556+ }
557+ }
558+
559+ _endSplitterDrag ( event , onMove , onEnd ) {
560+ if ( ! this . _activeSplitDrag ) {
561+ return ;
562+ }
563+ if ( event && event . pointerId !== this . _activeSplitDrag . pointerId ) {
564+ return ;
565+ }
566+
567+ document . removeEventListener ( 'pointermove' , onMove ) ;
568+ document . removeEventListener ( 'pointerup' , onEnd ) ;
569+ document . removeEventListener ( 'pointercancel' , onEnd ) ;
570+ document . body . classList . remove ( 'is-resizing-split' ) ;
571+ this . _activeSplitDrag = null ;
572+ }
573+
574+ _setOptionsPanelWidth ( optionsParent , widthPx ) {
575+ const safeWidth = Math . round ( widthPx ) ;
576+ optionsParent . style . width = `${ safeWidth } px` ;
577+ optionsParent . style . minWidth = `${ safeWidth } px` ;
578+ optionsParent . style . maxWidth = `${ safeWidth } px` ;
579+ optionsParent . style . flex = '0 0 auto' ;
580+ this . currentOptionsPanelWidthPx = safeWidth ;
581+ }
582+
583+ _handleSplitterKeyDown ( event , optionsParent , editArea , splitter ) {
584+ if ( ! event ) {
585+ return ;
586+ }
587+
588+ const step = event . shiftKey ? 24 : 12 ;
589+ let requestedWidth = this . _readOptionsPanelWidthPx ( optionsParent ) ;
590+ let handled = true ;
591+
592+ if ( event . key === 'ArrowLeft' ) {
593+ requestedWidth -= step ;
594+ } else if ( event . key === 'ArrowRight' ) {
595+ requestedWidth += step ;
596+ } else if ( event . key === 'Home' ) {
597+ requestedWidth = this . minOptionsPanelWidthPx ;
598+ } else if ( event . key === 'End' ) {
599+ requestedWidth = this . maxOptionsPanelWidthPx ;
600+ } else {
601+ handled = false ;
602+ }
603+
604+ if ( ! handled ) {
605+ return ;
606+ }
607+
608+ event . preventDefault ( ) ;
609+ const boundedWidth = this . _clampOptionsPanelWidth ( requestedWidth , editArea ) ;
610+ this . _setOptionsPanelWidth ( optionsParent , boundedWidth ) ;
611+ this . _updateSplitterAriaValues ( splitter , optionsParent , editArea ) ;
612+ }
613+
614+ _readOptionsPanelWidthPx ( optionsParent ) {
615+ const parsed = Number . parseFloat ( optionsParent ?. style ?. width || '' ) ;
616+ if ( Number . isFinite ( parsed ) ) {
617+ return parsed ;
618+ }
619+ return this . _getInitialOptionsPanelWidthPx ( ) ;
620+ }
621+
622+ _getInitialOptionsPanelWidthPx ( ) {
623+ if ( Number . isFinite ( this . currentOptionsPanelWidthPx ) ) {
624+ return this . currentOptionsPanelWidthPx ;
625+ }
626+ return this . defaultOptionsPanelWidthPx ;
627+ }
628+
629+ _clampOptionsPanelWidth ( widthPx , editArea ) {
630+ const editWidth = editArea ?. getBoundingClientRect ?. ( ) . width || 0 ;
631+ const maxByContainer =
632+ editWidth > 0
633+ ? Math . max ( this . minOptionsPanelWidthPx , editWidth - this . minPreviewPanelWidthPx )
634+ : this . maxOptionsPanelWidthPx ;
635+ const maxAllowed = Math . min ( this . maxOptionsPanelWidthPx , maxByContainer ) ;
636+ return Math . min ( Math . max ( widthPx , this . minOptionsPanelWidthPx ) , maxAllowed ) ;
637+ }
638+
639+ _updateSplitterAriaValues ( splitter , optionsParent , editArea ) {
640+ if ( ! splitter ) {
641+ return ;
642+ }
643+ const min = this . minOptionsPanelWidthPx ;
644+ const max = this . _clampOptionsPanelWidth ( this . maxOptionsPanelWidthPx , editArea ) ;
645+ const now = this . _clampOptionsPanelWidth ( this . _readOptionsPanelWidthPx ( optionsParent ) , editArea ) ;
646+ splitter . setAttribute ( 'aria-valuemin' , `${ min } ` ) ;
647+ splitter . setAttribute ( 'aria-valuemax' , `${ max } ` ) ;
648+ splitter . setAttribute ( 'aria-valuenow' , `${ now } ` ) ;
649+ }
479650}
480651
481652export { ImportExportControls } ;
0 commit comments