| @@ -44,9 +44,8 @@ | ||
| 44 | 44 | if (missing.indexOf(name) === -1) { |
| 45 | 45 | missing.push(name); |
| 46 | 46 | } |
| 47 | 47 | }); |
| 48 | - | |
| 49 | 48 | // The editor script is ordered after GrapesJS but WordPress cannot |
| 50 | 49 | // guarantee the file actually arrived, so verify the global exists. |
| 51 | 50 | if (typeof grapesjs === 'undefined') { |
| 52 | 51 | if (missing.indexOf('grapesjs') === -1) { |
| @@ -84,12 +83,85 @@ | ||
| 84 | 83 | { fatal: false } |
| 85 | 84 | ); |
| 86 | 85 | } |
| 87 | 86 | |
| 87 | + // Pages the canvas cannot round-trip are announced after it starts, so | |
| 88 | + // the layout stays visible for reference, but saving is disabled before | |
| 89 | + // the user can edit: the document was already reduced when it was | |
| 90 | + // parsed into the canvas, and saving that reduction is the data loss. | |
| 91 | + showBlockedNotice(); | |
| 92 | + | |
| 88 | 93 | return true; |
| 89 | 94 | } |
| 90 | 95 | |
| 91 | 96 | /** |
| 97 | + * Disable saving for a page the canvas cannot represent faithfully. | |
| 98 | + * | |
| 99 | + * GrapesJS builds body fragments. A complete document, or a page carrying | |
| 100 | + * scripts, loses whatever the canvas cannot hold the moment it is parsed — | |
| 101 | + * so the warning belongs at load, not at save, and the only honest action | |
| 102 | + * is to send the user to the editor that can save the page intact. | |
| 103 | + */ | |
| 104 | + function showBlockedNotice() { | |
| 105 | + const reason = metasyncEditor.blocked_reason; | |
| 106 | + | |
| 107 | + if (!reason) { | |
| 108 | + return; | |
| 109 | + } | |
| 110 | + | |
| 111 | + const $panel = $('#metasync-editor-load-failure'); | |
| 112 | + | |
| 113 | + const message = reason === 'lps' | |
| 114 | + ? t('blocked_lps', 'This page was imported from Website Studio, which owns its content.') | |
| 115 | + : t('blocked_full_document', 'This page is a complete HTML document, so saving here would discard its doctype, head and scripts.'); | |
| 116 | + | |
| 117 | + $('.metasync-save-button') | |
| 118 | + .prop('disabled', true) | |
| 119 | + .attr('title', t('blocked_save_disabled', 'Saving is disabled to protect this page from being rewritten')); | |
| 120 | + | |
| 121 | + if (!$panel.length) { | |
| 122 | + return; | |
| 123 | + } | |
| 124 | + | |
| 125 | + $panel.find('.metasync-load-failure-title') | |
| 126 | + .text(t('blocked_title', 'This page cannot be saved from the visual editor')); | |
| 127 | + $panel.find('.metasync-load-failure-message').text(message); | |
| 128 | + $panel.find('.metasync-load-failure-detail').hide(); | |
| 129 | + | |
| 130 | + // Non-fatal styling: the canvas stays visible and usable for reading, | |
| 131 | + // so the notice sits above it rather than covering it. | |
| 132 | + $panel.removeClass('metasync-load-failure-fatal'); | |
| 133 | + | |
| 134 | + // Reload cannot help here — the block is a property of the stored | |
| 135 | + // page — so that button becomes the route to the lossless editor. | |
| 136 | + const $primary = $panel.find('.metasync-load-failure-reload').off('click'); | |
| 137 | + | |
| 138 | + if (metasyncEditor.direct_edit_url) { | |
| 139 | + $primary | |
| 140 | + .text(t('open_direct_editor', 'Edit HTML Directly')) | |
| 141 | + .on('click', function(e) { | |
| 142 | + e.preventDefault(); | |
| 143 | + window.location.href = metasyncEditor.direct_edit_url; | |
| 144 | + }) | |
| 145 | + .show(); | |
| 146 | + } else { | |
| 147 | + $primary.hide(); | |
| 148 | + } | |
| 149 | + | |
| 150 | + $panel.find('.metasync-load-failure-dismiss') | |
| 151 | + .text(t('dismiss', 'Dismiss')) | |
| 152 | + .off('click') | |
| 153 | + .on('click', function(e) { | |
| 154 | + e.preventDefault(); | |
| 155 | + $panel.attr('hidden', 'hidden'); | |
| 156 | + }) | |
| 157 | + .show(); | |
| 158 | + | |
| 159 | + $panel.removeAttr('hidden'); | |
| 160 | + updateStatus('error'); | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 92 | 164 | * Resolve the grapesjs-blocks-basic plugin. |
| 93 | 165 | * |
| 94 | 166 | * Releases before 1.0.0 registered themselves under the name |
| 95 | 167 | * 'gjs-blocks-basic'; 1.0.x only exposes a UMD export, so the plugin is |
| @@ -955,8 +1027,16 @@ | ||
| 955 | 1027 | if (!editor) { |
| 956 | 1028 | return; |
| 957 | 1029 | } |
| 958 | 1030 | |
| 1031 | + // Same reasoning for a page the canvas cannot round-trip: the button is | |
| 1032 | + // disabled, but the keyboard shortcut would otherwise still overwrite | |
| 1033 | + // the stored document with the canvas's reduced copy of it. | |
| 1034 | + if (metasyncEditor.blocked_reason) { | |
| 1035 | + showBlockedNotice(); | |
| 1036 | + return; | |
| 1037 | + } | |
| 1038 | + | |
| 959 | 1039 | const $button = $('.metasync-save-button'); |
| 960 | 1040 | const originalText = $button.text(); |
| 961 | 1041 | |
| 962 | 1042 | // Get HTML and CSS from editor |
| @@ -1060,9 +1140,12 @@ | ||
| 1060 | 1140 | * Prevent accidental exit with unsaved changes |
| 1061 | 1141 | */ |
| 1062 | 1142 | function preventAccidentalExit() { |
| 1063 | 1143 | $(window).on('beforeunload', function(e) { |
| 1064 | - if (hasUnsavedChanges) { | |
| 1144 | + // Nothing on a blocked page can be saved, so warning about unsaved | |
| 1145 | + // changes would only trap the user on a page they were told to | |
| 1146 | + // leave for the lossless editor. | |
| 1147 | + if (hasUnsavedChanges && !metasyncEditor.blocked_reason) { | |
| 1065 | 1148 | const message = metasyncEditor.i18n.confirm_exit; |
| 1066 | 1149 | e.returnValue = message; |
| 1067 | 1150 | return message; |
| 1068 | 1151 | } |