1/** 2 * Hide Prosemirror and show the default editor 3 * 4 * @param {string} text the wiki syntax to be shown in the textarea 5 */ 6function showDefaultEditor(text) { 7 window.Prosemirror.destroyProsemirror(); 8 window.proseMirrorIsActive = false; 9 dw_locktimer.init(dw_locktimer.timeout/1000, dw_locktimer.draft); 10 jQuery('#wiki__text').val(text).show(); 11 jQuery('#size__ctl').show(); 12 jQuery('.editBox > .toolbar').show(); 13} 14 15/** 16 * Hide the default editor and start a new Prosemirror Editor 17 * 18 * @param {string} json the prosemirror document json 19 */ 20function showProsemirror(json) { 21 const $textArea = jQuery('#wiki__text'); 22 const $prosemirrorJsonInput = jQuery('#dw__editform').find('[name=prosemirror_json]').val(json); 23 try { 24 window.Prosemirror.enableProsemirror(); 25 stickyMenubar(); 26 disableNativeFirefoxTableControls(); 27 } catch (e) { 28 console.error(e); 29 let message = 'There was an error in the WYSIWYG editor. You will be redirected to the syntax editor in 5 seconds.'; 30 if (window.SentryPlugin) { 31 SentryPlugin.logSentryException(e, { 32 tags: { 33 plugin: 'prosemirror', 34 'id': JSINFO.id, 35 }, 36 extra: { 37 'content': $textArea.val(), 38 'json': $prosemirrorJsonInput.val(), 39 } 40 }); 41 message += ' -- The error has been logged to Sentry.'; 42 } 43 showErrorMessage(message); 44 setTimeout(function() { 45 jQuery('.plugin_prosemirror_useWYSIWYG').click(); 46 }, 5000); 47 } 48 window.proseMirrorIsActive = true; 49 $textArea.hide(); 50 jQuery('#size__ctl').hide(); 51 jQuery('.editBox > .toolbar').hide(); 52 jQuery('div.ProseMirror').focus(); 53 54 if (dw_locktimer.addField) { 55 // todo remove this guard after the next stable DokuWiki release after Greebo 56 dw_locktimer.init(dw_locktimer.timeout/1000, dw_locktimer.draft, 'prosemirror__editor'); 57 dw_locktimer.addField('input[name=prosemirror_json]'); 58 } else { 59 console.warn('Draft saving in WYSIWYG is not available. Please upgrade your wiki to the current development snapshot.') 60 } 61} 62 63/** 64 * Disables Firefox's controls for editable tables, they are incompatible with prosemirror 65 * 66 * See https://github.com/ProseMirror/prosemirror/issues/432 and https://github.com/ProseMirror/prosemirror-tables/issues/22 67 */ 68function disableNativeFirefoxTableControls() { 69 document.execCommand("enableObjectResizing", false, "false"); 70 document.execCommand("enableInlineTableEditing", false, "false"); 71} 72 73/** 74 * Initialize the prosemirror framework 75 * 76 * (This shouldn't do much until we actually use the editor, but we maybe shouldn't do this twice) 77 */ 78function initializeProsemirror() { 79 try { 80 /* DOKUWIKI:include lib/bundle.js */ 81 } catch (e) { 82 const $textArea = jQuery('#wiki__text'); 83 console.error(e); 84 let message = 'There was an error initializing the WYSIWYG editor.'; 85 if (window.SentryPlugin) { 86 SentryPlugin.logSentryException(e, { 87 tags: { 88 plugin: 'prosemirror', 89 'id': JSINFO.id, 90 }, 91 extra: { 92 'content': $textArea.val(), 93 } 94 }); 95 message += ' The error has been logged to sentry.'; 96 } 97 98 showErrorMessage(message); 99 100 DokuCookie.setValue('plugin_prosemirror_useWYSIWYG', ''); 101 } 102} 103 104/** 105 * Add the error message above the editor 106 * 107 * @param {string} errorMsg 108 */ 109function showErrorMessage(errorMsg) { 110 jQuery('.editBox').before( 111 jQuery('<div class="error"></div>').text(errorMsg) 112 ); 113} 114 115/** 116 * Switch between WYSIWYG and Syntax editor 117 */ 118function toggleEditor() { 119 const $textArea = jQuery('#wiki__text'); 120 const $jsonField = jQuery('#dw__editform').find('[name=prosemirror_json]'); 121 jQuery.post(DOKU_BASE + 'lib/exe/ajax.php', { 122 call: 'plugin_prosemirror_switch_editors', 123 data: window.proseMirrorIsActive ? $jsonField.val() : $textArea.val(), 124 getJSON: window.proseMirrorIsActive ? '0' : '1', 125 }).done(function handleSwitchEditorResponse(data) { 126 if (window.proseMirrorIsActive) { 127 showDefaultEditor(data.text); 128 } else { 129 showProsemirror(data.json); 130 } 131 }).fail(function (jqXHR, textStatus, errorThrown) { 132 console.error(jqXHR, textStatus, errorThrown); // FIXME: proper error handling 133 if (jqXHR.responseJSON && jqXHR.responseJSON.error) { 134 showErrorMessage(jqXHR.responseJSON.error); 135 } else { 136 let message = 'The request failed with an unexpected error.'; 137 if (window.SentryPlugin) { 138 SentryPlugin.logSentryException(new Error(textStatus), { 139 tags: { 140 plugin: 'prosemirror', 141 'id': JSINFO.id, 142 status: jqXHR.status 143 }, 144 extra: { 145 'content': $textArea.val(), 146 'responseText': jqXHR.responseText, 147 } 148 }); 149 message += ' -- The error has been logged to Sentry.'; 150 } 151 showErrorMessage(message); 152 } 153 }); 154 155 const $current = DokuCookie.getValue('plugin_prosemirror_useWYSIWYG'); 156 DokuCookie.setValue('plugin_prosemirror_useWYSIWYG', $current ? '' : '1'); 157} 158 159/** 160 * If the cookie is set, then show the WYSIWYG editor and add the switch-editor-event to the button 161 */ 162function handleEditSession() { 163 const $jsonField = jQuery('#dw__editform').find('[name=prosemirror_json]'); 164 if (DokuCookie.getValue('plugin_prosemirror_useWYSIWYG')) { 165 showProsemirror($jsonField.val()); 166 } 167 const $toggleEditorButton = jQuery('.plugin_prosemirror_useWYSIWYG'); 168 $toggleEditorButton.on('click', toggleEditor); 169} 170 171/** 172 * when the editor switch button moves out of the view-port, the menubar gets a class 173 * @see https://codepen.io/hey-nick/pen/mLpmMV 174 * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API 175 */ 176 177function stickyMenubar() { 178 const editorswitch = document.querySelector('button[name=prosemirror]'); 179 const menubar = document.querySelector('#prosemirror__editor div.menubar'); 180 181 const observer = new IntersectionObserver( 182 ([e]) => { 183 return menubar.classList.toggle('prosemirror-menubar-fixed', e.intersectionRatio !== 1); 184 }, 185 { 186 root: null, 187 threshold: [0, 1] 188 } 189 ); 190 if (editorswitch && menubar) { 191 observer.observe(editorswitch); 192 } 193} 194 195 196jQuery(function () { 197 initializeProsemirror(); 198 window.proseMirrorIsActive = false; 199 200 if (jQuery('#dw__editform').find('[name=prosemirror_json]').length) { 201 handleEditSession(); 202 } 203 204 jQuery(window).on('fastwiki:afterSwitch', function(evt, viewMode, isSectionEdit, prevViewMode) { 205 if (viewMode === 'edit' || isSectionEdit) { 206 handleEditSession(); 207 } 208 }); 209}); 210