@@ -60,7 +60,7 @@ global.MonsieurBizRichEditorConfig = class {
6060 uielements ,
6161 wysiwyg ,
6262 containerHtml ,
63- buttonAddHtml ,
63+ actionsHtml ,
6464 elementHtml ,
6565 elementCardHtml ,
6666 deletionConfirmation ,
@@ -69,13 +69,14 @@ global.MonsieurBizRichEditorConfig = class {
6969 renderElementsUrl ,
7070 defaultUiElement ,
7171 defaultUIElementDataField ,
72- errorMessage
72+ errorMessage ,
73+ unallowedUiElementMessage
7374 ) {
7475 this . input = input ;
7576 this . uielements = uielements ;
7677 this . wysiwyg = wysiwyg ;
7778 this . containerHtml = containerHtml ;
78- this . buttonAddHtml = buttonAddHtml ;
79+ this . actionsHtml = actionsHtml ;
7980 this . elementHtml = elementHtml ;
8081 this . elementCardHtml = elementCardHtml ;
8182 this . deletionConfirmation = deletionConfirmation ;
@@ -85,6 +86,7 @@ global.MonsieurBizRichEditorConfig = class {
8586 this . defaultUiElement = defaultUiElement ;
8687 this . defaultUIElementDataField = defaultUIElementDataField ;
8788 this . errorMessage = errorMessage ;
89+ this . unallowedUiElementMessage = unallowedUiElementMessage ;
8890 }
8991
9092 findUiElementByCode ( code ) {
@@ -138,6 +140,10 @@ global.MonsieurBizRichEditorUiElement = class {
138140 this . manager . editUiElement ( this ) ;
139141 }
140142
143+ copy ( callback ) {
144+ this . manager . saveUiElementToClipboard ( this , callback ) ;
145+ }
146+
141147 up ( ) {
142148 this . manager . moveUp ( this ) ;
143149 }
@@ -225,6 +231,11 @@ global.MonsieurBizRichEditorManager = class {
225231 document . dispatchEvent ( new CustomEvent ( 'mbiz:rich-editor:init-interface-complete' , {
226232 'detail' : { 'editorManager' : this }
227233 } ) ) ;
234+ document . addEventListener ( 'mbiz:rich-editor:uielement:copied' , function ( e ) {
235+ this . container . querySelectorAll ( '.js-uie-paste' ) . forEach ( function ( action ) {
236+ action . classList . remove ( 'disabled' ) ;
237+ } . bind ( this ) ) ;
238+ } . bind ( this ) ) ;
228239 }
229240
230241 initUiPanelsInterface ( ) {
@@ -259,24 +270,41 @@ global.MonsieurBizRichEditorManager = class {
259270 let elementsContainer = this . container . querySelector ( '.js-uie-container' ) ;
260271 elementsContainer . innerHTML = '' ;
261272 this . uiElements . forEach ( function ( element , position ) {
262- elementsContainer . append ( this . getNewButton ( position ) ) ;
273+ elementsContainer . append ( this . getActions ( position ) ) ;
263274 elementsContainer . append ( this . getUiElement ( element , position ) ) ;
264275 } . bind ( this ) ) ;
265- elementsContainer . append ( this . getNewButton ( this . uiElements . length ) ) ;
266- }
267-
268- getNewButton ( position ) {
269- let buttonWrapper = document . createElement ( 'div' ) ;
270- buttonWrapper . innerHTML = Mustache . render ( this . config . buttonAddHtml , { 'position' : position } ) ;
271- let button = buttonWrapper . firstElementChild ;
272- button . querySelector ( '.js-uie-add' ) . position = position ;
273- button . querySelector ( '.js-uie-add' ) . manager = this ;
274- button . querySelector ( '.js-uie-add' ) . addEventListener ( 'click' , function ( e ) {
275- button . querySelector ( '.js-uie-add' ) . manager . openSelectionPanel (
276- button . querySelector ( '.js-uie-add' ) . position
276+ elementsContainer . append ( this . getActions ( this . uiElements . length ) ) ;
277+ }
278+
279+ getActions ( position ) {
280+ let actionsWrapper = document . createElement ( 'div' ) ;
281+ actionsWrapper . innerHTML = Mustache . render ( this . config . actionsHtml , { 'position' : position } ) ;
282+
283+ let actions = actionsWrapper . firstElementChild ;
284+
285+ // Add button
286+ actions . querySelector ( '.js-uie-add' ) . position = position ;
287+ actions . querySelector ( '.js-uie-add' ) . manager = this ;
288+ actions . querySelector ( '.js-uie-add' ) . addEventListener ( 'click' , function ( e ) {
289+ actions . querySelector ( '.js-uie-add' ) . manager . openSelectionPanel (
290+ actions . querySelector ( '.js-uie-add' ) . position
277291 ) ;
278292 } ) ;
279- return button ;
293+
294+ // Paste clipboard button
295+ actions . querySelector ( '.js-uie-paste' ) . position = position ;
296+ actions . querySelector ( '.js-uie-paste' ) . manager = this ;
297+ actions . querySelector ( '.js-uie-paste' ) . addEventListener ( 'click' , function ( e ) {
298+ actions . querySelector ( '.js-uie-paste' ) . manager . pasteUiElementFromClipboard (
299+ actions . querySelector ( '.js-uie-paste' ) . position
300+ ) ;
301+ } ) ;
302+ // Disabled?
303+ if ( ! this . isClipboardEmpty ( ) ) {
304+ actions . querySelector ( '.js-uie-paste' ) . classList . remove ( 'disabled' ) ;
305+ }
306+
307+ return actions ;
280308 }
281309
282310 getUiElement ( element , position ) {
@@ -312,6 +340,16 @@ global.MonsieurBizRichEditorManager = class {
312340 uiElement . querySelector ( '.js-uie-edit' ) . addEventListener ( 'click' , function ( ) {
313341 this . closest ( '.js-uie-element' ) . element . edit ( ) ;
314342 } ) ;
343+ uiElement . querySelector ( '.js-uie-copy' ) . addEventListener ( 'click' , function ( e ) {
344+ this . closest ( '.js-uie-element' ) . element . copy ( function ( ) {
345+ const button = e . currentTarget ;
346+ const originalText = button . dataset . tooltip ;
347+ button . dataset . tooltip = button . dataset . alternateText ;
348+ window . setTimeout ( function ( ) {
349+ button . dataset . tooltip = originalText ;
350+ } , 1000 ) ;
351+ } ) ;
352+ } ) ;
315353 return uiElement ;
316354 }
317355
@@ -577,6 +615,55 @@ global.MonsieurBizRichEditorManager = class {
577615 req . send ( data ) ;
578616 }
579617
618+ isClipboardEmpty ( ) {
619+ const clipboard = window . sessionStorage . getItem ( 'monsieurBizRichEditorClipboard' ) ;
620+ return null === clipboard || '' === clipboard ;
621+ }
622+
623+ saveUiElementToClipboard ( uiElement , callback ) {
624+ window . sessionStorage . setItem ( 'monsieurBizRichEditorClipboard' , JSON . stringify ( uiElement ) ) ;
625+ callback ( ) ;
626+ document . dispatchEvent ( new CustomEvent ( 'mbiz:rich-editor:uielement:copied' , { } ) ) ;
627+ }
628+
629+ pasteUiElementFromClipboard ( futurePosition ) {
630+ const clipboard = window . sessionStorage . getItem ( 'monsieurBizRichEditorClipboard' ) ;
631+ if ( null !== clipboard ) {
632+ const pastedUiElement = JSON . parse ( clipboard ) ;
633+ const manager = this ;
634+ manager . requestUiElementsHtml ( [ pastedUiElement ] , function ( ) {
635+ if ( this . status === 200 ) {
636+ let renderedElements = JSON . parse ( this . responseText ) ;
637+ const elementHtml = renderedElements . shift ( ) ;
638+ if ( pastedUiElement . code === undefined && pastedUiElement . type !== undefined ) {
639+ pastedUiElement . code = pastedUiElement . type ;
640+ pastedUiElement . data = pastedUiElement . fields ;
641+ delete pastedUiElement . type ;
642+ delete pastedUiElement . fields ;
643+ }
644+ let uiElement = manager . config . findUiElementByCode ( pastedUiElement . code ) ;
645+ if ( null !== uiElement ) {
646+ if ( manager . tags . length > 0 ) {
647+ let copy = false ;
648+ for ( let tagIndex in manager . tags ) {
649+ if ( 0 <= manager . config . uielements [ uiElement . code ] . tags . indexOf ( manager . tags [ tagIndex ] ) ) {
650+ copy = true ;
651+ }
652+ }
653+ if ( copy ) {
654+ manager . create ( uiElement . code , pastedUiElement . data , elementHtml , futurePosition ) ;
655+ } else {
656+ alert ( manager . config . unallowedUiElementMessage ) ;
657+ }
658+ } else {
659+ manager . create ( uiElement . code , pastedUiElement . data , elementHtml , futurePosition ) ;
660+ }
661+ }
662+ }
663+ } ) ;
664+ }
665+ }
666+
580667 dispatchInitFormEvent ( form ) {
581668 document . dispatchEvent ( new CustomEvent ( 'monsieurBizRichEditorInitForm' , {
582669 'detail' : { 'form' : form }
0 commit comments