@@ -148,6 +148,40 @@ export const getImageResizeHandler = ({ editor, imagesRef, setImage }) => () =>
148
148
} ) ;
149
149
} ;
150
150
151
+ /**
152
+ * Fix TinyMCE editors used in Paragon modals, by re-parenting their modal <div>
153
+ * from the body to the Paragon modal container.
154
+ *
155
+ * This fixes a problem where clicking on any modal/popup within TinyMCE (e.g.
156
+ * the emoji inserter, the link inserter, the floating format toolbar -
157
+ * quickbars, etc.) would cause the parent Paragon modal to close, because
158
+ * Paragon sees it as a "click outside" event. Also fixes some hover effects by
159
+ * ensuring the layering of the divs is correct.
160
+ *
161
+ * This could potentially cause problems if there are TinyMCE editors being used
162
+ * both on the parent page and inside a Paragon modal popup, but I don't think
163
+ * we have that situation.
164
+ *
165
+ * Note: we can't just do this on init, because the quickbars plugin used by
166
+ * ExpandableTextEditors creates its modal DIVs later. Ideally we could listen
167
+ * for some kind of "modal open" event, but I haven't been able to find anything
168
+ * like that so for now we do this quite frequently, every time there is a
169
+ * "selectionchange" event (which is pretty often).
170
+ */
171
+ export const reparentTinyMceModals = /* istanbul ignore next */ ( ) => {
172
+ const modalLayer = document . querySelector ( '.pgn__modal-layer' ) ;
173
+ if ( ! modalLayer ) {
174
+ return ;
175
+ }
176
+ const tinymceAuxDivs = document . querySelectorAll ( '.tox.tox-tinymce-aux' ) ;
177
+ for ( const tinymceAux of tinymceAuxDivs ) {
178
+ if ( tinymceAux . parentElement !== modalLayer ) {
179
+ // Move this tinyMCE modal div into the paragon modal layer.
180
+ modalLayer . appendChild ( tinymceAux ) ;
181
+ }
182
+ }
183
+ } ;
184
+
151
185
export const setupCustomBehavior = ( {
152
186
updateContent,
153
187
openImgModal,
@@ -221,30 +255,17 @@ export const setupCustomBehavior = ({
221
255
}
222
256
223
257
editor . on ( 'init' , /* istanbul ignore next */ ( ) => {
224
- // Moving TinyMce aux modal inside the Editor modal
225
- // if the editor is on modal mode.
226
- // This is to avoid issues using the aux modal:
227
- // * Avoid close aux modal when clicking the content inside.
228
- // * When the user opens the `Edit Source Code` modal, this adds `data-focus-on-hidden`
229
- // to the TinyMce aux modal, making it unusable.
230
- const modalLayer = document . querySelector ( '.pgn__modal-layer' ) ;
231
- const tinymceAux = document . querySelector ( '.tox.tox-tinymce-aux' ) ;
232
-
233
- if ( modalLayer && tinymceAux ) {
234
- modalLayer . appendChild ( tinymceAux ) ;
258
+ // Check if this editor is inside a (Paragon) modal.
259
+ // The way we get the editor's root <div> depends on whether or not this particular editor is using an iframe:
260
+ const editorDiv = editor . bodyElement ?? editor . container ;
261
+ if ( editorDiv ?. closest ( '.pgn__modal' ) ) {
262
+ // This editor is inside a Paragon modal. Use this hack to avoid interference with TinyMCE's own modal popups:
263
+ reparentTinyMceModals ( ) ;
264
+ editor . on ( 'selectionchange' , reparentTinyMceModals ) ;
235
265
}
236
266
} ) ;
237
267
238
268
editor . on ( 'ExecCommand' , /* istanbul ignore next */ ( e ) => {
239
- // Remove `data-focus-on-hidden` and `aria-hidden` on TinyMce aux modal used on emoticons, formulas, etc.
240
- // When using the Editor in modal mode, it may happen that the editor modal is rendered
241
- // before the TinyMce aux modal, which adds these attributes, making the TinyMce aux modal unusable.
242
- const modalElement = document . querySelector ( '.tox.tox-silver-sink.tox-tinymce-aux' ) ;
243
- if ( modalElement ) {
244
- modalElement . removeAttribute ( 'data-focus-on-hidden' ) ;
245
- modalElement . removeAttribute ( 'aria-hidden' ) ;
246
- }
247
-
248
269
if ( editorType === 'text' && e . command === 'mceFocus' ) {
249
270
const initialContent = editor . getContent ( ) ;
250
271
const newContent = module . replaceStaticWithAsset ( {
0 commit comments