1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/object", 5 "firebug/firebug", 6 "firebug/lib/domplate", 7 "firebug/lib/locale", 8 "firebug/lib/events", 9 "firebug/lib/css", 10 "firebug/lib/dom", 11 "firebug/lib/xml", 12 "firebug/lib/url", 13 "firebug/lib/array", 14 "firebug/js/sourceLink", 15 "firebug/chrome/menu", 16 "firebug/lib/options", 17 "firebug/lib/string", 18 "firebug/lib/persist", 19 "firebug/css/cssModule", 20 "firebug/css/cssReps" 21 ], 22 function(Obj, Firebug, Domplate, Locale, Events, Css, Dom, Xml, Url, Arr, SourceLink, Menu, 23 Options, Str, Persist, CSSModule, CSSInfoTip) { 24 25 with (Domplate) { 26 27 //********************************************************************************************* // 28 // Constants 29 30 const Cu = Components.utils; 31 32 const statusClasses = ["cssUnmatched", "cssParentMatch", "cssOverridden", "cssBestMatch"]; 33 34 try 35 { 36 Cu.import("resource:///modules/devtools/CssLogic.jsm"); 37 } 38 catch (err) 39 { 40 if (FBTrace.DBG_ERRORS) 41 FBTrace.sysout("cssComputedPanel: EXCEPTION CssLogic is not available!"); 42 } 43 44 // ********************************************************************************************* // 45 // CSS Computed panel (HTML side panel) 46 47 function CSSComputedPanel() {} 48 49 CSSComputedPanel.prototype = Obj.extend(Firebug.Panel, 50 { 51 template: domplate( 52 { 53 computedStylesTag: 54 DIV({"class": "a11yCSSView", role: "list", "aria-label": 55 Locale.$STR("aria.labels.computed styles")}), 56 57 groupedStylesTag: 58 FOR("group", "$groups", 59 DIV({"class": "computedStylesGroup", $opened: "$group.opened", role: "list", 60 $hidden: "$group.props|hasNoStyles", _repObject: "$group"}, 61 H1({"class": "cssComputedHeader groupHeader focusRow", role: "listitem"}, 62 DIV({"class": "twisty", role: "presentation"}), 63 SPAN({"class": "cssComputedLabel"}, "$group.title") 64 ), 65 TAG("$stylesTag", {props: "$group.props"}) 66 ) 67 ), 68 69 stylesTag: 70 TABLE({"class": "computedStyleTable", role: "list"}, 71 TBODY({role: "presentation"}, 72 FOR("prop", "$props", 73 TR({"class": "focusRow computedStyleRow computedStyle", 74 $opened: "$prop.opened", role: "listitem", 75 $hasSelectors: "$prop|hasSelectors", _repObject: "$prop"}, 76 TD({"class": "stylePropName", role: "presentation"}, 77 "$prop.property" 78 ), 79 TD({role: "presentation"}, 80 SPAN({"class": "stylePropValue"}, "$prop.value|formatValue")) 81 ), 82 TR({"class": "focusRow computedStyleRow matchedSelectors", _repObject: "$prop"}, 83 TD({colspan: 2}, 84 TAG("$selectorsTag", {prop: "$prop"}) 85 ) 86 ) 87 ) 88 ) 89 ), 90 91 selectorsTag: 92 TABLE({"class": "matchedSelectorsTable", role: "list"}, 93 TBODY({role: "presentation"}, 94 FOR("selector", "$prop.matchedSelectors", 95 TR({"class": "focusRow computedStyleRow styleSelector "+ 96 "$selector.status|getStatusClass", role: "listitem", 97 _repObject: "$selector"}, 98 TD({"class": "selectorName", role: "presentation"}, 99 "$selector.selector.text"), 100 TD({"class": "propValue", role: "presentation"}, 101 SPAN({"class": "stylePropValue"}, "$selector.value|formatValue")), 102 TD({"class": "styleSourceLink", role: "presentation"}, 103 TAG(FirebugReps.SourceLink.tag, {object: "$selector|getSourceLink"}) 104 ) 105 ) 106 ) 107 ) 108 ), 109 110 getStatusClass: function(status) 111 { 112 return statusClasses[status]; 113 }, 114 115 hasNoStyles: function(props) 116 { 117 return props.length == 0; 118 }, 119 120 hasSelectors: function(prop) 121 { 122 return prop.matchedRuleCount != 0; 123 }, 124 125 getSourceLink: function(selector) 126 { 127 var href = selector.href.href || selector.href; 128 var line = selector.ruleLine; 129 var rule = selector.selector._cssRule._domRule; 130 131 var instance = Css.getInstanceForStyleSheet(rule.parentStyleSheet); 132 var sourceLink = line != -1 ? new SourceLink.SourceLink(href, line, "css", 133 rule, instance) : null; 134 135 return sourceLink; 136 }, 137 138 formatValue: function(value) 139 { 140 if (Options.get("colorDisplay") == "hex") 141 value = Css.rgbToHex(value); 142 else if (Options.get("colorDisplay") == "hsl") 143 value = Css.rgbToHSL(value); 144 145 var limit = Options.get("stringCropLength"); 146 if (limit > 0) 147 value = Str.cropString(value, limit); 148 149 // Add a zero-width space after a comma to allow line breaking 150 return value.replace(/,/g, ",\u200B"); 151 } 152 }), 153 154 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 155 156 updateComputedView: function(element) 157 { 158 // The current selection can be null. 159 if (!element) 160 return; 161 162 var doc = element.ownerDocument; 163 var win = doc.defaultView; 164 165 // Update now if the document is loaded, otherwise wait for "load" event. 166 if (doc.readyState == "complete") 167 return this.doUpdateComputedView(element); 168 169 if (this.updateInProgress) 170 return; 171 172 var self = this; 173 var onWindowLoadHandler = function() 174 { 175 self.context.removeEventListener(win, "load", onWindowLoadHandler, true); 176 self.updateInProgress = false; 177 self.doUpdateComputedView(element); 178 } 179 180 this.context.addEventListener(win, "load", onWindowLoadHandler, true); 181 this.updateInProgress = true; 182 }, 183 184 doUpdateComputedView: function(element) 185 { 186 function isUnwantedProp(propName) 187 { 188 return !Firebug.showMozillaSpecificStyles && Str.hasPrefix(propName, "-moz") 189 } 190 191 var win = element.ownerDocument.defaultView; 192 var computedStyle = win.getComputedStyle(element); 193 194 try 195 { 196 if (this.cssLogic) 197 this.cssLogic.highlight(element); 198 } 199 catch (e) 200 { 201 // An exception is thrown if the document is not fully loaded yet 202 // The cssLogic API needs to be used after "load" has been fired. 203 if (FBTrace.DBG_ERRORS) 204 FBTrace.sysout("computedPanel.doUpdateComputedView; EXCEPTION " + e, e); 205 } 206 207 var props = []; 208 for (var i = 0; i < computedStyle.length; ++i) 209 { 210 var prop = this.cssLogic ? this.cssLogic.getPropertyInfo(computedStyle[i]) : 211 Firebug.CSSModule.getPropertyInfo(computedStyle, computedStyle[i]); 212 213 if (isUnwantedProp(prop.property) || 214 (this.cssLogic && !Firebug.showUserAgentCSS && prop.matchedRuleCount == 0)) 215 { 216 continue; 217 } 218 219 props.push(prop); 220 } 221 222 var parentNode = this.template.computedStylesTag.replace({}, this.panelNode); 223 224 if (props.length != 0) 225 { 226 if (Firebug.computedStylesDisplay == "alphabetical") 227 { 228 this.sortProperties(props); 229 230 for (var i = 0; i < props.length; ++i) 231 props[i].opened = this.styleOpened[props[i].property]; 232 233 var result = this.template.stylesTag.replace({props: props}, parentNode); 234 } 235 else 236 { 237 var groups = []; 238 for (var groupName in styleGroups) 239 { 240 var title = Locale.$STR("StyleGroup-" + groupName); 241 var group = {name: groupName, title: title, props: []}; 242 243 var groupProps = styleGroups[groupName]; 244 for (var i = 0; i < groupProps.length; ++i) 245 { 246 var propName = groupProps[i]; 247 if (isUnwantedProp(propName)) 248 continue; 249 250 var prop = this.cssLogic ? this.cssLogic.getPropertyInfo(propName) : 251 Firebug.CSSModule.getPropertyInfo(computedStyle, propName); 252 253 if (!Firebug.showUserAgentCSS && prop.matchedRuleCount == 0) 254 continue; 255 256 prop.opened = this.styleOpened[propName]; 257 258 group.props.push(prop); 259 260 for (var j = 0; j < props.length; ++j) 261 { 262 if (props[j].property == propName) 263 { 264 props.splice(j, 1); 265 break; 266 } 267 } 268 } 269 270 group.opened = this.groupOpened[groupName]; 271 272 groups.push(group); 273 } 274 275 if (props.length > 0) 276 { 277 var group = groups[groups.length-1]; 278 for (var i = 0; i < props.length; ++i) 279 { 280 var propName = props[i].property; 281 if (isUnwantedProp(propName)) 282 continue; 283 284 var prop = this.cssLogic ? this.cssLogic.getPropertyInfo(propName) : 285 Firebug.CSSModule.getPropertyInfo(computedStyle, propName); 286 287 prop.opened = this.styleOpened[propName]; 288 289 group.props.push(prop); 290 } 291 292 group.opened = this.groupOpened[group.name]; 293 } 294 295 var result = this.template.groupedStylesTag.replace({groups: groups}, parentNode); 296 } 297 } 298 else 299 { 300 FirebugReps.Warning.tag.replace({object: "computed.No_User-Defined_Styles"}, 301 this.panelNode); 302 } 303 304 if (this.scrollTop) 305 { 306 this.panelNode.scrollTop = this.scrollTop; 307 delete this.scrollTop; 308 } 309 310 Events.dispatch(this.fbListeners, "onCSSRulesAdded", [this, result]); 311 }, 312 313 toggleGroup: function(node) 314 { 315 var groupNode = Dom.getAncestorByClass(node, "computedStylesGroup"); 316 var group = Firebug.getRepObject(groupNode); 317 318 Css.toggleClass(groupNode, "opened"); 319 var opened = Css.hasClass(groupNode, "opened"); 320 this.groupOpened[group.name] = opened; 321 322 if (opened) 323 { 324 var offset = Dom.getClientOffset(node); 325 var titleAtTop = offset.y < this.panelNode.scrollTop; 326 327 Dom.scrollTo(groupNode, this.panelNode, null, 328 groupNode.offsetHeight > this.panelNode.clientHeight || titleAtTop ? "top" : "bottom"); 329 } 330 }, 331 332 toggleAllStyles: function(event, expand) 333 { 334 var computedStyles = this.panelNode.getElementsByClassName("computedStyle"); 335 336 for (var i = 0; i < computedStyles.length; ++i) 337 { 338 if (!Css.hasClass(computedStyles[i], "hasSelectors")) 339 continue; 340 341 var isOpened = Css.hasClass(computedStyles[i], "opened"); 342 if ((expand && !isOpened) || (!expand && isOpened)) 343 this.toggleStyle(computedStyles[i], false); 344 } 345 }, 346 347 toggleStyle: function(node, scroll) 348 { 349 var styleNode = Dom.getAncestorByClass(node, "computedStyle"); 350 var style = Firebug.getRepObject(styleNode); 351 352 Css.toggleClass(styleNode, "opened"); 353 var opened = Css.hasClass(styleNode, "opened"); 354 this.styleOpened[style.property] = Css.hasClass(styleNode, "opened"); 355 356 if (opened && scroll) 357 { 358 var selectorsNode = styleNode.nextSibling; 359 var offset = Dom.getClientOffset(styleNode); 360 var titleAtTop = offset.y < this.panelNode.scrollTop; 361 var totalHeight = styleNode.offsetHeight + selectorsNode.offsetHeight; 362 var alignAtTop = totalHeight > this.panelNode.clientHeight || titleAtTop; 363 364 Dom.scrollTo(alignAtTop ? styleNode : selectorsNode, this.panelNode, null, 365 alignAtTop ? "top" : "bottom", alignAtTop); 366 } 367 }, 368 369 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 370 // Events 371 372 onClick: function(event) 373 { 374 if (!Events.isLeftClick(event)) 375 return; 376 377 var cssComputedHeader = Dom.getAncestorByClass(event.target, "cssComputedHeader"); 378 if (cssComputedHeader) 379 { 380 this.toggleGroup(event.target); 381 return; 382 } 383 384 var computedStyle = Dom.getAncestorByClass(event.target, "computedStyle"); 385 if (computedStyle && Css.hasClass(computedStyle, "hasSelectors")) 386 { 387 this.toggleStyle(event.target, true); 388 return; 389 } 390 }, 391 392 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 393 // extends Panel 394 395 name: "computed", 396 parentPanel: "html", 397 order: 1, 398 399 initialize: function() 400 { 401 if (typeof CssLogic != "undefined") 402 this.cssLogic = new CssLogic(); 403 404 this.groupOpened = []; 405 for (var groupName in styleGroups) 406 this.groupOpened[groupName] = true; 407 408 this.styleOpened = []; 409 410 // Listen for CSS changes so the Computed panel is properly updated when needed. 411 Firebug.CSSModule.addListener(this); 412 413 this.onClick = Obj.bind(this.onClick, this); 414 415 Firebug.Panel.initialize.apply(this, arguments); 416 }, 417 418 destroy: function(state) 419 { 420 state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop; 421 state.groupOpened = this.groupOpened; 422 state.styleOpened = this.styleOpened; 423 424 Persist.persistObjects(this, state); 425 426 Firebug.CSSModule.removeListener(this); 427 428 Firebug.Panel.destroyNode.apply(this, arguments); 429 }, 430 431 initializeNode: function(oldPanelNode) 432 { 433 Events.addEventListener(this.panelNode, "click", this.onClick, false); 434 435 Firebug.Panel.initializeNode.apply(this, arguments); 436 }, 437 438 destroyNode: function() 439 { 440 Events.removeEventListener(this.panelNode, "click", this.onClick, false); 441 442 Firebug.Panel.destroyNode.apply(this, arguments); 443 }, 444 445 show: function(state) 446 { 447 // Wait for loadedContext to restore the panel 448 if (this.context.loaded) 449 { 450 Persist.restoreObjects(this, state); 451 452 if (state) 453 { 454 if (state.scrollTop) 455 this.scrollTop = state.scrollTop; 456 457 if (state.groupOpened) 458 this.groupOpened = state.groupOpened; 459 460 if (state.styleOpened) 461 this.styleOpened = state.styleOpened; 462 } 463 } 464 465 if (this.selection) 466 this.refresh(); 467 }, 468 469 hide: function() 470 { 471 this.lastScrollTop = this.panelNode.scrollTop; 472 }, 473 474 updateView: function(element) 475 { 476 this.updateComputedView(element); 477 }, 478 479 supportsObject: function(object, type) 480 { 481 return object instanceof window.Element ? 1 : 0; 482 }, 483 484 refresh: function() 485 { 486 this.updateSelection(this.selection); 487 }, 488 489 updateSelection: function(element) 490 { 491 this.updateComputedView(element); 492 }, 493 494 updateOption: function(name, value) 495 { 496 var options = new Set(); 497 options.add("showUserAgentCSS"); 498 options.add("computedStylesDisplay"); 499 options.add("colorDisplay"); 500 options.add("showMozillaSpecificStyles"); 501 502 if (options.has(name)) 503 this.refresh(); 504 }, 505 506 getOptionsMenuItems: function() 507 { 508 var items = []; 509 510 if (this.cssLogic) 511 { 512 items.push( 513 Menu.optionMenu("Show_User_Agent_CSS", "showUserAgentCSS", 514 "style.option.tip.Show_User_Agent_CSS") 515 ); 516 } 517 518 items.push( 519 { 520 label: "Sort_alphabetically", 521 type: "checkbox", 522 checked: Firebug.computedStylesDisplay == "alphabetical", 523 tooltiptext: "computed.option.tip.Sort_Alphabetically", 524 command: Obj.bind(this.toggleDisplay, this) 525 }, 526 Menu.optionMenu("Show_Mozilla_specific_styles", 527 "showMozillaSpecificStyles", 528 "computed.option.tip.Show_Mozilla_Specific_Styles") 529 ); 530 531 items = Arr.extendArray(items, CSSModule.getColorDisplayOptionMenuItems()); 532 533 return items; 534 }, 535 536 getContextMenuItems: function(style, target) 537 { 538 var items = []; 539 var computedStyles = this.panelNode.getElementsByClassName("computedStyle"); 540 var expandAll = false; 541 var collapseAll = false; 542 for (var i = 0; i < computedStyles.length; ++i) 543 { 544 if (!Css.hasClass(computedStyles[i], "hasSelectors")) 545 continue; 546 547 if (!expandAll && !Css.hasClass(computedStyles[i], "opened")) 548 expandAll = true; 549 if (!collapseAll && Css.hasClass(computedStyles[i], "opened")) 550 collapseAll = true; 551 } 552 553 if (expandAll) 554 { 555 items.push( 556 { 557 label: "computed.option.label.Expand_All_Styles", 558 command: Obj.bind(this.toggleAllStyles, this, true), 559 tooltiptext: "computed.option.tip.Expand_All_Styles" 560 } 561 ); 562 } 563 564 if (collapseAll) 565 { 566 items.push( 567 { 568 label: "computed.option.label.Collapse_All_Styles", 569 command: Obj.bind(this.toggleAllStyles, this, false), 570 tooltiptext: "computed.option.tip.Collapse_All_Styles" 571 } 572 ); 573 } 574 575 return items; 576 }, 577 578 onMouseDown: function(event) 579 { 580 if (!Events.isLeftClick(event)) 581 return; 582 583 var cssComputedHeader = Dom.getAncestorByClass(event.target, "cssComputedHeader"); 584 if (cssComputedHeader) 585 this.toggleNode(event); 586 }, 587 588 toggleNode: function(event) 589 { 590 var group = Dom.getAncestorByClass(event.target, "computedStylesGroup"); 591 var groupName = group.getElementsByClassName("cssComputedLabel")[0].textContent; 592 593 Css.toggleClass(group, "opened"); 594 this.groupOpened[groupName] = Css.hasClass(group, "opened"); 595 }, 596 597 toggleDisplay: function() 598 { 599 var display = Firebug.computedStylesDisplay == "alphabetical" ? "grouped" : "alphabetical"; 600 Options.set("computedStylesDisplay", display); 601 }, 602 603 sortProperties: function(props) 604 { 605 props.sort(function(a, b) 606 { 607 return a.property > b.property ? 1 : -1; 608 }); 609 }, 610 611 getStylesheetURL: function(rule, getBaseUri) 612 { 613 // If parentStyleSheet.href is null, then per the CSS standard this is an inline style. 614 if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href) 615 return rule.parentStyleSheet.href; 616 else if (getBaseUri) 617 return this.selection.ownerDocument.baseURI; 618 else 619 return this.selection.ownerDocument.location.href; 620 }, 621 622 showInfoTip: function(infoTip, target, x, y, rangeParent, rangeOffset) 623 { 624 var propValue = Dom.getAncestorByClass(target, "stylePropValue"); 625 if (propValue) 626 { 627 var propInfo = Firebug.getRepObject(target); 628 629 var prop = propInfo.property, value = propInfo.value; 630 var cssValue; 631 632 if (prop == "font" || prop == "font-family") 633 { 634 if (value.charAt(rangeOffset) == ",") 635 return; 636 637 cssValue = Firebug.CSSModule.parseCSSFontFamilyValue(value, rangeOffset, prop); 638 } 639 else 640 { 641 cssValue = Firebug.CSSModule.parseCSSValue(value, rangeOffset); 642 } 643 644 if (!cssValue) 645 return false; 646 647 if (cssValue.value == this.infoTipValue) 648 return true; 649 650 this.infoTipValue = cssValue.value; 651 652 switch (cssValue.type) 653 { 654 case "rgb": 655 case "hsl": 656 case "gradient": 657 case "colorKeyword": 658 this.infoTipType = "color"; 659 this.infoTipObject = cssValue.value; 660 return CSSInfoTip.populateColorInfoTip(infoTip, cssValue.value); 661 662 case "url": 663 if (Css.isImageRule(Xml.getElementSimpleType(propInfo), prop)) 664 { 665 var baseURL = typeof propInfo.href == "object" ? propInfo.href.href : propInfo.href; 666 if (!baseURL) 667 baseURL = propInfo.matchedSelectors[0].href; 668 var relURL = Firebug.CSSModule.parseURLValue(cssValue.value); 669 var absURL = Url.isDataURL(relURL) ? relURL : Url.absoluteURL(relURL, baseURL); 670 var repeat = Firebug.CSSModule.parseRepeatValue(value); 671 672 this.infoTipType = "image"; 673 this.infoTipObject = absURL; 674 675 return CSSInfoTip.populateImageInfoTip(infoTip, absURL, repeat); 676 } 677 break; 678 679 case "fontFamily": 680 return CSSInfoTip.populateFontFamilyInfoTip(infoTip, cssValue.value); 681 } 682 683 delete this.infoTipType; 684 delete this.infoTipValue; 685 delete this.infoTipObject; 686 687 return false; 688 } 689 }, 690 691 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 692 // Change Listener 693 694 onCSSInsertRule: function(styleSheet, cssText, ruleIndex) 695 { 696 // Force update, this causes updateSelection to be called. 697 // See {@link Firebug.Panel.select} 698 this.selection = null; 699 }, 700 701 onCSSDeleteRule: function(styleSheet, ruleIndex) 702 { 703 this.selection = null; 704 }, 705 706 onCSSSetProperty: function(style, propName, propValue, propPriority, prevValue, 707 prevPriority, rule, baseText) 708 { 709 this.selection = null; 710 }, 711 712 onCSSRemoveProperty: function(style, propName, prevValue, prevPriority, rule, baseText) 713 { 714 this.selection = null; 715 } 716 }); 717 718 //********************************************************************************************* // 719 //Helpers 720 721 const styleGroups = 722 { 723 text: [ 724 "font-family", 725 "font-size", 726 "font-weight", 727 "font-style", 728 "font-size-adjust", 729 "color", 730 "text-transform", 731 "text-decoration", 732 "letter-spacing", 733 "word-spacing", 734 "line-height", 735 "text-align", 736 "vertical-align", 737 "direction", 738 "column-count", 739 "column-gap", 740 "column-width", 741 "-moz-tab-size", // FF4.0 742 "-moz-font-feature-settings", // FF4.0 743 "-moz-font-language-override", // FF4.0 744 "-moz-text-blink", // FF6.0 745 "-moz-text-decoration-color", // FF6.0 746 "-moz-text-decoration-line", // FF6.0 747 "-moz-text-decoration-style", // FF6.0 748 "hyphens", // FF 6.0 749 "text-overflow" // FF7.0 750 ], 751 752 background: [ 753 "background-color", 754 "background-image", 755 "background-repeat", 756 "background-position", 757 "background-attachment", 758 "opacity", 759 "background-clip", 760 "-moz-background-inline-policy", 761 "background-origin", 762 "background-size", 763 "-moz-image-region" 764 ], 765 766 box: [ 767 "width", 768 "height", 769 "top", 770 "right", 771 "bottom", 772 "left", 773 "margin-top", 774 "margin-right", 775 "margin-bottom", 776 "margin-left", 777 "padding-top", 778 "padding-right", 779 "padding-bottom", 780 "padding-left", 781 "-moz-padding-start", 782 "-moz-padding-end", 783 "border-top-width", 784 "border-right-width", 785 "border-bottom-width", 786 "border-left-width", 787 "border-top-color", 788 "-moz-border-top-colors", 789 "border-right-color", 790 "-moz-border-right-colors", 791 "border-bottom-color", 792 "-moz-border-bottom-colors", 793 "border-left-color", 794 "-moz-border-left-colors", 795 "border-top-style", 796 "border-right-style", 797 "border-bottom-style", 798 "border-left-style", 799 "-moz-border-end", 800 "-moz-border-end-color", 801 "-moz-border-end-style", 802 "-moz-border-end-width", 803 "-moz-border-image", 804 "-moz-border-start", 805 "-moz-border-start-color", 806 "-moz-border-start-style", 807 "-moz-border-start-width", 808 "border-top-left-radius", 809 "border-top-right-radius", 810 "border-bottom-left-radius", 811 "border-bottom-right-radius", 812 "-moz-outline-radius-bottomleft", 813 "-moz-outline-radius-bottomright", 814 "-moz-outline-radius-topleft", 815 "-moz-outline-radius-topright", 816 "box-shadow", 817 "outline-color", 818 "outline-offset", 819 "outline-top-width", 820 "outline-right-width", 821 "outline-bottom-width", 822 "outline-left-width", 823 "outline-top-color", 824 "outline-right-color", 825 "outline-bottom-color", 826 "outline-left-color", 827 "outline-top-style", 828 "outline-right-style", 829 "outline-bottom-style", 830 "outline-left-style", 831 "-moz-box-align", 832 "-moz-box-direction", 833 "-moz-box-flex", 834 "-moz-box-ordinal-group", 835 "-moz-box-orient", 836 "-moz-box-pack", 837 "-moz-box-sizing", 838 "-moz-margin-start", 839 "-moz-margin-end" 840 ], 841 842 layout: [ 843 "position", 844 "display", 845 "visibility", 846 "z-index", 847 "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow 848 "overflow-y", 849 "overflow-clip", 850 "transform", 851 "transform-origin", 852 "white-space", 853 "clip", 854 "float", 855 "clear", 856 "-moz-appearance", 857 "-moz-stack-sizing", 858 "-moz-column-count", 859 "-moz-column-gap", 860 "-moz-column-width", 861 "-moz-column-rule", 862 "-moz-column-rule-width", 863 "-moz-column-rule-style", 864 "-moz-column-rule-color", 865 "-moz-float-edge", 866 "orient" 867 ], 868 869 other: [] 870 }; 871 872 //********************************************************************************************* // 873 //Registration 874 875 Firebug.registerPanel(CSSComputedPanel); 876 877 return CSSComputedPanel; 878 879 //********************************************************************************************* // 880 }}); 881