[BUGFIX] Prevent closing a record after T3Editor content changes 94/58394/7
authorJosef Glatz <josefglatz@gmail.com>
Tue, 25 Sep 2018 20:57:07 +0000 (22:57 +0200)
committerAndreas Fernandez <a.fernandez@scripting-base.de>
Wed, 26 Sep 2018 09:52:43 +0000 (11:52 +0200)
This patch prevents closing a form without showing the modal
to inform the backend user about unsaved changes if values of
an element with renderType `t3editor` were changed within the
CodeMirror editor.

In addition to the fix, a CSS border is added if the code editor
content was changed to improve the user experience.

Releases: master
Resolves: #86380
Change-Id: I641180a531b879ece70e30d0a22c9e5878d02953
Reviewed-on: https://review.typo3.org/58394
Reviewed-by: Josef Glatz <josef.glatz@typo3.org>
Tested-by: Josef Glatz <josef.glatz@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Michael Oehlhof <typo3@oehlhof.de>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Build/Resources/Public/Sass/editor.scss
Build/types/TYPO3/index.d.ts
typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
typo3/sysext/t3editor/Resources/Private/TypeScript/T3editor.ts
typo3/sysext/t3editor/Resources/Public/Css/t3editor.css
typo3/sysext/t3editor/Resources/Public/JavaScript/T3editor.js

index 35dff9d..bdc25eb 100644 (file)
@@ -5,28 +5,37 @@
 //
 $panel-bg-color: #f7f7f7;
 $panel-border-color: #ddd;
+$editor-border-color-changed: #6daadf;
 $fullscreen-top: 64px;
 $panel-font-size: 0.85em;
 $panel-padding-vertical: 3px;
 $panel-padding-horizontal: 6px;
 $color-matching-bracket: #6ca52b;
 
-.CodeMirror-fullscreen {
-    top: $fullscreen-top !important;
-}
+.t3editor-wrapper {
+    border: 1px solid transparent;
+
+    .CodeMirror-fullscreen {
+        top: $fullscreen-top !important;
+    }
 
-.CodeMirror-panel {
-    background: $panel-bg-color;
-    padding: $panel-padding-vertical $panel-padding-horizontal;
-    font-size: $panel-font-size;
+    .CodeMirror-panel {
+        background: $panel-bg-color;
+        padding: $panel-padding-vertical $panel-padding-horizontal;
+        font-size: $panel-font-size;
 
-    &-bottom {
-        border-top: 1px solid $panel-border-color;
+        &-bottom {
+            border-top: 1px solid $panel-border-color;
+        }
+    }
+
+    div.CodeMirror {
+        span.CodeMirror-matchingbracket {
+            color: $color-matching-bracket;
+        }
     }
-}
 
-div.CodeMirror {
-    span.CodeMirror-matchingbracket {
-        color: $color-matching-bracket;
+    .has-change & {
+        border-color: $editor-border-color-changed;
     }
 }
index b713464..d51cd8c 100644 (file)
@@ -26,6 +26,7 @@ declare namespace TYPO3 {
     export namespace Backend {
       export class FormEngineValidation {
         public readonly errorClass: string;
+        public markFieldAsChanged($field: JQuery): void;
       }
 
       export class FormEngine {
index 8ac16a8..8e78164 100644 (file)
@@ -157,7 +157,9 @@ class T3editorElement extends AbstractFormElement
         $html[] =   '<div class="form-control-wrap">';
         $html[] =       '<div class="form-wizards-wrap">';
         $html[] =           '<div class="form-wizards-element">';
-        $html[] =               $editorHtml;
+        $html[] =               '<div class="t3editor-wrapper">';
+        $html[] =                   $editorHtml;
+        $html[] =               '</div>';
         $html[] =           '</div>';
         if (!empty($fieldControlHtml)) {
             $html[] =           '<div class="form-wizards-items-aside">';
index 823732a..722fe3b 100644 (file)
@@ -13,6 +13,7 @@
 
 import * as CodeMirror from 'cm/lib/codemirror';
 import * as $ from 'jquery';
+import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
 
 /**
  * Module: TYPO3/CMS/T3editor/T3editor
@@ -82,6 +83,11 @@ class T3editor {
             cm.setOption(key, value);
           });
 
+          // Mark form as changed if code editor content has changed
+          cm.on('change', (): void => {
+            FormEngine.Validation.markFieldAsChanged($textarea);
+          });
+
           cm.addPanel(
             T3editor.createPanelNode('bottom', $textarea.attr('alt')),
             {
index fed9152..ff91404 100644 (file)
@@ -10,4 +10,4 @@
  * 
  * The TYPO3 project - inspiring people to share!
  */
-.CodeMirror-fullscreen{top:64px!important}.CodeMirror-panel{background:#f7f7f7;padding:3px 6px;font-size:.85em}.CodeMirror-panel-bottom{border-top:1px solid #ddd}div.CodeMirror span.CodeMirror-matchingbracket{color:#6ca52b}
\ No newline at end of file
+.t3editor-wrapper{border:1px solid transparent}.t3editor-wrapper .CodeMirror-fullscreen{top:64px!important}.t3editor-wrapper .CodeMirror-panel{background:#f7f7f7;padding:3px 6px;font-size:.85em}.t3editor-wrapper .CodeMirror-panel-bottom{border-top:1px solid #ddd}.t3editor-wrapper div.CodeMirror span.CodeMirror-matchingbracket{color:#6ca52b}.has-change .t3editor-wrapper{border-color:#6daadf}
\ No newline at end of file
index da3caca..1a4a960 100644 (file)
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","cm/lib/codemirror","jquery"],function(e,t,n,i){"use strict";return new(function(){function t(){this.initialize()}return t.createPanelNode=function(e,t){return i("<div />",{class:"CodeMirror-panel CodeMirror-panel-"+e,id:"panel-"+e}).append(i("<span />").text(t)).get(0)},t.prototype.findAndInitializeEditors=function(){i(document).find("textarea.t3editor").each(function(){var o=i(this);if(!o.prop("is_t3editor")){var r=o.data("codemirror-config"),a=r.mode.split("/"),l=i.merge([a.join("/")],JSON.parse(r.addons)),c=JSON.parse(r.options);e(l,function(){var e=n.fromTextArea(o.get(0),{extraKeys:{"Ctrl-Alt-F":function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},"Ctrl-Space":"autocomplete",Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}},fullScreen:!1,lineNumbers:!0,lineWrapping:!0,mode:a[a.length-1]});i.each(c,function(t,n){e.setOption(t,n)}),e.addPanel(t.createPanelNode("bottom",o.attr("alt")),{position:"bottom",stable:!0})}),o.prop("is_t3editor",!0)}})},t.prototype.initialize=function(){var e=this;i(function(){e.findAndInitializeEditors()})},t}())});
\ No newline at end of file
+define(["require","exports","cm/lib/codemirror","jquery","TYPO3/CMS/Backend/FormEngine"],function(e,t,n,i,o){"use strict";return new(function(){function t(){this.initialize()}return t.createPanelNode=function(e,t){return i("<div />",{class:"CodeMirror-panel CodeMirror-panel-"+e,id:"panel-"+e}).append(i("<span />").text(t)).get(0)},t.prototype.findAndInitializeEditors=function(){i(document).find("textarea.t3editor").each(function(){var r=i(this);if(!r.prop("is_t3editor")){var a=r.data("codemirror-config"),c=a.mode.split("/"),l=i.merge([c.join("/")],JSON.parse(a.addons)),d=JSON.parse(a.options);e(l,function(){var e=n.fromTextArea(r.get(0),{extraKeys:{"Ctrl-Alt-F":function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},"Ctrl-Space":"autocomplete",Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}},fullScreen:!1,lineNumbers:!0,lineWrapping:!0,mode:c[c.length-1]});i.each(d,function(t,n){e.setOption(t,n)}),e.on("change",function(){o.Validation.markFieldAsChanged(r)}),e.addPanel(t.createPanelNode("bottom",r.attr("alt")),{position:"bottom",stable:!0})}),r.prop("is_t3editor",!0)}})},t.prototype.initialize=function(){var e=this;i(function(){e.findAndInitializeEditors()})},t}())});
\ No newline at end of file