Changeset 147117 in webkit


Ignore:
Timestamp:
Mar 28, 2013 8:15:07 AM (11 years ago)
Author:
apavlov@chromium.org
Message:

Web Inspector: [Elements] Syntax-highlight the "Edit as HTML" editor
https://bugs.webkit.org/show_bug.cgi?id=113306

Reviewed by Vsevolod Vlasov.

Source/WebCore:

Use CodeMirror as the raw HTML editor for the "Edit as HTML" menu item
(and all multiline editors for WebInspector.startEditing()).
Drive-by fix for handling the editing when the editor has been invoked on the closing tag.

  • inspector/front-end/ElementsTreeOutline.js:

(WebInspector.ElementsTreeElement.prototype.commit):
(WebInspector.ElementsTreeElement.prototype._startEditingAsHTML):

  • inspector/front-end/UIUtils.js:

(WebInspector.EditingConfig.prototype.setMultiline):
(WebInspector.startEditing):
(WebInspector.CodeMirrorCSSLoadView): A bogus view to load-unload CodeMirror-related CSS on demand.

  • inspector/front-end/elementsPanel.css:

(#elements-content .CodeMirror):
(#elements-content .CodeMirror pre):
(#elements-content .CodeMirror-lines):

  • inspector/front-end/elementsPanel.css: CodeMirror styles for the "Edit as HTML" editor.
  • inspector/front-end/externs.js: Declare CodeMirror type with some members, as it is third-party code.
  • inspector/front-end/inspector.html: Fix script order (UIUtils.js requires View.js).

LayoutTests:

  • inspector/elements/edit-dom-actions.html:
Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r147116 r147117  
     12013-03-28  Alexander Pavlov  <apavlov@chromium.org>
     2
     3        Web Inspector: [Elements] Syntax-highlight the "Edit as HTML" editor
     4        https://bugs.webkit.org/show_bug.cgi?id=113306
     5
     6        Reviewed by Vsevolod Vlasov.
     7
     8        * inspector/elements/edit-dom-actions.html:
     9
    1102013-03-28  Christophe Dumez  <ch.dumez@sisa.samsung.com>
    211
  • trunk/LayoutTests/inspector/elements/edit-dom-actions.html

    r131455 r147117  
    126126                function step2()
    127127                {
    128                     InspectorTest.addResult(treeElement._htmlEditElement.textContent);
    129                     treeElement._htmlEditElement.textContent = "<div foo=\"bar-comment\">Element</div>";
     128                    InspectorTest.addResult(treeElement._editing.codeMirror.getValue());
     129                    treeElement._editing.codeMirror.setValue("<div foo=\"bar-comment\">Element</div>");
    130130                    var event = InspectorTest.createKeyEvent("Enter");
    131131                    event.isMetaOrCtrlForTest = true;
     
    148148                function step2()
    149149                {
    150                     InspectorTest.addResult(treeElement._htmlEditElement.textContent);
    151                     treeElement._htmlEditElement.textContent = "<span foo=\"bar\"><span id=\"inner-span\">Span contents</span></span>";
     150                    InspectorTest.addResult(treeElement._editing.codeMirror.getValue());
     151                    treeElement._editing.codeMirror.setValue("<span foo=\"bar\"><span id=\"inner-span\">Span contents</span></span>");
    152152                    var event = InspectorTest.createKeyEvent("Enter");
    153153                    event.isMetaOrCtrlForTest = true;
     
    170170                function step2()
    171171                {
    172                     InspectorTest.addResult(treeElement._htmlEditElement.textContent);
    173                     treeElement._htmlEditElement.textContent = treeElement._htmlEditElement.textContent.replace(/&/g, '#');
     172                    var codeMirror = treeElement._editing.codeMirror;
     173                    InspectorTest.addResult(codeMirror.getValue());
     174                    codeMirror.setValue(codeMirror.getValue().replace(/&/g, '#'));
    174175                    var event = InspectorTest.createKeyEvent("Enter");
    175176                    event.isMetaOrCtrlForTest = true;
  • trunk/Source/WebCore/ChangeLog

    r147113 r147117  
     12013-03-28  Alexander Pavlov  <apavlov@chromium.org>
     2
     3        Web Inspector: [Elements] Syntax-highlight the "Edit as HTML" editor
     4        https://bugs.webkit.org/show_bug.cgi?id=113306
     5
     6        Reviewed by Vsevolod Vlasov.
     7
     8        Use CodeMirror as the raw HTML editor for the "Edit as HTML" menu item
     9        (and all multiline editors for WebInspector.startEditing()).
     10        Drive-by fix for handling the editing when the editor has been invoked on the closing tag.
     11
     12        * inspector/front-end/ElementsTreeOutline.js:
     13        (WebInspector.ElementsTreeElement.prototype.commit):
     14        (WebInspector.ElementsTreeElement.prototype._startEditingAsHTML):
     15        * inspector/front-end/UIUtils.js:
     16        (WebInspector.EditingConfig.prototype.setMultiline):
     17        (WebInspector.startEditing):
     18        (WebInspector.CodeMirrorCSSLoadView): A bogus view to load-unload CodeMirror-related CSS on demand.
     19        * inspector/front-end/elementsPanel.css:
     20        (#elements-content .CodeMirror):
     21        (#elements-content .CodeMirror pre):
     22        (#elements-content .CodeMirror-lines):
     23        * inspector/front-end/elementsPanel.css: CodeMirror styles for the "Edit as HTML" editor.
     24        * inspector/front-end/externs.js: Declare CodeMirror type with some members, as it is third-party code.
     25        * inspector/front-end/inspector.html: Fix script order (UIUtils.js requires View.js).
     26
    1272013-03-28  Hajime Morrita  <morrita@google.com>
    228
  • trunk/Source/WebCore/inspector/front-end/ElementsTreeOutline.js

    r146220 r147117  
    14811481        if (error)
    14821482            return;
    1483         if (this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement))
     1483        if (this._editing)
    14841484            return;
    14851485
     
    14921492        initialValue = this._convertWhitespaceToEntities(initialValue);
    14931493
     1494        this.select(true);
     1495
    14941496        this._htmlEditElement = document.createElement("div");
    14951497        this._htmlEditElement.className = "source-code elements-tree-editor";
    1496         this._htmlEditElement.textContent = initialValue;
    14971498
    14981499        // Hide header items.
     
    15111512        this.updateSelection();
    15121513
    1513         function commit()
    1514         {
    1515             commitCallback(initialValue, this._htmlEditElement.textContent);
     1514        /**
     1515         * @param {Element} element
     1516         * @param {string} newValue
     1517         */
     1518        function commit(element, newValue)
     1519        {
     1520            commitCallback(initialValue, newValue);
    15161521            dispose.call(this);
    15171522        }
     
    15391544
    15401545        var config = new WebInspector.EditingConfig(commit.bind(this), dispose.bind(this));
    1541         config.setMultiline(true);
     1546        config.setMultilineOptions(initialValue, { name: "xml", htmlMode: true }, "web-inspector-html", true, true);
    15421547        this._editing = WebInspector.startEditing(this._htmlEditElement, config);
    15431548    },
  • trunk/Source/WebCore/inspector/front-end/UIUtils.js

    r146326 r147117  
    220220    },
    221221
    222     setMultiline: function(multiline)
    223     {
    224         this.multiline = multiline;
     222    /**
     223     * @param {string} initialValue
     224     * @param {Object} mode
     225     * @param {string} theme
     226     * @param {boolean=} lineWrapping
     227     * @param {boolean=} smartIndent
     228     */
     229    setMultilineOptions: function(initialValue, mode, theme, lineWrapping, smartIndent)
     230    {
     231        this.multiline = true;
     232        this.initialValue = initialValue;
     233        this.mode = mode;
     234        this.theme = theme;
     235        this.lineWrapping = lineWrapping;
     236        this.smartIndent = smartIndent;
    225237    },
    226238
     
    429441    var pasteCallback = config.pasteHandler;
    430442    var context = config.context;
    431     var oldText = getContent(element);
     443    var isMultiline = config.multiline || false;
     444    var oldText = isMultiline ? config.initialValue : getContent(element);
    432445    var moveDirection = "";
    433 
    434     element.addStyleClass("editing");
    435 
    436     var oldTabIndex = element.getAttribute("tabIndex");
    437     if (typeof oldTabIndex !== "number" || oldTabIndex < 0)
    438         element.tabIndex = 0;
    439 
    440     function blurEventListener() {
    441         editingCommitted.call(element);
     446    var oldTabIndex;
     447    var codeMirror;
     448    var cssLoadView;
     449
     450    if (isMultiline) {
     451        loadScript("CodeMirrorTextEditor.js");
     452        cssLoadView = new WebInspector.CodeMirrorCSSLoadView();
     453        cssLoadView.show(element);
     454        WebInspector.setCurrentFocusElement(element);
     455        codeMirror = window.CodeMirror(element, {
     456            mode: config.mode,
     457            lineWrapping: config.lineWrapping,
     458            smartIndent: config.smartIndent,
     459            autofocus: true,
     460            theme: config.theme,
     461            value: oldText
     462        });
     463    } else {
     464        element.addStyleClass("editing");
     465
     466        oldTabIndex = element.getAttribute("tabIndex");
     467        if (typeof oldTabIndex !== "number" || oldTabIndex < 0)
     468            element.tabIndex = 0;
     469        WebInspector.setCurrentFocusElement(element);
     470    }
     471
     472    /**
     473     * @param {Event=} e
     474     */
     475    function blurEventListener(e) {
     476        if (!isMultiline || !e || !e.relatedTarget || !e.relatedTarget.isSelfOrDescendant(element))
     477            editingCommitted.call(element);
    442478    }
    443479
    444480    function getContent(element) {
     481        if (isMultiline)
     482            return codeMirror.getValue();
     483
    445484        if (element.tagName === "INPUT" && element.type === "text")
    446485            return element.value;
    447         else
    448             return element.textContent;
     486
     487        return element.textContent;
    449488    }
    450489
     
    453492    {
    454493        WebInspector.markBeingEdited(element, false);
     494
     495        element.removeEventListener("blur", blurEventListener, isMultiline);
     496        element.removeEventListener("keydown", keyDownEventListener, true);
     497        if (pasteCallback)
     498            element.removeEventListener("paste", pasteEventListener, true);
     499
     500        WebInspector.restoreFocusFromElement(element);
     501
     502        if (isMultiline) {
     503            cssLoadView.detach();
     504            return;
     505        }
    455506
    456507        this.removeStyleClass("editing");
     
    462513        this.scrollTop = 0;
    463514        this.scrollLeft = 0;
    464 
    465         element.removeEventListener("blur", blurEventListener, false);
    466         element.removeEventListener("keydown", keyDownEventListener, true);
    467         if (pasteCallback)
    468             element.removeEventListener("paste", pasteEventListener, true);
    469 
    470         WebInspector.restoreFocusFromElement(element);
    471515    }
    472516
     
    474518    function editingCancelled()
    475519    {
    476         if (this.tagName === "INPUT" && this.type === "text")
    477             this.value = oldText;
    478         else
    479             this.textContent = oldText;
     520        if (isMultiline)
     521            codeMirror.setValue(oldText);
     522        else {
     523            if (this.tagName === "INPUT" && this.type === "text")
     524                this.value = oldText;
     525            else
     526                this.textContent = oldText;
     527        }
    480528
    481529        cleanUpAfterEditing.call(this);
     
    497545            event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey :
    498546            event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;
    499         if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl))
     547        if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !isMultiline || isMetaOrCtrl))
    500548            return "commit";
    501549        else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
    502550            return "cancel";
    503         else if (event.keyIdentifier === "U+0009") // Tab key
     551        else if (!isMultiline && event.keyIdentifier === "U+0009") // Tab key
    504552            return "move-" + (event.shiftKey ? "backward" : "forward");
    505553    }
     
    533581    }
    534582
    535     element.addEventListener("blur", blurEventListener, false);
     583    element.addEventListener("blur", blurEventListener, isMultiline);
    536584    element.addEventListener("keydown", keyDownEventListener, true);
    537585    if (pasteCallback)
    538586        element.addEventListener("paste", pasteEventListener, true);
    539587
    540     WebInspector.setCurrentFocusElement(element);
    541588    return {
    542589        cancel: editingCancelled.bind(element),
    543         commit: editingCommitted.bind(element)
     590        commit: editingCommitted.bind(element),
     591        codeMirror: codeMirror // For testing.
    544592    };
    545593}
     
    9981046}
    9991047
     1048/**
     1049 * This bogus view is needed to load/unload CodeMirror-related CSS on demand.
     1050 *
     1051 * @constructor
     1052 * @extends {WebInspector.View}
     1053 */
     1054WebInspector.CodeMirrorCSSLoadView = function()
     1055{
     1056    WebInspector.View.call(this);
     1057    this.element.addStyleClass("hidden");
     1058    this.registerRequiredCSS("cm/codemirror.css");
     1059    this.registerRequiredCSS("cm/cmdevtools.css");
     1060}
     1061
     1062WebInspector.CodeMirrorCSSLoadView.prototype = {
     1063    __proto__: WebInspector.View.prototype
     1064}
     1065
    10001066;(function() {
    10011067
  • trunk/Source/WebCore/inspector/front-end/elementsPanel.css

    r145943 r147117  
    5656}
    5757
     58#elements-content .CodeMirror {
     59    /* Consistent with the .editing class in inspector.css */
     60    -webkit-box-shadow: rgba(0, 0, 0, .5) 3px 3px 4px;
     61    outline: 1px solid rgb(66%, 66%, 66%) !important;
     62    background-color: white;
     63}
     64
     65#elements-content .CodeMirror pre {
     66    padding: 0;
     67}
     68
     69#elements-content .CodeMirror-lines {
     70    padding: 0;
     71}
     72
    5873.elements-tree-editor {
    5974    -webkit-user-select: text;
  • trunk/Source/WebCore/inspector/front-end/externs.js

    r147004 r147117  
    332332WebInspector.AceTextEditor = function(url, delegate) { }
    333333
     334/** @constructor */
     335var CodeMirror = function() { }
     336CodeMirror.prototype.replaceSelection = function(str1, str2, str3) { }
     337/** @return {Element} */
     338CodeMirror.prototype.getInputField = function() { }
     339CodeMirror.prototype.getCursor = function() { }
     340CodeMirror.prototype.setCursor = function(arg) { }
     341CodeMirror.prototype.getLine = function() { }
     342CodeMirror.prototype.getValue = function() { }
     343CodeMirror.prototype.setValue = function(arg) { }
     344CodeMirror.prototype.clearGutter = function(arg) { }
     345CodeMirror.prototype.setGutterMarker = function(arg1, arg2, arg3) { }
     346CodeMirror.prototype.clearHistory = function() { }
     347CodeMirror.prototype.markText = function(arg1, arg2, arg3) { }
     348
    334349WebInspector.suggestReload = function() { }
    335350WebInspector.reload = function() { }
  • trunk/Source/WebCore/inspector/front-end/inspector.html

    r147105 r147117  
    4242    <script type="text/javascript" src="inspector.js"></script>
    4343    <script type="text/javascript" src="UIString.js"></script>
    44     <script type="text/javascript" src="UIUtils.js"></script>
    4544    <script type="text/javascript" src="InspectorBackend.js"></script>
    4645    <script type="text/javascript" src="InspectorBackendCommands.js"></script>
     
    5049    <script type="text/javascript" src="Settings.js"></script>
    5150    <script type="text/javascript" src="View.js"></script>
     51    <script type="text/javascript" src="UIUtils.js"></script>
    5252    <script type="text/javascript" src="HelpScreen.js"></script>
    5353    <script type="text/javascript" src="InspectorFrontendHostStub.js"></script>
Note: See TracChangeset for help on using the changeset viewer.