gecko-dev/devtools/client/sourceeditor
Xidorn Quan 5050b395ae Bug 1434130 part 13 - Use Servo code to back GetCSSValuesForProperty. r=emilio,gl
This causes various changes to properties-db.js and also many devtools
tests get updated.

There are two changes affect multiple tests:

* `calc` gets removed from everywhere. We never have it listed in all
  properties which deserve it, and doing so without much false positive
  (i.e. properties don't deserve but get it) can be pretty tricky.
  So they are just removed for now.

* The complete color keyword list is no longer included, and instead,
  "COLOR" is prepended to the list directly. We can probably remove
  the related code which replaces color keywords with "COLOR" from
  devtools. Note that, with stylo enabled, the list is already unrelated
  to what the parsing code uses. We should eventually re-enable the
  disabled test here after we can get the color list from cssparser
  in bug 1456715.

Other changes to properties-db.js seem to be valid, some of them also
affect tests:

* `{-webkit-,}align-{content,items,self}` get `first baseline`, `safe`,
  `unsafe`, and lose `left` and `right`.

* `{-moz-,-webkit-,}{animation,transition}{,-timing-function}` has a
  new `frame` keyword which is a function value in `<timing-function>`.

* `{background,{-webkit-,}mask}-position-x` lose `top` and `bottom`, and
  correspondingly `{background,{-webkit-,}mask}-position-y` lose `left`
  and `right`.  They don't deserve those values.

* `{background,{-webkit-,}mask}{,-size}` get `auto`.

* `border` shorthand loses `<image>` values as well as other keyword
  values for `border-image-*` subproperties, because they aren't parsed
  on the shorthand.

* `{-moz-,}border-image{,-width}` get `auto`.

* `-moz-context-properties` gets `none`.

* `cursor` get some -moz-prefixed values as well as `url`.

* `fill` and `stroke` get the color keywords.

* `{-webkit-,}filter` get the keywords and function names.

* `font` shorthand loses values from many of `font-variant-*` properties
  because they are not parsed there.

* `font-variant` and `font-variant-alternates` get function values of
  the longhand.

* `font-variant-{east-asian,ligatures,numeric}` get `normal`, and
  `font-variant-ligatures` in addition gets `none`.
  `font-{feature,variation}-settings` also get `normal`.

* `grid` and `grid-template-{areas,columns,rows}` get `none`.

* `grid`, `grid-template`, and `grid-template-{columns,rows}` get
  `auto`, `fit-content`, `minmax`, and `repeat`.

* `grid-auto-{columns,rows}` get `auto`, `fit-content` and `minmax`.

* `-moz-image-region` gets `auto` and `rect`.

* `{-webkit-,}justify-content` lose `baseline`, `last baseline`, and
  get `safe` and `unsafe`.

* `{justify,place}-items` get `first baseline`, `legacy`, `safe`,
  `unsafe` and lose `auto`.

* `{justify,place}-self` and `place-content` get `first baseline`,
  `safe`, and `unsafe`.

* `outline{,-style}` get `hidden`.

* `scroll-snap-coordinate` gets `none`, and `scroll-snap-points-{x,y}`
  gets `none` and `repeat`.

* `shape-outside`, `text-emphasis{,-style}` get all the keyword values
  and function names they deserve.

* `stroke-dasharray` gets `none`.

* `text-combine-upright` drops `digits` which we never implemented.

* `{-moz-,-webkit-,}transform` and `-moz-window-transform` get their
  transform function list. `accumulatematrix` and `interpolatematrix`
  aren't real CSS value but they have `#[css(function)]` specified.
  We should probably remove them at some point.

* `will-change` gets `auto`.

* All properties accept `<image>` value now gets -webkit-prefixed
  gradient function names, including
  * `background{,-image}`,
  * `{-moz-,-webkit-,}border-image{,-source}`, and
  * `{-webkit-,}mask{,-image}`.

MozReview-Commit-ID: E7Y0CFUFYgW

--HG--
extra : source : bab732c8c531cfca1bcd233f769c25bb2e373773
2018-04-29 09:03:31 +10:00
..
codemirror Bug 1456143 - Update Codemirror to 5.37.0. r=bgrins 2018-04-24 14:34:58 -04:00
tern Bug 1446711 part 8. Get rid of nsIDOMMouseEvent. r=qdot 2018-03-20 00:16:07 -04:00
test Bug 1434130 part 13 - Use Servo code to back GetCSSValuesForProperty. r=emilio,gl 2018-04-29 09:03:31 +10:00
.eslintrc.js Bug 1316096 - Change eslint configuration to use string values for rules instead of integers, making it easier for others who are reading the rules to know if a rule is set to off, warn, or error. r=mossop 2016-11-08 15:14:19 -05:00
autocomplete.js Bug 1443081 - Apply spacing via eslint --fix for DevTools. r=jdescottes 2018-03-12 13:44:41 -05:00
css-autocompleter.js Bug 1443081 - Apply spacing via eslint --fix for DevTools. r=jdescottes 2018-03-12 13:44:41 -05:00
debugger.js Bug 1443081 - Apply spacing via eslint --fix for DevTools. r=jdescottes 2018-03-12 13:44:41 -05:00
editor-commands-controller.js Bug 1443081 - Apply spacing via eslint --fix for DevTools. r=jdescottes 2018-03-12 13:44:41 -05:00
editor.js Bug 1447715 - Remove old-event-emitter usage from sourceeditor; r=gl. 2018-03-21 18:30:21 +01:00
moz.build Bug 1397366 - restore source-editor commands controller for scratchpad & styleeditor menus;r=ochameau 2018-01-03 20:52:58 +01:00
package.json Bug 1393825 - Update Codemirror to 5.29.0. r=bgrins 2017-08-29 01:18:54 -04:00
README Bug 1456143 - Update Codemirror to 5.37.0. r=bgrins 2018-04-24 14:34:58 -04:00
wasm.js Bug 1443081 - Apply spacing via eslint --fix for DevTools. r=jdescottes 2018-03-12 13:44:41 -05:00
webpack.config.js Bug 1333602 - Update new frontend (1/24/2017). r=jdescottes 2017-01-25 11:49:00 +08:00

This is the CodeMirror editor packaged for the Mozilla Project. CodeMirror
is a JavaScript component that provides a code editor in the browser. When
a mode is available for the language you are coding in, it will color your
code, and optionally help with indentation.

# Upgrade

Currently used version is 5.37.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

Then to recreate codemirror.bundle.js:
 > cd devtools/client/sourceeditor
 > npm install
 > webpack

To confirm the functionality run mochitests for the following components:

 * sourceeditor
 * scratchpad
 * debugger
 * styleditor
 * netmonitor

The sourceeditor component contains imported CodeMirror tests [3].

 * Some tests were commented out because we don't use that functionality
   within Firefox (for example Ruby editing mode). Be careful when updating
   files test/codemirror.html and test/vimemacs.html; they were modified to
   co-exist with Mozilla's testing infrastructure. Basically, vimemacs.html
   is a copy of codemirror.html but only with VIM and Emacs mode tests
   enabled.
 * In cm_comment_test.js comment out fallbackToBlock and fallbackToLine
   tests.
 * The search addon (search.js) was slightly modified to make search
   UI localizable (see patch below).

Other than that, we don't have any Mozilla-specific patches applied to
CodeMirror itself.

# Addons

To install a new CodeMirror addon add it to the codemirror directory,
jar.mn [4] file and editor.js [5]. Also, add it to the License section
below.

# License

The following files in this directory and devtools/client/sourceeditor/test/codemirror/
are licensed according to the contents in the LICENSE file.

# Localization patches

diff --git a/devtools/client/sourceeditor/codemirror/addon/search/search.js b/devtools/client/sourceeditor/codemirror/addon/search/search.js
--- a/devtools/client/sourceeditor/codemirror/addon/search/search.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/search.js
@@ -93,32 +93,47 @@
     } else {
       query = parseString(query)
     }
     if (typeof query == "string" ? query == "" : query.test(""))
       query = /x^/;
     return query;
   }

-  var queryDialog =
-    '<span class="CodeMirror-search-label">Search:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
+  var queryDialog;

   function startSearch(cm, state, query) {
     state.queryText = query;
     state.query = parseQuery(query);
     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
     state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
     cm.addOverlay(state.overlay);
     if (cm.showMatchesOnScrollbar) {
       if (state.annotate) { state.annotate.clear(); state.annotate = null; }
       state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
     }
   }

   function doSearch(cm, rev, persistent, immediate) {
+    if (!queryDialog) {
+      let doc = cm.getWrapperElement().ownerDocument;
+      let inp = doc.createElement("input");
+
+      inp.type = "search";
+      inp.placeholder = cm.l10n("findCmd.promptMessage");
+      inp.style.marginInlineStart = "1em";
+      inp.style.marginInlineEnd = "1em";
+      inp.style.flexGrow = "1";
+      inp.addEventListener("focus", () => inp.select());
+
+      queryDialog = doc.createElement("div");
+      queryDialog.appendChild(inp);
+      queryDialog.style.display = "flex";
+    }
+
     var state = getSearchState(cm);
     if (state.query) return findNext(cm, rev);
     var q = cm.getSelection() || state.lastQuery;
     if (q instanceof RegExp && q.source == "x^") q = null
     if (persistent && cm.openDialog) {
       var hiding = null
       var searchNext = function(query, event) {
         CodeMirror.e_stop(event);
@@ -181,56 +196,110 @@
     var state = getSearchState(cm);
     state.lastQuery = state.query;
     if (!state.query) return;
     state.query = state.queryText = null;
     cm.removeOverlay(state.overlay);
     if (state.annotate) { state.annotate.clear(); state.annotate = null; }
   });}

-  var replaceQueryDialog =
-    ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
-  var replacementQueryDialog = '<span class="CodeMirror-search-label">With:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
-  var doReplaceConfirm = '<span class="CodeMirror-search-label">Replace?</span> <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>';
-
   function replaceAll(cm, query, text) {
     cm.operation(function() {
       for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
         if (typeof query != "string") {
           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
           cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
         } else cursor.replace(text);
       }
     });
   }

   function replace(cm, all) {
     if (cm.getOption("readOnly")) return;
     var query = cm.getSelection() || getSearchState(cm).lastQuery;
-    var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Replace all:' : 'Replace:') + '</span>';
-    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
+
+    let doc = cm.getWrapperElement().ownerDocument;
+
+    // `searchLabel` is used as part of `replaceQueryFragment` and as a separate
+    // argument by itself, so it should be cloned.
+    let searchLabel = doc.createElement("span");
+    searchLabel.classList.add("CodeMirror-search-label");
+    searchLabel.textContent = all ? "Replace all:" : "Replace:";
+
+    let replaceQueryFragment = doc.createDocumentFragment();
+    replaceQueryFragment.appendChild(searchLabel.cloneNode(true));
+
+    let searchField = doc.createElement("input");
+    searchField.setAttribute("type", "text");
+    searchField.setAttribute("style", "width: 10em");
+    searchField.classList.add("CodeMirror-search-field");
+    replaceQueryFragment.appendChild(searchField);
+
+    let searchHint = doc.createElement("span");
+    searchHint.setAttribute("style", "color: #888");
+    searchHint.classList.add("CodeMirror-search-hint");
+    searchHint.textContent = "(Use /re/ syntax for regexp search)";
+    replaceQueryFragment.appendChild(searchHint);
+
+    dialog(cm, replaceQueryFragment, searchLabel, query, function(query) {
       if (!query) return;
       query = parseQuery(query);
-      dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
+
+      let replacementQueryFragment = doc.createDocumentFragment();
+
+      let replaceWithLabel = searchLabel.cloneNode(false);
+      replaceWithLabel.textContent = "With:";
+      replacementQueryFragment.appendChild(replaceWithLabel);
+
+      let replaceField = doc.createElement("input");
+      replaceField.setAttribute("type", "text");
+      replaceField.setAttribute("style", "width: 10em");
+      replaceField.classList.add("CodeMirror-search-field");
+      replacementQueryFragment.appendChild(replaceField);
+
+      dialog(cm, replacementQueryFragment, "Replace with:", "", function(text) {
         text = parseString(text)
         if (all) {
           replaceAll(cm, query, text)
         } else {
           clearSearch(cm);
           var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
           var advance = function() {
             var start = cursor.from(), match;
             if (!(match = cursor.findNext())) {
               cursor = getSearchCursor(cm, query);
               if (!(match = cursor.findNext()) ||
                   (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
             }
             cm.setSelection(cursor.from(), cursor.to());
-            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
-            confirmDialog(cm, doReplaceConfirm, "Replace?",
+            cm.scrollIntoView({ from: cursor.from(), to: cursor.to() });
+
+            let replaceConfirmFragment = doc.createDocumentFragment();
+
+            let replaceConfirmLabel = searchLabel.cloneNode(false);
+            replaceConfirmLabel.textContent = "Replace?";
+            replaceConfirmFragment.appendChild(replaceConfirmLabel);
+
+            let yesButton = doc.createElement("button");
+            yesButton.textContent = "Yes";
+            replaceConfirmFragment.appendChild(yesButton);
+
+            let noButton = doc.createElement("button");
+            noButton.textContent = "No";
+            replaceConfirmFragment.appendChild(noButton);
+
+            let allButton = doc.createElement("button");
+            allButton.textContent = "All";
+            replaceConfirmFragment.appendChild(allButton);
+
+            let stopButton = doc.createElement("button");
+            stopButton.textContent = "Stop";
+            replaceConfirmFragment.appendChild(stopButton);
+
+            confirmDialog(cm, replaceConfirmFragment, "Replace?",
                           [function() {doReplace(match);}, advance,
                            function() {replaceAll(cm, query, text)}]);
           };
           var doReplace = function(match) {
             cursor.replace(typeof query == "string" ? text :
                            text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
             advance();
           };

# Footnotes

[1] http://codemirror.net
[2] devtools/client/sourceeditor/codemirror
[3] devtools/client/sourceeditor/test/browser_codemirror.js
[4] devtools/client/jar.mn
[5] devtools/client/sourceeditor/editor.js