diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.appcache b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.appcache
new file mode 100644
index 0000000000000000000000000000000000000000..4a49b7c4ddf15cdaffeebe3c287507b78d339d15
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.appcache
@@ -0,0 +1,43 @@
+CACHE MANIFEST
+# generated on Mon, 11 Sep 2017 10:00:00 GMT
+CACHE:
+favicon.ico
+renderjs.js
+rsvp.js
+codemirror/lib/codemirror.js
+codemirror/lib/codemirror.css
+codemirror/addon/cm_edit/matchbrackets.js
+codemirror/addon/cm_edit/trailingspace.js
+codemirror/addon/dialog/dialog.css
+codemirror/addon/dialog/dialog.js
+codemirror/addon/display/fullscreen.css
+codemirror/addon/display/fullscreen.js
+codemirror/addon/display/rulers.js
+codemirror/addon/search/searchcursor.js
+codemirror/addon/search/search.js
+codemirror/addon/search/jump-to-line.js
+codemirror/addon/selection/active-line.js
+codemirror/addon/hint/show-hint.css
+codemirror/addon/hint/show-hint.js
+codemirror/addon/hint/anyword-hint.js
+codemirror/addon/fold/foldgutter.css
+codemirror/addon/fold/foldcode.js
+codemirror/addon/fold/foldgutter.js
+codemirror/addon/fold/indent-fold.js
+codemirror/addon/fold/comment-fold.js
+codemirror/addon/merge/merge.css
+diff_match_patch/javascript/diff_match_patch_uncompressed.js
+codemirror/addon/merge/merge.js
+codemirror/addon/lint/lint.css
+codemirror/addon/lint/lint.js
+jshint.js
+codemirror/addon/lint/javascript-lint.js
+csslint.js
+codemirror/addon/lint/css-lint.js
+codemirror/mode/xml/xml.js
+codemirror/mode/javascript/javascript.js
+codemirror/mode/css/css.js
+codemirror/mode/htmlmixed/htmlmixed.js
+codemirror.gadget.js
+NETWORK:
+*
\ No newline at end of file
diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.xml
new file mode 100644
index 0000000000000000000000000000000000000000..61438493e16dbadcae1889048d2d9d61692ee4a9
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.appcache.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_Cacheable__manager_id</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>codemirror.gadget.appcache</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>text/cache-manifest</string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.html b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.html
new file mode 100644
index 0000000000000000000000000000000000000000..b739f84c5ab6127534c4ef1ee75a50d5ee57fb0e
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html manifest=codemirror.gadget.appcache>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Codemirror</title>
+
+    <script src="rsvp.js"></script>
+    <script src="renderjs.js"></script>
+
+    <script src="codemirror/lib/codemirror.js"></script>
+    <link rel="stylesheet" href="codemirror/lib/codemirror.css" />
+    <!--script src="codemirror/mode/&dtml-mode;/&dtml-mode;.js"></script-->
+    <script src="codemirror/addon/cm_edit/matchbrackets.js"></script>
+
+    <!-- Trailing spaces -->
+    <script src="codemirror/addon/cm_edit/trailingspace.js"></script>
+    <style type="text/css">
+      .cm-trailingspace {
+        background-color: gray;
+      }
+      body {
+        padding: 0;
+        margin: 0;
+      }
+    </style>
+
+    <!-- Rulers -->
+    <script src="codemirror/addon/display/rulers.js"></script>
+
+    <!-- Search addons -->
+    <link rel="stylesheet" href="codemirror/addon/dialog/dialog.css">
+    <script src="codemirror/addon/dialog/dialog.js"></script>
+    <script src="codemirror/addon/search/searchcursor.js"></script>
+    <script src="codemirror/addon/search/search.js"></script>
+    <script src="codemirror/addon/search/jump-to-line.js"></script>
+    <script src="codemirror/addon/selection/active-line.js"></script>
+
+    <!-- Python autocomplete (Ctrl-Space, see below)
+         TODO-arnau: Add ERP5 autocompletion?
+      -->
+    <link rel="stylesheet" href="codemirror/addon/hint/show-hint.css" />
+    <script src="codemirror/addon/hint/show-hint.js"></script>
+    <script src="codemirror/addon/hint/anyword-hint.js"></script>
+
+    <!-- Code folding -->
+    <link rel="stylesheet" href="codemirror/addon/fold/foldgutter.css" />
+    <script src="codemirror/addon/fold/foldcode.js"></script>
+    <script src="codemirror/addon/fold/foldgutter.js"></script>
+    <script src="codemirror/addon/fold/indent-fold.js"></script>
+    <script src="codemirror/addon/fold/comment-fold.js"></script>
+
+    <!-- Merge -->
+    <link rel="stylesheet" href="codemirror/addon/merge/merge.css" />
+    <script src="diff_match_patch/javascript/diff_match_patch_uncompressed.js"></script>
+    <script src="codemirror/addon/merge/merge.js"></script>
+
+    <!-- Linter -->
+    <link rel="stylesheet" href="codemirror/addon/lint/lint.css" />
+    <script src="codemirror/addon/lint/lint.js"></script>
+
+    <script type="text/javascript" src="jshint.js"></script>
+    <script type="text/javascript" src="codemirror/addon/lint/javascript-lint.js"></script>
+
+    <script type="text/javascript" src="csslint.js"></script>
+    <script type="text/javascript" src="codemirror/addon/lint/css-lint.js"></script>
+
+    <script type="text/javascript" src="codemirror/mode/xml/xml.js"></script>
+    <script type="text/javascript" src="codemirror/mode/javascript/javascript.js"></script>
+    <script type="text/javascript" src="codemirror/mode/css/css.js"></script>
+    <script type="text/javascript" src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
+
+    <link rel="stylesheet" href="codemirror/addon/display/fullscreen.css" />
+    <script src="codemirror/addon/display/fullscreen.js"></script>
+    <script src="codemirror.gadget.js"></script>
+
+  </head>
+  <body>
+    <textarea></textarea>
+  </body>
+</html>
diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.xml
new file mode 100644
index 0000000000000000000000000000000000000000..136c6a2f875631e2910f958b6ac5ca54ffaaa1a1
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.html.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_Cacheable__manager_id</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>codemirror.gadget.html</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>text/html</string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.js b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.js
new file mode 100644
index 0000000000000000000000000000000000000000..286924dd3ca6a7f61cb3cdcd7755b31095cb16b8
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.js
@@ -0,0 +1,110 @@
+/*jslint nomen: true, indent: 2 */
+/*global window, rJS, CodeMirror*/
+(function (window, rJS, CodeMirror) {
+  "use strict";
+
+  rJS(window)
+    .declareAcquiredMethod("notifySubmit", "notifySubmit")
+    .declareJob("deferNotifySubmit", function () {
+      // Ensure error will be correctly handled
+      return this.notifySubmit();
+    })
+    .declareAcquiredMethod("notifyChange", "notifyChange")
+    .declareJob("deferNotifyChange", function () {
+      // Ensure error will be correctly handled
+      return this.notifyChange();
+    })
+    .ready(function () {
+      var context = this;
+      context.deferNotifyChangeBinded = context.deferNotifyChange.bind(context);
+      this.editor = CodeMirror.fromTextArea(
+        this.element.querySelector('textarea'),
+        {
+          // mode: mode,
+          fullScreen: true,
+          lineNumbers: true,
+          styleActiveLine: true,
+          showTrailingSpace: true,
+          tabSize: 2,
+          indentWithTabs: false,
+          matchBrackets: true,
+          rulers: [{
+            column: 80,
+            color: "#bbb",
+            lineStyle: "dashed"
+          }],
+          extraKeys: {
+            "Ctrl-Space": "autocomplete",
+            "Alt-Space": "autocomplete",
+            "Ctrl-Q": function (cm) {
+              cm.foldCode(cm.getCursor());
+            },
+            "Tab": function (cm) {
+              // We want to insert spaces, not tab, and we also want to keep the behaviour of indenting selection.
+              if (cm.getSelection()) {
+                return cm.execCommand("defaultTab");
+              }
+              var spaces = new Array(cm.getOption("indentUnit") + 1).join(" ");
+              cm.replaceSelection(spaces);
+            },
+            "Ctrl-I": "indentAuto",
+            "Shift-Tab": "indentLess",
+            "Ctrl-S": context.deferNotifySubmit.bind(context),
+            "Ctrl-R": function () {
+              // Disable page refresh to prevent data lose
+              return;
+            }
+          },
+          foldGutter: false,
+          lineWrapping: true,
+          gutters: ["CodeMirror-lint-markers",
+                    "CodeMirror-linenumbers",
+                    "CodeMirror-foldgutter"],
+          lint: true
+        }
+      );
+      this.editor.on('changes', this.deferNotifyChangeBinded);
+    })
+
+    .declareMethod('render', function (options) {
+      var mode,
+        state_dict = {
+          key: options.key,
+          editable: options.editable === undefined ? true : options.editable
+        };
+      if (options.portal_type === 'Web Page') {
+        mode = 'htmlmixed';
+      } else if (options.portal_type === 'Web Script') {
+        mode = 'javascript';
+      } else if (options.portal_type === 'Web Style') {
+        mode = 'css';
+      }
+      state_dict.mode = mode;
+      state_dict.value = options.value || "";
+      /* if (!this.editor.hasFocus()) {
+        state_dict.value = options.value || "";
+      } */
+      return this.changeState(state_dict);
+    })
+
+    .onStateChange(function (modification_dict) {
+      if (modification_dict.hasOwnProperty('value')) {
+        // Do not notify the UI when value is set
+        this.editor.off('changes', this.deferNotifyChangeBinded);
+        this.editor.setValue(this.state.value);
+        this.editor.on('changes', this.deferNotifyChangeBinded);
+      }
+      if (modification_dict.hasOwnProperty('mode')) {
+        this.editor.setOption("mode", this.state.mode);
+      }
+    })
+
+    .declareMethod('getContent', function () {
+      var form_data = {};
+      if (this.state.editable) {
+        form_data[this.state.key] = this.editor.getValue();
+      }
+      return form_data;
+    });
+
+}(window, rJS, CodeMirror));
diff --git a/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.xml b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eb5d79cb490aad6ace80c34ca0f89df86035d7e0
--- /dev/null
+++ b/bt5/erp5_code_mirror/SkinTemplateItem/portal_skins/erp5_code_mirror/codemirror.gadget.js.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_Cacheable__manager_id</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>codemirror.gadget.js</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>application/javascript</string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>