Changeset 46429 in webkit


Ignore:
Timestamp:
Jul 27, 2009 2:58:19 PM (15 years ago)
Author:
timothy@apple.com
Message:

Adds support to the Web Inspector for tabbing through element attributes and CSS properties when editing.

2009-07-27 Joseph Pecoraro <joepeck02@gmail.com>

Inspector: Tab Through Element Attributes and CSS Properties When Editing

https://bugs.webkit.org/show_bug.cgi?id=27673

Reviewed by Timothy Hatcher.

  • inspector/front-end/ElementsTreeOutline.js: (WebInspector.ElementsTreeElement): (WebInspector.ElementsTreeElement.prototype._startEditing): refactored parameter (WebInspector.ElementsTreeElement.prototype._addNewAttribute): refactored to remove excess (WebInspector.ElementsTreeElement.prototype._triggerEditAttribute): provide an attribute name and this will start editing it (WebInspector.ElementsTreeElement.prototype._attributeEditingCommitted.moveToNextAttributeIfNeeded): move between attributes (WebInspector.ElementsTreeElement.prototype._attributeEditingCommitted):
  • inspector/front-end/StylesSidebarPane.js: (WebInspector.StylePropertiesSection.prototype.onpopulate): (WebInspector.StylePropertiesSection.prototype.findTreeElementWithName): search through treeElements for a style property name (WebInspector.StylePropertiesSection.prototype.addNewBlankProperty): initialize a blank property for adding new properties (WebInspector.StylePropertyTreeElement.prototype.updateTitle): add references to the name and value elements (WebInspector.StylePropertyTreeElement.prototype.): (WebInspector.StylePropertyTreeElement.prototype):
  • inspector/front-end/inspector.js: (WebInspector.startEditing.editingCommitted): include the move direction as a parameter to the commit callback (WebInspector.startEditing.element.handleKeyEvent): handle the tab key to specify the move direction (WebInspector.startEditing):
Location:
trunk/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r46428 r46429  
     12009-07-27  Joseph Pecoraro  <joepeck02@gmail.com>
     2
     3        Inspector: Tab Through Element Attributes and CSS Properties When Editing
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=27673
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        * inspector/front-end/ElementsTreeOutline.js:
     10        (WebInspector.ElementsTreeElement):
     11        (WebInspector.ElementsTreeElement.prototype._startEditing): refactored parameter
     12        (WebInspector.ElementsTreeElement.prototype._addNewAttribute): refactored to remove excess
     13        (WebInspector.ElementsTreeElement.prototype._triggerEditAttribute): provide an attribute name and this will start editing it
     14        (WebInspector.ElementsTreeElement.prototype._attributeEditingCommitted.moveToNextAttributeIfNeeded): move between attributes
     15        (WebInspector.ElementsTreeElement.prototype._attributeEditingCommitted):
     16        * inspector/front-end/StylesSidebarPane.js:
     17        (WebInspector.StylePropertiesSection.prototype.onpopulate):
     18        (WebInspector.StylePropertiesSection.prototype.findTreeElementWithName): search through treeElements for a style property name
     19        (WebInspector.StylePropertiesSection.prototype.addNewBlankProperty): initialize a blank property for adding new properties
     20        (WebInspector.StylePropertyTreeElement.prototype.updateTitle): add references to the name and value elements
     21        (WebInspector.StylePropertyTreeElement.prototype.):
     22        (WebInspector.StylePropertyTreeElement.prototype):
     23        * inspector/front-end/inspector.js:
     24        (WebInspector.startEditing.editingCommitted): include the move direction as a parameter to the commit callback
     25        (WebInspector.startEditing.element.handleKeyEvent): handle the tab key to specify the move direction
     26        (WebInspector.startEditing):
     27
    1282009-07-27  Mike Fenton  <mike.fenton@torchmobile.com>
    229
  • trunk/WebCore/inspector/front-end/ElementsTreeOutline.js

    r46339 r46429  
    22 * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
    33 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
     4 * Copyright (C) 2009 Joseph Pecoraro
    45 *
    56 * Redistribution and use in source and binary forms, with or without
     
    256257    // The title will be updated in onattach.
    257258    TreeElement.call(this, "", node, titleInfo.hasChildren);
    258    
    259     // Can add attributes
     259
    260260    if (this.representedObject.nodeType == Node.ELEMENT_NODE)
    261261        this._canAddAttributes = true;
     
    554554        var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute");
    555555        if (attribute)
    556             return this._startEditingAttribute(attribute, event);
     556            return this._startEditingAttribute(attribute, event.target);
    557557
    558558        var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute");
    559559        if (newAttribute)
    560             return this._addNewAttribute(event, treeElement);
     560            return this._addNewAttribute(treeElement.listItemElement);
    561561
    562562        return false;
    563563    },
    564564
    565     _addNewAttribute: function(event, treeElement)
     565    _addNewAttribute: function(listItemElement)
    566566    {
    567567        var attr = document.createElement("span");
     
    577577        attr.appendChild(value);
    578578
    579         var tag = treeElement.listItemElement.getElementsByClassName("webkit-html-tag")[0];
     579        var tag = listItemElement.getElementsByClassName("webkit-html-tag")[0];
    580580        this._insertInLastAttributePosition(tag, attr);
    581 
    582         // Start editing the attr span and highlight it first
    583         // NOTE: _startEditingAttribute only looks at the "target", so we
    584         // can fake an object here instead of passing the "event" with the
    585         // wrong target element
    586         return this._startEditingAttribute(attr, {target: attr});
    587     },
    588 
    589     _startEditingAttribute: function(attribute, event)
     581        return this._startEditingAttribute(attr, attr);
     582    },
     583
     584    _triggerEditAttribute: function(attributeName)
     585    {
     586        var attributeElements = this.listItemElement.getElementsByClassName("webkit-html-attribute-name");
     587        for (var i = 0, len = attributeElements.length; i < len; ++i) {
     588            if (attributeElements[i].textContent === attributeName) {
     589                for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) {
     590                    if (elem.nodeType !== Node.ELEMENT_NODE)
     591                        continue;
     592
     593                    if (elem.hasStyleClass("webkit-html-attribute-value"))
     594                        return this._startEditingAttribute(attributeElements[i].parentNode, elem);
     595                }
     596            }
     597        }
     598    },
     599
     600    _startEditingAttribute: function(attribute, elementForSelection)
    590601    {
    591602        if (WebInspector.isBeingEdited(attribute))
     
    618629
    619630        WebInspector.startEditing(attribute, this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName);
    620         window.getSelection().setBaseAndExtent(event.target, 0, event.target, 1);
     631        window.getSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1);
    621632
    622633        return true;
     
    636647    },
    637648
    638     _attributeEditingCommitted: function(element, newText, oldText, attributeName)
     649    _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection)
    639650    {
    640651        delete this._editing;
     652
     653        // Before we do anything, determine where we should move
     654        // next based on the current element's settings
     655        var moveToAttribute;
     656        var newAttribute;
     657        if (moveDirection) {
     658            var found = false;
     659            var attributes = this.representedObject.attributes;
     660            for (var i = 0, len = attributes.length; i < len; ++i) {
     661                if (attributes[i].name === attributeName) {
     662                    found = true;
     663                    if (moveDirection === "backward" && i > 0)
     664                        moveToAttribute = attributes[i - 1].name;
     665                    else if (moveDirection === "forward" && i < attributes.length - 1)
     666                        moveToAttribute = attributes[i + 1].name;
     667                    else if (moveDirection === "forward" && i === attributes.length - 1)
     668                        newAttribute = true;
     669                }
     670            }
     671
     672            if (!found && moveDirection === "backward")
     673                moveToAttribute = attributes[attributes.length - 1].name;
     674            else if (!found && moveDirection === "forward" && !/^\s*$/.test(newText))
     675                newAttribute = true;
     676        }
     677
     678        function moveToNextAttributeIfNeeded() {
     679            if (moveToAttribute)
     680                this._triggerEditAttribute(moveToAttribute);
     681            else if (newAttribute)
     682                this._addNewAttribute(this.listItemElement);
     683        }
    641684
    642685        var parseContainerElement = document.createElement("span");
    643686        parseContainerElement.innerHTML = "<span " + newText + "></span>";
    644687        var parseElement = parseContainerElement.firstChild;
    645         if (!parseElement || !parseElement.hasAttributes()) {
     688
     689        if (!parseElement) {
    646690            this._editingCancelled(element, attributeName);
     691            moveToNextAttributeIfNeeded.call(this);
     692            return;
     693        }
     694
     695        if (!parseElement.hasAttributes()) {
     696            InspectorController.inspectedWindow().Element.prototype.removeAttribute.call(this.representedObject, attributeName);
     697            this._updateTitle();
     698            moveToNextAttributeIfNeeded.call(this);
    647699            return;
    648700        }
     
    652704            var attr = parseElement.attributes[i];
    653705            foundOriginalAttribute = foundOriginalAttribute || attr.name === attributeName;
    654             InspectorController.inspectedWindow().Element.prototype.setAttribute.call(this.representedObject, attr.name, attr.value);
     706            try {
     707                InspectorController.inspectedWindow().Element.prototype.setAttribute.call(this.representedObject, attr.name, attr.value);
     708            } catch(e) {} // ignore invalid attribute (innerHTML doesn't throw errors, but this can)
    655709        }
    656710
     
    661715
    662716        this.treeOutline.focusedNodeChanged(true);
     717
     718        moveToNextAttributeIfNeeded.call(this);
    663719    },
    664720
  • trunk/WebCore/inspector/front-end/StylesSidebarPane.js

    r42224 r46429  
    11/*
    22 * Copyright (C) 2007 Apple Inc.  All rights reserved.
     3 * Copyright (C) 2009 Joseph Pecoraro
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    388389            }
    389390        }
     391
     392        if (this._afterUpdate) {
     393            this._afterUpdate(this);
     394            delete this._afterUpdate;
     395        }
    390396    },
    391397
     
    426432            this.propertiesTreeOutline.appendChild(item);
    427433        }
     434    },
     435
     436    findTreeElementWithName: function(name)
     437    {
     438        var treeElement = this.propertiesTreeOutline.children[0];
     439        while (treeElement) {
     440            if (treeElement.name === name)
     441                return treeElement;
     442            treeElement = treeElement.traverseNextTreeElement(true, null, true);
     443        }
     444        return null;
     445    },
     446
     447    addNewBlankProperty: function()
     448    {
     449        var item = new WebInspector.StylePropertyTreeElement(this.styleRule.style, "", false, false, false, false);
     450        this.propertiesTreeOutline.appendChild(item);
     451        item.listItemElement.textContent = "";
     452        item._newProperty = true;
     453        return item;
    428454    }
    429455}
     
    559585        nameElement.className = "name";
    560586        nameElement.textContent = this.name;
     587        this.nameElement = nameElement;
    561588
    562589        var valueElement = document.createElement("span");
    563590        valueElement.className = "value";
    564591        valueElement.innerHTML = htmlValue;
     592        this.valueElement = valueElement;
    565593
    566594        if (priority) {
     
    844872    },
    845873
    846     editingCommitted: function(element, userInput, previousContent, context)
     874    editingCommitted: function(element, userInput, previousContent, context, moveDirection)
    847875    {
    848876        this.editingEnded(context);
    849877
    850         if (userInput === previousContent)
    851             return; // nothing changed, so do nothing else
    852 
    853         this.applyStyleText(userInput, true);
     878        // Determine where to move to before making changes
     879        var newProperty = false;
     880        var moveToPropertyName;
     881        var moveTo = (moveDirection === "forward" ? this.nextSibling : this.previousSibling);
     882        if (moveTo)
     883            moveToPropertyName = moveTo.name;
     884        else if (moveDirection === "forward")
     885            newProperty = true;
     886
     887        // Make the Changes and trigger the moveToNextCallback after updating
     888        var blankInput = /^\s*$/.test(userInput);
     889        if (userInput !== previousContent || (this._newProperty && blankInput)) { // only if something changed, or adding a new style and it was blank
     890            this.treeOutline.section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput);
     891            this.applyStyleText(userInput, true);
     892        } else
     893            moveToNextCallback(this._newProperty, false, this.treeOutline.section, false);
     894
     895        // The Callback to start editing the next property
     896        function moveToNextCallback(alreadyNew, valueChanged, section) {
     897            if (!moveDirection)
     898                return;
     899
     900            // User just tabbed through without changes
     901            if (moveTo && moveTo.parent) {
     902                moveTo.startEditing(moveTo.valueElement);
     903                return;
     904            }
     905
     906            // User has made a change then tabbed, wiping all the original treeElements,
     907            // recalculate the new treeElement for the same property we were going to edit next
     908            if (moveTo && !moveTo.parent) {
     909                var treeElement = section.findTreeElementWithName(moveToPropertyName);
     910                if (treeElement)
     911                    treeElement.startEditing(treeElement.valueElement);
     912                return;
     913            }
     914
     915            // Create a new attribute in this section
     916            if (newProperty) {
     917                if (alreadyNew && !valueChanged)
     918                    return;
     919
     920                var item = section.addNewBlankProperty();
     921                item.startEditing();
     922            }
     923        }
    854924    },
    855925
     
    877947        if (!styleTextLength) {
    878948            if (updateInterface) {
    879                 // The user deleted the everything, so remove the tree element and update.
     949                // The user deleted everything, so remove the tree element and update.
     950                if (!this._newProperty)
     951                    delete this.treeOutline.section._afterUpdate;
    880952                if (this.treeOutline.section && this.treeOutline.section.pane)
    881953                    this.treeOutline.section.pane.update();
     
    887959        if (!tempStyle.length) {
    888960            // The user typed something, but it didn't parse. Just abort and restore
    889             // the original title for this property.
     961            // the original title for this property.  If this was a new attribute and
     962            // we couldn't parse, then just remove it.
     963            if (this._newProperty) {
     964                this.parent.removeChild(this);
     965                return;
     966            }
    890967            if (updateInterface)
    891968                this.updateTitle();
  • trunk/WebCore/inspector/front-end/inspector.js

    r46397 r46429  
    13201320    var oldText = element.textContent;
    13211321    var oldHandleKeyEvent = element.handleKeyEvent;
     1322    var moveDirection = "";
    13221323
    13231324    element.addStyleClass("editing");
     
    13571358        cleanUpAfterEditing.call(this);
    13581359
    1359         committedCallback(this, this.textContent, oldText, context);
     1360        committedCallback(this, this.textContent, oldText, context, moveDirection);
    13601361    }
    13611362
     
    13731374            event.preventDefault();
    13741375            event.handled = true;
    1375         }
     1376        } else if (event.keyIdentifier === "U+0009") // Tab key
     1377            moveDirection = (event.shiftKey ? "backward" : "forward");
    13761378    }
    13771379
Note: See TracChangeset for help on using the changeset viewer.