Changeset 121902 in webkit


Ignore:
Timestamp:
Jul 5, 2012 7:19:54 AM (12 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: Add support for keyboard increment / decrement on numbers in attributes in Elements Panel
https://bugs.webkit.org/show_bug.cgi?id=89586

Patch by Vivek Galatage <vivekgalatage@gmail.com> on 2012-07-05
Reviewed by Pavel Feldman

Refactoring the key events while editing style property values. Migrated the code to UIUtils.js and referred
from StylesSidebarPane.js, ElementsTreeOutline.js and MetricsSidebarPane.js.

No new tests as code refactoring and UI feature added to ElementsTreeOutline.js

  • inspector/front-end/ElementsTreeOutline.js:

(WebInspector.ElementsTreeElement.prototype._startEditingAttribute.handleKeyDownEvents):
(WebInspector.ElementsTreeElement.prototype._startEditingAttribute):

  • inspector/front-end/MetricsSidebarPane.js:

(WebInspector.MetricsSidebarPane.prototype._handleKeyDown.finishHandler):
(WebInspector.MetricsSidebarPane.prototype._handleKeyDown.customNumberHandler):
(WebInspector.MetricsSidebarPane.prototype._handleKeyDown):

  • inspector/front-end/StylesSidebarPane.js:

(WebInspector.StylesSidebarPane.prototype._handleNameOrValueUpDown.finishHandler):
(WebInspector.StylesSidebarPane.prototype._handleNameOrValueUpDown):

  • inspector/front-end/UIUtils.js:

(WebInspector._modifiedHexValue):
(WebInspector._modifiedFloatNumber):
(WebInspector.handleElementValueModifications):

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r121900 r121902  
     12012-07-05  Vivek Galatage  <vivekgalatage@gmail.com>
     2
     3        Web Inspector: Add support for keyboard increment / decrement on numbers in attributes in Elements Panel
     4        https://bugs.webkit.org/show_bug.cgi?id=89586
     5
     6        Reviewed by Pavel Feldman
     7
     8        Refactoring the key events while editing style property values. Migrated the code to UIUtils.js and referred
     9        from StylesSidebarPane.js, ElementsTreeOutline.js and MetricsSidebarPane.js.
     10
     11        No new tests as code refactoring and UI feature added to ElementsTreeOutline.js
     12
     13        * inspector/front-end/ElementsTreeOutline.js:
     14        (WebInspector.ElementsTreeElement.prototype._startEditingAttribute.handleKeyDownEvents):
     15        (WebInspector.ElementsTreeElement.prototype._startEditingAttribute):
     16        * inspector/front-end/MetricsSidebarPane.js:
     17        (WebInspector.MetricsSidebarPane.prototype._handleKeyDown.finishHandler):
     18        (WebInspector.MetricsSidebarPane.prototype._handleKeyDown.customNumberHandler):
     19        (WebInspector.MetricsSidebarPane.prototype._handleKeyDown):
     20        * inspector/front-end/StylesSidebarPane.js:
     21        (WebInspector.StylesSidebarPane.prototype._handleNameOrValueUpDown.finishHandler):
     22        (WebInspector.StylesSidebarPane.prototype._handleNameOrValueUpDown):
     23        * inspector/front-end/UIUtils.js:
     24        (WebInspector._modifiedHexValue):
     25        (WebInspector._modifiedFloatNumber):
     26        (WebInspector.handleElementValueModifications):
     27
    1282012-07-05  Gabor Rapcsanyi  <rgabor@webkit.org>
    229
  • trunk/Source/WebCore/inspector/front-end/ElementsTreeOutline.js

    r121896 r121902  
    12781278
    12791279        var config = new WebInspector.EditingConfig(this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName);
     1280       
     1281        function handleKeyDownEvents(event)
     1282        {
     1283            var isMetaOrCtrl = WebInspector.isMac() ?
     1284                event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey :
     1285                event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;
     1286            if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl))
     1287                return "commit";
     1288            else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
     1289                return "cancel";
     1290            else if (event.keyIdentifier === "U+0009") // Tab key
     1291                return "move-" + (event.shiftKey ? "backward" : "forward");
     1292            else {
     1293                WebInspector.handleElementValueModifications(event, attribute);
     1294                return "";
     1295            }
     1296        }
     1297
     1298        config.customFinishHandler = handleKeyDownEvents.bind(this);
     1299       
    12801300        this._editing = WebInspector.startEditing(attribute, config);
    12811301
  • trunk/Source/WebCore/inspector/front-end/MetricsSidebarPane.js

    r111551 r121902  
    301301    _handleKeyDown: function(context, styleProperty, event)
    302302    {
    303         if (!/^(?:Page)?(?:Up|Down)$/.test(event.keyIdentifier))
    304             return;
    305303        var element = event.currentTarget;
    306304
    307         var selection = window.getSelection();
    308         if (!selection.rangeCount)
    309             return;
    310 
    311         var selectionRange = selection.getRangeAt(0);
    312         if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element))
    313             return;
    314 
    315         var originalValue = element.textContent;
    316         var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StylesSidebarPane.StyleValueDelimiters, element);
    317         var wordString = wordRange.toString();
    318 
    319         var matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
    320         var replacementString;
    321         if (matches && matches.length) {
    322             var prefix = matches[1];
    323             var suffix = matches[3];
    324             var number = WebInspector.StylesSidebarPane.alteredFloatNumber(parseFloat(matches[2]), event);
    325             if (number === null) {
    326                 // Need to check for null explicitly.
    327                 return;
    328             }
    329 
     305        function finishHandler(originalValue, replacementString)
     306        {
     307            this._applyUserInput(element, replacementString, originalValue, context, false);
     308        }
     309
     310        function customNumberHandler(number)
     311        {
    330312            if (styleProperty !== "margin" && number < 0)
    331313                number = 0;
    332 
    333             replacementString = prefix + number + suffix;
    334         }
    335         if (!replacementString)
    336             return;
    337 
    338         var replacementTextNode = document.createTextNode(replacementString);
    339 
    340         wordRange.deleteContents();
    341         wordRange.insertNode(replacementTextNode);
    342 
    343         var finalSelectionRange = document.createRange();
    344         finalSelectionRange.setStart(replacementTextNode, 0);
    345         finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
    346 
    347         selection.removeAllRanges();
    348         selection.addRange(finalSelectionRange);
    349 
    350         event.handled = true;
    351         event.preventDefault();
    352         this._applyUserInput(element, replacementString, originalValue, context, false);
     314            return number;
     315        }
     316
     317        WebInspector.handleElementValueModifications(event, element, finishHandler.bind(this), undefined, customNumberHandler);
    353318    },
    354319
  • trunk/Source/WebCore/inspector/front-end/StylesSidebarPane.js

    r121860 r121902  
    115115}
    116116
    117 WebInspector.StylesSidebarPane.StyleValueDelimiters = " \xA0\t\n\"':;,/()";
    118 
    119 
    120117// Keep in sync with RenderStyleConstants.h PseudoId enum. Array below contains pseudo id names for corresponding enum indexes.
    121118// First item is empty due to its artificial NOPSEUDO nature in the enum.
     
    135132    "-webkit-resizer", "-webkit-inner-spin-button", "-webkit-outer-spin-button"
    136133];
    137 
    138 WebInspector.StylesSidebarPane.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/;
    139 
    140 WebInspector.StylesSidebarPane.alteredFloatNumber = function(number, event)
    141 {
    142     var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
    143 
    144     // Jump by 10 when shift is down or jump by 0.1 when Alt/Option is down.
    145     // Also jump by 10 for page up and down, or by 100 if shift is held with a page key.
    146     var changeAmount = 1;
    147     if (event.shiftKey && !arrowKeyPressed)
    148         changeAmount = 100;
    149     else if (event.shiftKey || !arrowKeyPressed)
    150         changeAmount = 10;
    151     else if (event.altKey)
    152         changeAmount = 0.1;
    153 
    154     if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown")
    155         changeAmount *= -1;
    156 
    157     // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns.
    158     // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
    159     var result = Number((number + changeAmount).toFixed(6));
    160     if (!String(result).match(WebInspector.StylesSidebarPane.CSSNumberRegex))
    161         return null;
    162 
    163     return result;
    164 }
    165 
    166 WebInspector.StylesSidebarPane.alteredHexNumber = function(hexString, event)
    167 {
    168     var number = parseInt(hexString, 16);
    169     if (isNaN(number) || !isFinite(number))
    170         return hexString;
    171 
    172     var maxValue = Math.pow(16, hexString.length) - 1;
    173     var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
    174 
    175     var delta;
    176     if (arrowKeyPressed)
    177         delta = (event.keyIdentifier === "Up") ? 1 : -1;
    178     else
    179         delta = (event.keyIdentifier === "PageUp") ? 16 : -16;
    180 
    181     if (event.shiftKey)
    182         delta *= 16;
    183 
    184     var result = number + delta;
    185     if (result < 0)
    186         result = 0; // Color hex values are never negative, so clamp to 0.
    187     else if (result > maxValue)
    188         return hexString;
    189 
    190     // Ensure the result length is the same as the original hex value.
    191     var resultString = result.toString(16).toUpperCase();
    192     for (var i = 0, lengthDelta = hexString.length - resultString.length; i < lengthDelta; ++i)
    193         resultString = "0" + resultString;
    194     return resultString;
    195 }
    196134
    197135WebInspector.StylesSidebarPane.canonicalPropertyName = function(name)
     
    25392477{
    25402478    // Use the same callback both for applyItemCallback and acceptItemCallback.
    2541     WebInspector.TextPrompt.call(this, this._buildPropertyCompletions.bind(this), WebInspector.StylesSidebarPane.StyleValueDelimiters);
     2479    WebInspector.TextPrompt.call(this, this._buildPropertyCompletions.bind(this), WebInspector.StyleValueDelimiters);
    25422480    this.setSuggestBoxEnabled("generic-suggest");
    25432481    this._cssCompletions = cssCompletions;
     
    25742512    _handleNameOrValueUpDown: function(event)
    25752513    {
    2576         // Handle numeric value increment/decrement only at this point.
    2577         if (!this._isEditingName && this._handleUpOrDownValue(event))
    2578             return true;
    2579 
    2580         return false;
    2581     },
    2582 
    2583     _handleUpOrDownValue: function(event)
    2584     {
    2585         var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
    2586         var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown");
    2587         if (!arrowKeyPressed && !pageKeyPressed)
    2588             return false;
    2589 
    2590         var selection = window.getSelection();
    2591         if (!selection.rangeCount)
    2592             return false;
    2593 
    2594         var selectionRange = selection.getRangeAt(0);
    2595         if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(this._sidebarPane.valueElement))
    2596             return false;
    2597 
    2598         var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StylesSidebarPane.StyleValueDelimiters, this._sidebarPane.valueElement);
    2599         var wordString = wordRange.toString();
    2600         if (this._isValueSuggestion(wordString))
    2601             return false;
    2602 
    2603         var replacementString;
    2604         var prefix, suffix, number;
    2605 
    2606         var matches;
    2607         matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString);
    2608         if (matches && matches.length) {
    2609             prefix = matches[1];
    2610             suffix = matches[3];
    2611             number = WebInspector.StylesSidebarPane.alteredHexNumber(matches[2], event);
    2612 
    2613             replacementString = prefix + number + suffix;
    2614         } else {
    2615             matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
    2616             if (matches && matches.length) {
    2617                 prefix = matches[1];
    2618                 suffix = matches[3];
    2619                 number = WebInspector.StylesSidebarPane.alteredFloatNumber(parseFloat(matches[2]), event);
    2620                 if (number === null) {
    2621                     // Need to check for null explicitly.
    2622                     return false;
    2623                 }
    2624 
    2625                 replacementString = prefix + number + suffix;
    2626             }
    2627         }
    2628 
    2629         if (replacementString) {
    2630             var replacementTextNode = document.createTextNode(replacementString);
    2631 
    2632             wordRange.deleteContents();
    2633             wordRange.insertNode(replacementTextNode);
    2634 
    2635             var finalSelectionRange = document.createRange();
    2636             finalSelectionRange.setStart(replacementTextNode, 0);
    2637             finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
    2638 
    2639             selection.removeAllRanges();
    2640             selection.addRange(finalSelectionRange);
    2641 
    2642             event.handled = true;
    2643             event.preventDefault();
    2644 
     2514        function finishHandler(originalValue, replacementString)
     2515        {
    26452516            // Synthesize property text disregarding any comments, custom whitespace etc.
    26462517            this._sidebarPane.applyStyleText(this._sidebarPane.nameElement.textContent + ": " + this._sidebarPane.valueElement.textContent, false, false, false);
    2647 
     2518        }
     2519   
     2520        // Handle numeric value increment/decrement only at this point.
     2521        if (!this._isEditingName && WebInspector.handleElementValueModifications(event, this._sidebarPane.valueElement, finishHandler.bind(this), this._isValueSuggestion.bind(this)))
    26482522            return true;
    2649         }
     2523
    26502524        return false;
    26512525    },
  • trunk/Source/WebCore/inspector/front-end/UIUtils.js

    r121843 r121902  
    277277}
    278278
     279WebInspector.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/;
     280
     281WebInspector.StyleValueDelimiters = " \xA0\t\n\"':;,/()";
     282
     283/**
     284 * @param {string} hexString
     285 * @param {Event} event
     286 */
     287WebInspector._modifiedHexValue = function(hexString, event)
     288{
     289    var number = parseInt(hexString, 16);
     290    if (isNaN(number) || !isFinite(number))
     291        return hexString;
     292
     293    var maxValue = Math.pow(16, hexString.length) - 1;
     294    var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
     295
     296    var delta;
     297    if (arrowKeyPressed)
     298        delta = (event.keyIdentifier === "Up") ? 1 : -1;
     299    else
     300        delta = (event.keyIdentifier === "PageUp") ? 16 : -16;
     301
     302    if (event.shiftKey)
     303        delta *= 16;
     304
     305    var result = number + delta;
     306    if (result < 0)
     307        result = 0; // Color hex values are never negative, so clamp to 0.
     308    else if (result > maxValue)
     309        return hexString;
     310
     311    // Ensure the result length is the same as the original hex value.
     312    var resultString = result.toString(16).toUpperCase();
     313    for (var i = 0, lengthDelta = hexString.length - resultString.length; i < lengthDelta; ++i)
     314        resultString = "0" + resultString;
     315    return resultString;
     316}
     317
     318/**
     319 * @param {number} number
     320 * @param {Event} event
     321 */
     322WebInspector._modifiedFloatNumber = function(number, event)
     323{
     324    var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
     325
     326    // Jump by 10 when shift is down or jump by 0.1 when Alt/Option is down.
     327    // Also jump by 10 for page up and down, or by 100 if shift is held with a page key.
     328    var changeAmount = 1;
     329    if (event.shiftKey && !arrowKeyPressed)
     330        changeAmount = 100;
     331    else if (event.shiftKey || !arrowKeyPressed)
     332        changeAmount = 10;
     333    else if (event.altKey)
     334        changeAmount = 0.1;
     335
     336    if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown")
     337        changeAmount *= -1;
     338
     339    // Make the new number and constrain it to a precision of 6, this matches numbers the engine returns.
     340    // Use the Number constructor to forget the fixed precision, so 1.100000 will print as 1.1.
     341    var result = Number((number + changeAmount).toFixed(6));
     342    if (!String(result).match(WebInspector.CSSNumberRegex))
     343        return null;
     344
     345    return result;
     346}
     347
     348/**
     349  * @param {Event} event
     350  * @param {Element} element
     351  * @param {function(string,string)=} finishHandler
     352  * @param {function(string)=} suggestionHandler
     353  * @param {function(number):number=} customNumberHandler
     354 */
     355WebInspector.handleElementValueModifications = function(event, element, finishHandler, suggestionHandler, customNumberHandler)
     356{
     357    var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down");
     358    var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown");
     359    if (!arrowKeyPressed && !pageKeyPressed)
     360        return false;
     361
     362    var selection = window.getSelection();
     363    if (!selection.rangeCount)
     364        return false;
     365
     366    var selectionRange = selection.getRangeAt(0);
     367    if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element))
     368        return false;
     369
     370    var originalValue = element.textContent;
     371    var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StyleValueDelimiters, element);
     372    var wordString = wordRange.toString();
     373   
     374    if (suggestionHandler && suggestionHandler(wordString))
     375        return false;
     376
     377    var replacementString;
     378    var prefix, suffix, number;
     379
     380    var matches;
     381    matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString);
     382    if (matches && matches.length) {
     383        prefix = matches[1];
     384        suffix = matches[3];
     385        number = WebInspector._modifiedHexValue(matches[2], event);
     386       
     387        if (customNumberHandler)
     388            number = customNumberHandler(number);
     389
     390        replacementString = prefix + number + suffix;
     391    } else {
     392        matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString);
     393        if (matches && matches.length) {
     394            prefix = matches[1];
     395            suffix = matches[3];
     396            number = WebInspector._modifiedFloatNumber(parseFloat(matches[2]), event);
     397           
     398            // Need to check for null explicitly.
     399            if (number === null)               
     400                return false;
     401           
     402            if (customNumberHandler)
     403                number = customNumberHandler(number);
     404
     405            replacementString = prefix + number + suffix;
     406        }
     407    }
     408
     409    if (replacementString) {
     410        var replacementTextNode = document.createTextNode(replacementString);
     411
     412        wordRange.deleteContents();
     413        wordRange.insertNode(replacementTextNode);
     414
     415        var finalSelectionRange = document.createRange();
     416        finalSelectionRange.setStart(replacementTextNode, 0);
     417        finalSelectionRange.setEnd(replacementTextNode, replacementString.length);
     418
     419        selection.removeAllRanges();
     420        selection.addRange(finalSelectionRange);
     421
     422        event.handled = true;
     423        event.preventDefault();
     424               
     425        if (finishHandler)
     426            finishHandler(originalValue, replacementString);
     427
     428        return true;
     429    }
     430    return false;
     431}
     432
    279433/**
    280434 * @param {Element} element
Note: See TracChangeset for help on using the changeset viewer.