Changeset 46690 in webkit
- Timestamp:
- Aug 2, 2009 12:41:56 AM (15 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r46689 r46690 1 2009-07-30 Joseph Pecoraro <joepeck02@gmail.com> 2 3 Reviewed by Timothy Hatcher. 4 5 Inspector: let me *edit* css styles in the web inspector. 6 https://bugs.webkit.org/show_bug.cgi?id=27124 7 8 * English.lproj/localizedStrings.js: 9 * inspector/front-end/ElementsPanel.js: 10 (WebInspector.ElementsPanel): added property stylesheet pointing to 1 stylesheet added to the page if needed 11 * inspector/front-end/StylesSidebarPane.js: 12 (WebInspector.StylesSidebarPane.prototype.update): handle blank sections 13 (WebInspector.StylesSidebarPane.prototype.addBlankSection): blank section in the correct position 14 (WebInspector.StylesSidebarPane.prototype.appropriateSelectorForNode): helper to get a nice selector for the selectd node 15 (WebInspector.StylePropertiesSection): 16 (WebInspector.StylePropertiesSection.prototype.expand): 17 (WebInspector.StylePropertiesSection.prototype.isPropertyInherited): 18 (WebInspector.StylePropertiesSection.prototype.isPropertyOverloaded): 19 (WebInspector.StylePropertiesSection.prototype.addNewBlankProperty): 20 (WebInspector.StylePropertiesSection.prototype._dblclickEmptySpace): easily create new properties 21 (WebInspector.StylePropertiesSection.prototype._dblclickSelector): 22 (WebInspector.StylePropertiesSection.prototype.startEditingSelector): allow for editing selectors 23 (WebInspector.StylePropertiesSection.prototype.editingSelectorCommitted): 24 (WebInspector.StylePropertiesSection.prototype.editingSelectorCancelled): 25 (WebInspector.StylePropertiesSection.prototype._doesSelectorAffectSelectedNode): helper to check if a selector applies to the selected node 26 (WebInspector.BlankStylePropertiesSection.prototype._dblclick): 27 (WebInspector.BlankStylePropertiesSection.prototype.startEditing): 28 (WebInspector.BlankStylePropertiesSection.prototype.editingCancelled): 29 (WebInspector.BlankStylePropertiesSection.prototype.editingCommitted): 30 (WebInspector.BlankStylePropertiesSection.prototype.makeNormal): morph into a StylePropertiesSection 31 (WebInspector.StylePropertyTreeElement.prototype): 32 (WebInspector.StylePropertyTreeElement.prototype.): 33 * inspector/front-end/inspector.css: 34 1 35 2009-07-31 Anton Muhin <antonm@chromium.org> 2 36 -
trunk/WebCore/inspector/front-end/ElementsPanel.js
r46687 r46690 114 114 this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this)); 115 115 116 this.stylesheet = null; 117 116 118 this.reset(); 117 119 } -
trunk/WebCore/inspector/front-end/StylesSidebarPane.js
r46429 r46690 69 69 for (var i = 0; i < this.sections.length; ++i) { 70 70 var section = this.sections[i]; 71 if (section._blank) 72 continue; 71 73 if (section.computedStyle) 72 74 section.styleRule.style = node.ownerDocument.defaultView.getComputedStyle(node); 73 var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle };75 var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle, rule: section.rule }; 74 76 styleRules.push(styleRule); 75 77 } … … 92 94 } 93 95 94 if (node.style && (node.style.length || Object.hasProperties(node.style.__disabledProperties))) { 95 var inlineStyle = { selectorText: WebInspector.UIString("Inline Style Attribute"), style: node.style }; 96 // Always Show element's Style Attributes 97 if (node.nodeType === Node.ELEMENT_NODE) { 98 var inlineStyle = { selectorText: WebInspector.UIString("Style Attribute"), style: node.style, isAttribute: true }; 96 99 inlineStyle.subtitle = WebInspector.UIString("element’s “%s” attribute", "style"); 97 100 styleRules.push(inlineStyle); … … 103 106 for (var i = (matchedStyleRules.length - 1); i >= 0; --i) { 104 107 var rule = matchedStyleRules[i]; 105 styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet });108 styleRules.push({ style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet, rule: rule }); 106 109 } 107 110 } … … 128 131 var styleRule = styleRules[i]; 129 132 if (styleRule.computedStyle) 133 continue; 134 if (styleRule.section && styleRule.section.noAffect) 130 135 continue; 131 136 … … 224 229 delete styleRule.editable; 225 230 231 var isAttribute = styleRule.isAttribute; 232 delete styleRule.isAttribute; 233 226 234 // Default editable to true if it was omitted. 227 235 if (typeof editable === "undefined") … … 237 245 else if (computedStyle) 238 246 section.collapse(true); 247 else if (isAttribute && styleRule.style.length === 0) 248 section.collapse(true); 239 249 else 240 250 section.expand(true); … … 243 253 this.sections.push(section); 244 254 } 245 } 255 256 this.addBlankSection(); 257 } 258 }, 259 260 addBlankSection: function() 261 { 262 var blankSection = new WebInspector.BlankStylePropertiesSection(); 263 blankSection.pane = this; 264 265 this.bodyElement.insertBefore(blankSection.element, this.bodyElement.firstChild.nextSibling.nextSibling); // 0 is computed, 1 is element.style 266 var computed = this.sections.shift(); 267 var elementStyle = this.sections.shift(); 268 this.sections.unshift(blankSection); 269 this.sections.unshift(elementStyle); 270 this.sections.unshift(computed); 271 }, 272 273 appropriateSelectorForNode: function() 274 { 275 var node = this.node; 276 if (!node) 277 return; 278 279 if (node.id) 280 return "#" + node.id; 281 282 if (node.className) 283 return "." + node.className.replace(/\s+/, "."); 284 285 var nodeName = node.nodeName.toLowerCase(); 286 if (nodeName === "input" && node.type) 287 return nodeName + "[type=\"" + node.type + "\"]"; 288 289 return nodeName; 246 290 } 247 291 } … … 252 296 { 253 297 WebInspector.PropertiesSection.call(this, styleRule.selectorText); 298 this.titleElement.addEventListener("click", function(e) { e.stopPropagation(); }, false); 299 this.titleElement.addEventListener("dblclick", this._dblclickSelector.bind(this), false); 300 this.element.addEventListener("dblclick", this._dblclickEmptySpace.bind(this), false); 254 301 255 302 this.styleRule = styleRule; 303 this.rule = this.styleRule.rule; 256 304 this.computedStyle = computedStyle; 257 305 this.editable = (editable && !computedStyle); … … 301 349 else if (isUser) 302 350 subtitle = WebInspector.UIString("user stylesheet"); 351 else if (this.styleRule.parentStyleSheet === WebInspector.panels.elements.stylesheet) 352 subtitle = WebInspector.UIString("via inspector"); 303 353 else 304 354 subtitle = WebInspector.UIString("inline stylesheet"); … … 310 360 this.identifier = styleRule.selectorText; 311 361 if (this.subtitle) 312 this.identifier += ":" + this.subtitleElement.textContent; 362 this.identifier += ":" + this.subtitleElement.textContent; 313 363 } 314 364 … … 327 377 expand: function(dontRememberState) 328 378 { 379 if (this._blank) 380 return; 381 329 382 WebInspector.PropertiesSection.prototype.expand.call(this); 330 383 if (dontRememberState) … … 349 402 isPropertyInherited: function(property) 350 403 { 351 if (!this.computedStyle || !this._usedProperties )404 if (!this.computedStyle || !this._usedProperties || this.noAffect) 352 405 return false; 353 406 // These properties should always show for Computed Style. … … 358 411 isPropertyOverloaded: function(property, shorthand) 359 412 { 360 if (this.computedStyle || !this._usedProperties )413 if (this.computedStyle || !this._usedProperties || this.noAffect) 361 414 return false; 362 415 … … 452 505 item._newProperty = true; 453 506 return item; 507 }, 508 509 _dblclickEmptySpace: function(event) 510 { 511 this.expand(); 512 this.addNewBlankProperty().startEditing(); 513 }, 514 515 _dblclickSelector: function(event) 516 { 517 if (!this.editable) 518 return; 519 520 if (!this.rule && this.propertiesTreeOutline.children.length === 0) { 521 this.expand(); 522 this.addNewBlankProperty().startEditing(); 523 return; 524 } 525 526 if (!this.rule) 527 return; 528 529 this.startEditingSelector(); 530 event.stopPropagation(); 531 }, 532 533 startEditingSelector: function() 534 { 535 var element = this.titleElement; 536 if (WebInspector.isBeingEdited(element)) 537 return; 538 539 var context = this.styleRule.selectorText; 540 WebInspector.startEditing(this.titleElement, this.editingSelectorCommitted.bind(this), this.editingSelectorCancelled.bind(this), context); 541 window.getSelection().setBaseAndExtent(element, 0, element, 1); 542 }, 543 544 editingSelectorCommitted: function(element, newContent, oldContent, context, moveDirection) 545 { 546 function moveToNextIfNeeded() { 547 if (!moveDirection || moveDirection !== "forward") 548 return; 549 550 this.expand(); 551 if (this.propertiesTreeOutline.children.length === 0) 552 this.addNewBlankProperty().startEditing(); 553 else { 554 var item = this.propertiesTreeOutline.children[0] 555 item.startEditing(item.valueElement); 556 } 557 } 558 559 if (newContent === oldContent) 560 return moveToNextIfNeeded.call(this); 561 562 try { 563 var stylesheet = this.rule.parentStyleSheet; 564 stylesheet.addRule(newContent); 565 var newRule = stylesheet.cssRules[stylesheet.cssRules.length - 1]; 566 newRule.style.cssText = this.styleRule.style.cssText; 567 } catch (e) { 568 // Invalid Syntax for a Selector 569 this.editingSelectorCancelled(element, context); 570 return moveToNextIfNeeded.call(this); 571 } 572 573 if (!this._doesSelectorAffectSelectedNode(newContent)) { 574 this.noAffect = true; 575 this.element.addStyleClass("no-affect"); 576 } else { 577 delete this.noAffect; 578 this.element.removeStyleClass("no-affect"); 579 } 580 581 var parentRules = this.rule.parentStyleSheet.cssRules; 582 for (var i = 0; i < parentRules.length; ++i) { 583 if (parentRules[i] === this.rule) { 584 this.rule.parentStyleSheet.removeRule(i); 585 break; 586 } 587 } 588 589 this.rule = newRule; 590 this.styleRule = { section: this, style: newRule.style, selectorText: newRule.selectorText, parentStyleSheet: newRule.parentStyleSheet, rule: newRule }; 591 this.pane.update(null, true); 592 moveToNextIfNeeded.call(this); 593 }, 594 595 editingSelectorCancelled: function(element, context) 596 { 597 element.textContent = context; 598 }, 599 600 _doesSelectorAffectSelectedNode: function(selector) 601 { 602 var selectedNode = this.pane.node; 603 var nodes = selectedNode.ownerDocument.querySelectorAll(selector); 604 for (var i = 0; i < nodes.length; ++i) { 605 if (nodes[i] === selectedNode) 606 return true; 607 } 608 609 return false; 454 610 } 455 611 } 456 612 457 613 WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; 614 615 WebInspector.BlankStylePropertiesSection = function() 616 { 617 WebInspector.PropertiesSection.call(this, WebInspector.UIString("Double-Click to Add"), null); 618 619 this._blank = true; 620 this._dblclickListener = this._dblclick.bind(this); 621 this.element.addStyleClass("blank-section"); 622 this.titleElement.addStyleClass("blank-title"); 623 this.titleElement.addEventListener("click", function(e) { e.stopPropagation(); }, false); 624 this.titleElement.addEventListener("dblclick", this._dblclickListener, false); 625 } 626 627 WebInspector.BlankStylePropertiesSection.prototype = { 628 _dblclick: function(event) 629 { 630 this.startEditing(); 631 }, 632 633 startEditing: function() 634 { 635 var element = this.titleElement; 636 if (WebInspector.isBeingEdited(element)) 637 return; 638 639 this.titleElement.textContent = this.pane.appropriateSelectorForNode(); 640 this.titleElement.removeStyleClass("blank-title"); 641 WebInspector.startEditing(this.titleElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), ""); 642 window.getSelection().setBaseAndExtent(element, 0, element, 1); 643 }, 644 645 editingCancelled: function() 646 { 647 this.titleElement.textContent = WebInspector.UIString("Double-Click to Add"); 648 this.titleElement.addStyleClass("blank-title"); 649 }, 650 651 editingCommitted: function(element, newContent, oldContent, context) 652 { 653 var stylesheet = WebInspector.panels.elements.stylesheet; 654 if (!stylesheet) { 655 var inspectedDocument = InspectorController.inspectedWindow().document; 656 var head = inspectedDocument.getElementsByTagName("head")[0]; 657 var styleElement = inspectedDocument.createElement("style"); 658 styleElement.type = "text/css"; 659 head.appendChild(styleElement); 660 stylesheet = inspectedDocument.styleSheets[inspectedDocument.styleSheets.length - 1]; 661 WebInspector.panels.elements.stylesheet = stylesheet; 662 } 663 664 try { 665 stylesheet.addRule(newContent); 666 } catch (e) { 667 // Invalid Syntax for a Selector 668 this.editingCancelled(); 669 return; 670 } 671 672 var rule = stylesheet.cssRules[stylesheet.cssRules.length - 1]; 673 var styleRule = { section: this, style: rule.style, selectorText: rule.selectorText, parentStyleSheet: rule.parentStyleSheet, rule: rule }; 674 this.makeNormal(styleRule); 675 676 if (!this._doesSelectorAffectSelectedNode(newContent)) { 677 this.noAffect = true; 678 this.element.addStyleClass("no-affect"); 679 } 680 681 this.subtitleElement.textContent = WebInspector.UIString("via inspector"); 682 this.expand(); 683 684 this.pane.addBlankSection(); 685 this.addNewBlankProperty().startEditing(); 686 }, 687 688 makeNormal: function(styleRule) 689 { 690 this.titleElement.removeEventListener("dblclick", this._dblclickListener, false); 691 this.titleElement.addEventListener("dblclick", this._dblclickSelector.bind(this), false); 692 this.element.addEventListener("dblclick", this._dblclickEmptySpace.bind(this), false); 693 this.element.removeStyleClass("blank-section"); 694 delete this._blank; 695 delete this._dblclick; 696 delete this.startEditing; 697 delete this.editingCancelled; 698 delete this.editingCommitted; 699 delete this._dblclickListener; 700 delete this.makeNormal; 701 this.styleRule = styleRule; 702 this.rule = styleRule.rule; 703 this.computedStyle = false; 704 this.editable = true; 705 // leftovers are: this.noAffect if applicable 706 } 707 } 708 709 WebInspector.BlankStylePropertiesSection.prototype.__proto__ = WebInspector.StylePropertiesSection.prototype; 458 710 459 711 WebInspector.StylePropertyTreeElement = function(style, name, shorthand, inherited, overloaded, disabled) … … 732 984 { 733 985 this.startEditing(event.target); 986 event.stopPropagation(); 734 987 }, 735 988 … … 859 1112 editingCancelled: function(element, context) 860 1113 { 861 if (this.originalCSSText) { 1114 if (this._newProperty) 1115 this.treeOutline.removeChild(this); 1116 else if (this.originalCSSText) { 862 1117 this.style.cssText = this.originalCSSText; 863 1118 … … 877 1132 878 1133 // Determine where to move to before making changes 879 var newProperty = false; 880 var moveToPropertyName; 1134 var newProperty, moveToPropertyName, moveToSelector; 881 1135 var moveTo = (moveDirection === "forward" ? this.nextSibling : this.previousSibling); 882 1136 if (moveTo) … … 884 1138 else if (moveDirection === "forward") 885 1139 newProperty = true; 1140 else if (moveDirection === "backward" && this.treeOutline.section.rule) 1141 moveToSelector = true; 886 1142 887 1143 // Make the Changes and trigger the moveToNextCallback after updating … … 920 1176 var item = section.addNewBlankProperty(); 921 1177 item.startEditing(); 922 } 1178 return; 1179 } 1180 1181 if (moveToSelector) 1182 section.startEditingSelector(); 923 1183 } 924 1184 }, … … 999 1259 if (updateInterface) 1000 1260 this.updateAll(true); 1261 1262 if (!this.rule) 1263 WebInspector.panels.elements.treeOutline.update(); 1001 1264 } 1002 1265 } -
trunk/WebCore/inspector/front-end/inspector.css
r46402 r46690 1183 1183 } 1184 1184 1185 .section.no-affect .header { 1186 background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(167, 167, 167)), to(rgb(123, 123, 123))) 1187 } 1188 1185 1189 .section .header::before { 1186 1190 position: absolute; … … 1192 1196 } 1193 1197 1198 .section.blank-section .header::before { 1199 display: none; 1200 } 1201 1194 1202 .section.expanded .header::before { 1195 1203 content: url(Images/treeDownTriangleWhite.png); … … 1201 1209 word-wrap: break-word; 1202 1210 white-space: normal; 1211 } 1212 1213 .section .header .title.blank-title { 1214 font-style: italic; 1203 1215 } 1204 1216 … … 1240 1252 list-style: none; 1241 1253 background-color: white; 1254 min-height: 18px; 1255 } 1256 1257 .section.no-affect .properties li { 1258 opacity: 0.5; 1259 } 1260 1261 .section.no-affect .properties li.editing { 1262 opacity: 1.0; 1242 1263 } 1243 1264
Note: See TracChangeset
for help on using the changeset viewer.