1212 * window.L.Control.PartsPreview
1313 */
1414
15- /* global _ app $ Hammer _UNO cool */
15+ /* global _ app $ Hammer _UNO cool JSDialog */
1616window . L . Control . PartsPreview = window . L . Control . extend ( {
1717 options : {
1818 fetchThumbnail : true ,
@@ -44,6 +44,7 @@ window.L.Control.PartsPreview = window.L.Control.extend({
4444 this . _width = 0 ;
4545 this . _height = 0 ;
4646 this . scrollTimer = null ;
47+ this . _menuPosEl = null ;
4748
4849 document . body . addEventListener ( 'click' , ( e ) => {
4950 if ( ! e . partsFocusedApplied && this . partsFocused )
@@ -181,6 +182,16 @@ window.L.Control.PartsPreview = window.L.Control.extend({
181182 return ! ( ( x > nLeft && x < width - nRight ) && ( y > nTop && y < height - nBottom ) ) ;
182183 } ,
183184
185+ _getMenuPosEl : function ( ) {
186+ if ( ! this . _menuPosEl ) {
187+ this . _menuPosEl = document . createElement ( 'div' ) ;
188+ this . _menuPosEl . id = 'slide-context-menu-pos' ;
189+ this . _menuPosEl . style . position = 'absolute' ;
190+ this . _container . appendChild ( this . _menuPosEl ) ;
191+ }
192+ return this . _menuPosEl ;
193+ } ,
194+
184195 _createPreview : function ( i , hashCode ) {
185196 var frameClass = 'preview-frame ' + this . options . frameClass ;
186197 var frame = window . L . DomUtil . create ( 'div' , frameClass , this . _partsPreviewCont ) ;
@@ -245,12 +256,9 @@ window.L.Control.PartsPreview = window.L.Control.extend({
245256 var that = this ;
246257 window . L . DomEvent . on ( frame , 'contextmenu' , function ( e ) {
247258 var isMasterView = this . _map [ 'stateChangeHandler' ] . getItemValue ( '.uno:SlideMasterPage' ) ;
248- var pcw = document . getElementById ( 'presentation-controls-wrapper' ) ;
249- var $trigger = $ ( pcw ) ;
250- if ( isMasterView === 'true' || app . map . isReadOnlyMode ( ) ) {
251- $trigger . contextMenu ( false ) ;
259+ if ( isMasterView === 'true' || app . map . isReadOnlyMode ( ) )
252260 return ;
253- }
261+ e . preventDefault ( ) ;
254262
255263 var nPos = undefined ;
256264 if ( this . isPaddingClick ( frame , e , 'top' ) )
@@ -260,137 +268,187 @@ window.L.Control.PartsPreview = window.L.Control.extend({
260268 else if ( this . isPaddingClick ( frame , e , 'right' ) || this . isPaddingClick ( frame , e , 'left' ) )
261269 nPos = that . _findClickedPart ( frame ) ;
262270
263- $trigger . contextMenu ( true ) ;
264271 if ( ! that . _isSelected ( e ) )
265272 that . _setPart ( e ) ;
266- $ . contextMenu ( {
267- selector : '#' + frame . id ,
268- className : 'cool-font' ,
269- items : {
270- paste : {
271- name : app . IconUtil . createMenuItemLink ( _ ( 'Paste' ) , 'Paste' ) ,
272- isHtmlName : true ,
273- callback : function ( key , options ) {
274- if ( nPos === undefined )
275- nPos = that . _findClickedPart ( options . $trigger [ 0 ] ) ;
276- that . _pasteSlide ( nPos ) ;
277- } ,
278- visible : function ( ) {
279- // Show paste if we have a local copied slide OR
280- // the system clipboard API is available (may have content from another tab)
281- return that . copiedSlide || window . L . Browser . clipboardApiAvailable ;
282- }
283- } ,
284- newslide : {
285- name : app . IconUtil . createMenuItemLink ( _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:InsertSlide' : '.uno:InsertPage' , 'presentation' ) , 'InsertPage' ) ,
286- isHtmlName : true ,
287- callback : function ( ) { that . _map . insertPage ( nPos ) ; }
288- }
289- } ,
290- events : {
291- hide : function ( ) {
292- img . focus ( ) ;
293- }
294- }
273+ img . focus ( ) ;
274+
275+ var entries = [ ] ;
276+ if ( that . copiedSlide || window . L . Browser . clipboardApiAvailable ) {
277+ entries . push ( {
278+ id : 'paste' ,
279+ type : 'comboboxentry' ,
280+ text : _ ( 'Paste' ) ,
281+ img : 'Paste' ,
282+ pos : 0 ,
283+ } ) ;
284+ }
285+ entries . push ( {
286+ id : 'newslide' ,
287+ type : 'comboboxentry' ,
288+ text : _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:InsertSlide' : '.uno:InsertPage' , 'presentation' ) ,
289+ img : 'InsertPage' ,
290+ pos : 0 ,
295291 } ) ;
292+
293+ var menuPosEl = that . _getMenuPosEl ( ) ;
294+ var rect = that . _container . getBoundingClientRect ( ) ;
295+ menuPosEl . style . left = ( e . clientX - rect . left ) + 'px' ;
296+ menuPosEl . style . top = ( e . clientY - rect . top ) + 'px' ;
297+
298+ var callback = function ( objectType , eventType , object , data , entry ) {
299+ if ( eventType !== 'selected' )
300+ return false ;
301+ if ( entry . id === 'paste' ) {
302+ if ( nPos === undefined )
303+ nPos = that . _findClickedPart ( frame ) ;
304+ that . _pasteSlide ( nPos ) ;
305+ } else if ( entry . id === 'newslide' ) {
306+ that . _map . insertPage ( nPos ) ;
307+ }
308+ JSDialog . CloseAllDropdowns ( ) ;
309+ return true ;
310+ } ;
311+
312+ JSDialog . OpenDropdown (
313+ 'slide-frame-menu' ,
314+ menuPosEl ,
315+ entries ,
316+ callback ,
317+ '' ,
318+ false ,
319+ ) ;
296320 } , this ) ;
297321
298322 window . L . DomEvent . on ( img , 'contextmenu' , function ( e ) {
323+ e . stopPropagation ( ) ;
299324 var isMasterView = this . _map [ 'stateChangeHandler' ] . getItemValue ( '.uno:SlideMasterPage' ) ;
300- var $trigger = $ ( '#' + img . id ) ;
301- if ( isMasterView === 'true' || app . map . isReadOnlyMode ( ) ) {
302- $trigger . contextMenu ( false ) ;
325+ if ( isMasterView === 'true' || app . map . isReadOnlyMode ( ) )
303326 return ;
304- }
305- $trigger . contextMenu ( true ) ;
327+ e . preventDefault ( ) ;
328+
306329 if ( ! that . _isSelected ( e ) )
307330 that . _setPart ( e ) ;
331+ img . focus ( ) ;
308332
309- $ . contextMenu ( {
310- selector : '#' + img . id ,
311- className : 'cool-font' ,
312- items : {
313- copy : {
314- name : app . IconUtil . createMenuItemLink ( _ ( 'Copy' ) , 'Copy' ) ,
315- isHtmlName : true ,
316- callback : function ( ) {
317- that . copiedSlide = e ;
318- that . _map . _clip . clearSelection ( ) ;
319- that . _map . _clip . setTextSelectionType ( 'slide' ) ;
320- that . _map . _clip . _execCopyCutPaste ( 'copy' , '.uno:CopySlide' ) ;
321- } ,
322- visible : function ( ) {
323- return ! ( app . impress . hasOverviewPage && that . _map . _docLayer . _selectedPart === 0 ) ;
324- }
325- } ,
326- paste : {
327- name : app . IconUtil . createMenuItemLink ( _ ( 'Paste' ) , 'Paste' ) ,
328- isHtmlName : true ,
329- callback : function ( ) {
330- that . _pasteSlide ( ) ;
331- } ,
332- } ,
333- newslide : {
334- name : app . IconUtil . createMenuItemLink ( _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:InsertSlide' : '.uno:InsertPage' , 'presentation' ) , 'InsertPage' ) ,
335- isHtmlName : true ,
336- callback : function ( ) { that . _map . insertPage ( ) ; }
337- } ,
338- duplicateslide : {
339- name : app . IconUtil . createMenuItemLink ( _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:DuplicateSlide' : '.uno:DuplicatePage' , 'presentation' ) , 'DuplicatePage' ) ,
340- isHtmlName : true ,
341- callback : function ( ) { that . _map . duplicatePage ( ) ; }
342- } ,
343- delete : {
344- name : app . IconUtil . createMenuItemLink ( _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:DeleteSlide' : '.uno:DeletePage' , 'presentation' ) , 'DeletePage' ) ,
345- isHtmlName : true ,
346- callback : function ( ) { app . dispatcher . dispatch ( 'deletepage' ) ; } ,
347- visible : function ( ) {
348- return that . _map . _docLayer . _parts > 1 ;
349- }
350- } ,
351- slideproperties : {
352- name : app . IconUtil . createMenuItemLink ( _UNO ( that . _map . _docLayer . _docType == 'presentation' ? '.uno:SlideSetup' : '.uno:PageSetup' , 'presentation' ) , 'PageSetup' ) ,
353- isHtmlName : true ,
354- callback : function ( ) {
355- app . socket . sendMessage ( 'uno .uno:PageSetup' ) ;
356- }
357- } ,
358- showslide : {
359- name : app . IconUtil . createMenuItemLink ( _UNO ( '.uno:ShowSlide' , 'presentation' ) , 'ShowSlide' ) ,
360- isHtmlName : true ,
361- callback : function ( key , options ) {
362- var part = that . _findClickedPart ( options . $trigger [ 0 ] . parentNode ) ;
363- if ( part !== null ) {
364- that . _map . showSlide ( ) ;
365- }
366- } ,
367- visible : function ( key , options ) {
368- var part = that . _findClickedPart ( options . $trigger [ 0 ] . parentNode ) ;
369- return that . _map . _docLayer . _docType === 'presentation' && app . impress . isSlideHidden ( parseInt ( part ) - 1 ) ;
370- }
371- } ,
372- hideslide : {
373- name : app . IconUtil . createMenuItemLink ( _UNO ( '.uno:HideSlide' , 'presentation' ) , 'Hideslide' ) ,
374- isHtmlName : true ,
375- callback : function ( key , options ) {
376- var part = that . _findClickedPart ( options . $trigger [ 0 ] . parentNode ) ;
377- if ( part !== null ) {
378- that . _map . hideSlide ( ) ;
379- }
380- } ,
381- visible : function ( key , options ) {
382- var part = that . _findClickedPart ( options . $trigger [ 0 ] . parentNode ) ;
383- return that . _map . _docLayer . _docType === 'presentation' && ! app . impress . isSlideHidden ( parseInt ( part ) - 1 ) ;
384- }
385- }
386- } ,
387- events : {
388- hide : function ( ) {
389- // Restore focus to the element that opened the menu
390- img . focus ( ) ;
391- }
392- }
333+ var part = that . _findClickedPart ( img . parentNode ) ;
334+ var partIndex = parseInt ( part ) - 1 ;
335+ var isPresentation = that . _map . _docLayer . _docType === 'presentation' ;
336+
337+ var entries = [ ] ;
338+ if ( ! ( app . impress . hasOverviewPage && that . _map . _docLayer . _selectedPart === 0 ) ) {
339+ entries . push ( {
340+ id : 'copy' ,
341+ type : 'comboboxentry' ,
342+ text : _ ( 'Copy' ) ,
343+ img : 'Copy' ,
344+ pos : 0 ,
345+ } ) ;
346+ }
347+ entries . push ( {
348+ id : 'paste' ,
349+ type : 'comboboxentry' ,
350+ text : _ ( 'Paste' ) ,
351+ img : 'Paste' ,
352+ pos : 0 ,
353+ } ) ;
354+ entries . push ( {
355+ id : 'newslide' ,
356+ type : 'comboboxentry' ,
357+ text : _UNO ( isPresentation ? '.uno:InsertSlide' : '.uno:InsertPage' , 'presentation' ) ,
358+ img : 'InsertPage' ,
359+ pos : 0 ,
360+ } ) ;
361+ entries . push ( {
362+ id : 'duplicateslide' ,
363+ type : 'comboboxentry' ,
364+ text : _UNO ( isPresentation ? '.uno:DuplicateSlide' : '.uno:DuplicatePage' , 'presentation' ) ,
365+ img : 'DuplicatePage' ,
366+ pos : 0 ,
367+ } ) ;
368+ if ( that . _map . _docLayer . _parts > 1 ) {
369+ entries . push ( {
370+ id : 'delete' ,
371+ type : 'comboboxentry' ,
372+ text : _UNO ( isPresentation ? '.uno:DeleteSlide' : '.uno:DeletePage' , 'presentation' ) ,
373+ img : 'DeletePage' ,
374+ pos : 0 ,
375+ } ) ;
376+ }
377+ entries . push ( {
378+ id : 'slideproperties' ,
379+ type : 'comboboxentry' ,
380+ text : _UNO ( isPresentation ? '.uno:SlideSetup' : '.uno:PageSetup' , 'presentation' ) ,
381+ img : 'PageSetup' ,
382+ pos : 0 ,
393383 } ) ;
384+ if ( isPresentation && app . impress . isSlideHidden ( partIndex ) ) {
385+ entries . push ( {
386+ id : 'showslide' ,
387+ type : 'comboboxentry' ,
388+ text : _UNO ( '.uno:ShowSlide' , 'presentation' ) ,
389+ img : 'ShowSlide' ,
390+ pos : 0 ,
391+ } ) ;
392+ }
393+ if ( isPresentation && ! app . impress . isSlideHidden ( partIndex ) ) {
394+ entries . push ( {
395+ id : 'hideslide' ,
396+ type : 'comboboxentry' ,
397+ text : _UNO ( '.uno:HideSlide' , 'presentation' ) ,
398+ img : 'Hideslide' ,
399+ pos : 0 ,
400+ } ) ;
401+ }
402+
403+ var menuPosEl = that . _getMenuPosEl ( ) ;
404+ var rect = that . _container . getBoundingClientRect ( ) ;
405+ menuPosEl . style . left = ( e . clientX - rect . left ) + 'px' ;
406+ menuPosEl . style . top = ( e . clientY - rect . top ) + 'px' ;
407+
408+ var callback = function ( objectType , eventType , object , data , entry ) {
409+ if ( eventType !== 'selected' )
410+ return false ;
411+ switch ( entry . id ) {
412+ case 'copy' :
413+ that . copiedSlide = e ;
414+ that . _map . _clip . clearSelection ( ) ;
415+ that . _map . _clip . setTextSelectionType ( 'slide' ) ;
416+ that . _map . _clip . _execCopyCutPaste ( 'copy' , '.uno:CopySlide' ) ;
417+ break ;
418+ case 'paste' :
419+ that . _pasteSlide ( ) ;
420+ break ;
421+ case 'newslide' :
422+ that . _map . insertPage ( ) ;
423+ break ;
424+ case 'duplicateslide' :
425+ that . _map . duplicatePage ( ) ;
426+ break ;
427+ case 'delete' :
428+ app . dispatcher . dispatch ( 'deletepage' ) ;
429+ break ;
430+ case 'slideproperties' :
431+ app . socket . sendMessage ( 'uno .uno:PageSetup' ) ;
432+ break ;
433+ case 'showslide' :
434+ that . _map . showSlide ( ) ;
435+ break ;
436+ case 'hideslide' :
437+ that . _map . hideSlide ( ) ;
438+ break ;
439+ }
440+ JSDialog . CloseAllDropdowns ( ) ;
441+ return true ;
442+ } ;
443+
444+ JSDialog . OpenDropdown (
445+ 'slide-img-menu' ,
446+ menuPosEl ,
447+ entries ,
448+ callback ,
449+ '' ,
450+ false ,
451+ ) ;
394452 } , this ) ;
395453
396454 var imgSize = this . _map . getPreview ( i , i ,
0 commit comments