@@ -93,6 +93,10 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
9393 + ' <div class="annotationSearchContainer contextButtonContainer">'
9494 + ' </div>'
9595 + ' </div>'
96+ + ' <div class="layoutAreasButton playerControl">'
97+ + ' <span class="icon-th-large-1"></span>'
98+ + ' <div class="layoutAreasPanel"></div>'
99+ + ' </div>'
96100 + ' <div class="captionsButton playerControl">'
97101 + ' <span class="icon-captions-off"></span>'
98102 + ' <div class="captionSelectContainer">'
@@ -339,23 +343,161 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
339343 }
340344 }
341345
342- Controls . querySelector ( '.captionsButton' ) . addEventListener ( 'click' , function ( ) {
346+ var layoutAreasButton = Controls . querySelector ( '.layoutAreasButton' ) ;
347+ var layoutAreasPanel = layoutAreasButton . querySelector ( '.layoutAreasPanel' ) ;
348+ layoutAreasButton . style . display = 'none' ;
349+
350+ layoutAreasButton . addEventListener ( 'click' , function ( evt ) {
351+ evt . stopPropagation ( ) ;
352+
353+ Controls . querySelectorAll ( '.rightControlPanel .active:not([data-config]):not(.layoutAreasButton):not(.layoutAreasPanel)' ) . forEach ( function ( el ) { el . classList . remove ( 'active' ) ; } ) ;
354+ closeCaptionPanel ( ) ;
355+
356+ if ( ! layoutAreasPanel . classList . contains ( 'active' ) ) {
357+ updateLayoutAreasPanel ( ) ;
358+ layoutAreasPanel . classList . add ( 'active' ) ;
359+ addOutsideClickHandler ( ) ;
360+ } else {
361+ layoutAreasPanel . classList . remove ( 'active' ) ;
362+ }
363+
364+ } ) ;
365+
366+ layoutAreasPanel . addEventListener ( 'click' , function ( evt ) {
367+ evt . stopPropagation ( ) ;
368+ } ) ;
369+
370+ function updateLayoutAreasPanel ( ) {
371+ layoutAreasPanel . innerHTML = '' ;
372+
373+ var schematic = document . createElement ( 'div' ) ;
374+ schematic . className = 'layoutAreasSchematic' ;
375+
376+ var hasTop = FrameTrail . getState ( 'hv_config_areaTopVisible' ) ;
377+ var hasBottom = FrameTrail . getState ( 'hv_config_areaBottomVisible' ) ;
378+ var hasLeft = FrameTrail . getState ( 'hv_config_areaLeftVisible' ) ;
379+ var hasRight = FrameTrail . getState ( 'hv_config_areaRightVisible' ) ;
380+
381+ if ( hasTop ) {
382+ var topEl = document . createElement ( 'div' ) ;
383+ topEl . className = 'schematicArea schematicAreaTop' ;
384+ topEl . setAttribute ( 'data-size' , AreaTopContainer . getAttribute ( 'data-size' ) || 'small' ) ;
385+ if ( ! AreaTopContainer . classList . contains ( 'closed' ) ) topEl . classList . add ( 'active' ) ;
386+ topEl . addEventListener ( 'click' , function ( ) {
387+ AreaTopContainer . classList . toggle ( 'closed' ) ;
388+ this . classList . toggle ( 'active' ) ;
389+ FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
390+ window . setTimeout ( function ( ) { adjustHypervideo ( ) ; } , 250 ) ;
391+ } ) ;
392+ schematic . appendChild ( topEl ) ;
393+ }
394+
395+ var middleRow = document . createElement ( 'div' ) ;
396+ middleRow . className = 'schematicMiddleRow' ;
397+
398+ if ( hasLeft ) {
399+ var leftEl = document . createElement ( 'div' ) ;
400+ leftEl . className = 'schematicArea schematicAreaLeft' ;
401+ leftEl . setAttribute ( 'data-size' , AreaLeftContainer . getAttribute ( 'data-size' ) || 'small' ) ;
402+ if ( ! AreaLeftContainer . classList . contains ( 'closed' ) ) leftEl . classList . add ( 'active' ) ;
403+ leftEl . addEventListener ( 'click' , function ( ) {
404+ AreaLeftContainer . classList . toggle ( 'closed' ) ;
405+ this . classList . toggle ( 'active' ) ;
406+ FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
407+ window . setTimeout ( function ( ) { adjustHypervideo ( ) ; } , 250 ) ;
408+ } ) ;
409+ middleRow . appendChild ( leftEl ) ;
410+ }
411+
412+ var centerEl = document . createElement ( 'div' ) ;
413+ centerEl . className = 'schematicCenter' ;
414+ centerEl . innerHTML = '<span class="icon-play-1"></span>' ;
415+ middleRow . appendChild ( centerEl ) ;
416+
417+ if ( hasRight ) {
418+ var rightEl = document . createElement ( 'div' ) ;
419+ rightEl . className = 'schematicArea schematicAreaRight' ;
420+ rightEl . setAttribute ( 'data-size' , AreaRightContainer . getAttribute ( 'data-size' ) || 'small' ) ;
421+ if ( ! AreaRightContainer . classList . contains ( 'closed' ) ) rightEl . classList . add ( 'active' ) ;
422+ rightEl . addEventListener ( 'click' , function ( ) {
423+ AreaRightContainer . classList . toggle ( 'closed' ) ;
424+ this . classList . toggle ( 'active' ) ;
425+ FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
426+ window . setTimeout ( function ( ) { adjustHypervideo ( ) ; } , 250 ) ;
427+ } ) ;
428+ middleRow . appendChild ( rightEl ) ;
429+ }
430+
431+ schematic . appendChild ( middleRow ) ;
432+
433+ if ( hasBottom ) {
434+ var bottomEl = document . createElement ( 'div' ) ;
435+ bottomEl . className = 'schematicArea schematicAreaBottom' ;
436+ bottomEl . setAttribute ( 'data-size' , AreaBottomContainer . getAttribute ( 'data-size' ) || 'small' ) ;
437+ if ( ! AreaBottomContainer . classList . contains ( 'closed' ) ) bottomEl . classList . add ( 'active' ) ;
438+ bottomEl . addEventListener ( 'click' , function ( ) {
439+ AreaBottomContainer . classList . toggle ( 'closed' ) ;
440+ this . classList . toggle ( 'active' ) ;
441+ FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
442+ window . setTimeout ( function ( ) { adjustHypervideo ( ) ; } , 250 ) ;
443+ } ) ;
444+ schematic . appendChild ( bottomEl ) ;
445+ }
446+
447+ layoutAreasPanel . appendChild ( schematic ) ;
448+ }
449+
450+ function updateLayoutAreasButtonVisibility ( ) {
451+ var hasAny = FrameTrail . getState ( 'hv_config_areaTopVisible' )
452+ || FrameTrail . getState ( 'hv_config_areaBottomVisible' )
453+ || FrameTrail . getState ( 'hv_config_areaLeftVisible' )
454+ || FrameTrail . getState ( 'hv_config_areaRightVisible' ) ;
455+ layoutAreasButton . style . display = hasAny ? '' : 'none' ;
456+ }
457+
458+ var captionsButton = Controls . querySelector ( '.captionsButton' ) ;
459+ var captionContainer = captionsButton . querySelector ( '.captionSelectContainer' ) ;
460+
461+ captionsButton . addEventListener ( 'click' , function ( evt ) {
462+ evt . stopPropagation ( ) ;
343463
344464 Controls . querySelectorAll ( '.rightControlPanel .active:not([data-config]):not(.captionsButton):not(.captionSelectContainer):not(.annotationSetButton)' ) . forEach ( function ( el ) { el . classList . remove ( 'active' ) ; } ) ;
465+ layoutAreasPanel . classList . remove ( 'active' ) ;
345466
346- var captionContainer = this . querySelector ( '.captionSelectContainer' ) ;
347467 if ( ! captionContainer . classList . contains ( 'active' ) ) {
348468 captionContainer . classList . add ( 'active' ) ;
349469 VideoContainer . style . opacity = '0.3' ;
350470 domElement . querySelectorAll ( '.areaLeftContainer, .areaRightContainer' ) . forEach ( function ( el ) { el . style . opacity = '0.3' ; } ) ;
471+ addOutsideClickHandler ( ) ;
351472 } else {
352- captionContainer . classList . remove ( 'active' ) ;
353- VideoContainer . style . opacity = '1' ;
354- domElement . querySelectorAll ( '.areaLeftContainer, .areaRightContainer' ) . forEach ( function ( el ) { el . style . opacity = '1' ; } ) ;
473+ closeCaptionPanel ( ) ;
355474 }
356475
357476 } ) ;
358477
478+ captionContainer . addEventListener ( 'click' , function ( evt ) {
479+ evt . stopPropagation ( ) ;
480+ } ) ;
481+
482+ function closeCaptionPanel ( ) {
483+ captionContainer . classList . remove ( 'active' ) ;
484+ VideoContainer . style . opacity = '1' ;
485+ domElement . querySelectorAll ( '.areaLeftContainer, .areaRightContainer' ) . forEach ( function ( el ) { el . style . opacity = '1' ; } ) ;
486+ }
487+
488+ function closeAllPanels ( ) {
489+ layoutAreasPanel . classList . remove ( 'active' ) ;
490+ closeCaptionPanel ( ) ;
491+ }
492+
493+ function addOutsideClickHandler ( ) {
494+ var handler = function ( ) {
495+ closeAllPanels ( ) ;
496+ document . removeEventListener ( 'click' , handler ) ;
497+ } ;
498+ document . addEventListener ( 'click' , handler ) ;
499+ }
500+
359501 Controls . querySelector ( '.captionSelect.none' ) . addEventListener ( 'click' , function ( ) {
360502 FrameTrail . changeState ( 'hv_config_captionsVisible' , false ) ;
361503 } ) ;
@@ -944,6 +1086,9 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
9441086 AreaLeftContainer . style . display = 'none' ;
9451087 AreaRightContainer . style . display = 'none' ;
9461088
1089+ layoutAreasButton . style . display = 'none' ;
1090+ layoutAreasPanel . classList . remove ( 'active' ) ;
1091+
9471092 // Timeline visibility is handled by CSS rules based on .editActive[data-edit-mode]
9481093 // Don't use .show() here as it sets inline display:block that persists after leaving edit mode
9491094
@@ -1080,6 +1225,7 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
10801225 if ( FrameTrail . getState ( 'slidePosition' ) != 'middle' ) {
10811226 FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
10821227 }
1228+ updateLayoutAreasButtonVisibility ( ) ;
10831229 } ;
10841230
10851231 /**
@@ -1100,6 +1246,7 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
11001246 if ( FrameTrail . getState ( 'slidePosition' ) != 'middle' ) {
11011247 FrameTrail . changeState ( 'slidePosition' , 'middle' ) ;
11021248 }
1249+ updateLayoutAreasButtonVisibility ( ) ;
11031250 } ;
11041251
11051252 /**
@@ -1117,6 +1264,7 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
11171264 } else {
11181265 AreaLeftContainer . style . display = 'none' ;
11191266 }
1267+ updateLayoutAreasButtonVisibility ( ) ;
11201268 } ;
11211269
11221270 /**
@@ -1134,6 +1282,7 @@ FrameTrail.defineModule('ViewVideo', function(FrameTrail){
11341282 } else {
11351283 AreaRightContainer . style . display = 'none' ;
11361284 }
1285+ updateLayoutAreasButtonVisibility ( ) ;
11371286 } ;
11381287
11391288 /**
0 commit comments