summaryrefslogtreecommitdiffstats
path: root/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite
diff options
context:
space:
mode:
authortalasila <talasila@research.att.com>2017-02-07 15:03:57 -0500
committertalasila <talasila@research.att.com>2017-02-07 15:05:15 -0500
commit4ad39a5c96dd99acf819ce189b13fec946d7506b (patch)
treea1449286441947cc3d07a45227fa0d6f978e1a7d /ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite
parent5500448cbd1f374d0ac743ee2fd636fe2d3c0027 (diff)
Initial OpenECOMP Portal commit
Change-Id: I804b80e0830c092e307da1599bd9fbb5c3e2da77 Signed-off-by: talasila <talasila@research.att.com>
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite')
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/license.txt30
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/blank.gifbin0 -> 43 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBg.pngbin0 -> 167 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.pngbin0 -> 171 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/debugger.css331
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detach.pngbin0 -> 655 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detachHover.pngbin0 -> 586 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.gifbin0 -> 340 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.pngbin0 -> 543 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.gifbin0 -> 344 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.pngbin0 -> 512 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/down.pngbin0 -> 637 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downActive.pngbin0 -> 543 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downHover.pngbin0 -> 526 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.pngbin0 -> 447 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.gifbin0 -> 365 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.pngbin0 -> 457 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css817
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css20
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.css3147
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.html215
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.pngbin0 -> 1167 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/group.gifbin0 -> 158 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/html.css272
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.gifbin0 -> 359 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.pngbin0 -> 524 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/loading_16.gifbin0 -> 1553 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/min.pngbin0 -> 552 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/minHover.pngbin0 -> 485 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/off.pngbin0 -> 742 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/offHover.pngbin0 -> 680 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gifbin0 -> 43 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg6
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.gifbin0 -> 550 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.pngbin0 -> 685 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow.gifbin0 -> 4364 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow2.gifbin0 -> 3093 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.pngbin0 -> 3403 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/sprite.pngbin0 -> 40027 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.pngbin0 -> 438 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.pngbin0 -> 261 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.pngbin0 -> 436 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabLeft.pngbin0 -> 449 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.pngbin0 -> 220 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.pngbin0 -> 207 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.pngbin0 -> 192 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.pngbin0 -> 142 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.pngbin0 -> 148 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMid.pngbin0 -> 262 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabRight.pngbin0 -> 448 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gifbin0 -> 117 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.pngbin0 -> 3144 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gifbin0 -> 1821 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.pngbin0 -> 3960 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/titlebarMid.pngbin0 -> 273 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/toolbarMid.pngbin0 -> 242 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_close.gifbin0 -> 300 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_open.gifbin0 -> 202 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyClosed.pngbin0 -> 334 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyOpen.pngbin0 -> 309 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/up.pngbin0 -> 619 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upActive.pngbin0 -> 551 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upHover.pngbin0 -> 526 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.gifbin0 -> 357 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.pngbin0 -> 516 bytes
-rw-r--r--ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/src/firebug-lite-debug.js31176
66 files changed, 36014 insertions, 0 deletions
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/license.txt b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/license.txt
new file mode 100644
index 00000000..ba43b751
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/license.txt
@@ -0,0 +1,30 @@
+Software License Agreement (BSD License)
+
+Copyright (c) 2007, Parakey Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Parakey Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Parakey Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/blank.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/blank.gif
new file mode 100644
index 00000000..6865c960
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/blank.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBg.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBg.png
new file mode 100644
index 00000000..f367b427
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBg.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png
new file mode 100644
index 00000000..cd37a0d5
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/debugger.css b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/debugger.css
new file mode 100644
index 00000000..ba55c7ea
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/debugger.css
@@ -0,0 +1,331 @@
+/* See license.txt for terms of usage */
+
+.panelNode-script {
+ overflow: hidden;
+ font-family: monospace;
+}
+
+/************************************************************************************************/
+
+.scriptTooltip {
+ position: fixed;
+ z-index: 2147483647;
+ padding: 2px 3px;
+ border: 1px solid #CBE087;
+ background: LightYellow;
+ font-family: monospace;
+ color: #000000;
+}
+
+/************************************************************************************************/
+
+.sourceBox {
+ /* TODO: xxxpedro problem with sourceBox and scrolling elements */
+ /*overflow: scroll; /* see issue 1479 */
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.sourceRow {
+ white-space: nowrap;
+ -moz-user-select: text;
+}
+
+.sourceRow.hovered {
+ background-color: #EEEEEE;
+}
+
+/************************************************************************************************/
+
+.sourceLine {
+ -moz-user-select: none;
+ margin-right: 10px;
+ border-right: 1px solid #CCCCCC;
+ padding: 0px 4px 0 20px;
+ background: #EEEEEE no-repeat 2px 0px;
+ color: #888888;
+ white-space: pre;
+ font-family: monospace; /* see issue 2953 */
+}
+
+.noteInToolTip { /* below sourceLine, so it overrides it */
+ background-color: #FFD472;
+}
+
+.useA11y .sourceBox .sourceViewport:focus .sourceLine {
+ background-color: #FFFFC0;
+ color: navy;
+ border-right: 1px solid black;
+}
+
+.useA11y .sourceBox .sourceViewport:focus {
+ outline: none;
+}
+
+.a11y1emSize {
+ width: 1em;
+ height: 1em;
+ position: absolute;
+}
+
+.useA11y .panelStatusLabel:focus {
+ outline-offset: -2px !important;
+ }
+
+.sourceBox > .sourceRow > .sourceLine {
+ cursor: pointer;
+}
+
+.sourceLine:hover {
+ text-decoration: none;
+}
+
+.sourceRowText {
+ white-space: pre;
+}
+
+.sourceRow[exe_line="true"] {
+ outline: 1px solid #D9D9B6;
+ margin-right: 1px;
+ background-color: lightgoldenrodyellow;
+}
+
+.sourceRow[executable="true"] > .sourceLine {
+ content: "-";
+ color: #4AA02C; /* Spring Green */
+ font-weight: bold;
+}
+
+.sourceRow[exe_line="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/exe.png);
+ color: #000000;
+}
+
+.sourceRow[breakpoint="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/breakpoint.png);
+}
+
+.sourceRow[breakpoint="true"][condition="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/breakpointCondition.png);
+}
+
+.sourceRow[breakpoint="true"][disabledBreakpoint="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/breakpointDisabled.png);
+}
+
+.sourceRow[breakpoint="true"][exe_line="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/breakpointExe.png);
+}
+
+.sourceRow[breakpoint="true"][exe_line="true"][disabledBreakpoint="true"] > .sourceLine {
+ background-image: url(chrome://firebug/skin/breakpointDisabledExe.png);
+}
+
+.sourceLine.editing {
+ background-image: url(chrome://firebug/skin/breakpoint.png);
+}
+
+/************************************************************************************************/
+
+.conditionEditor {
+ z-index: 2147483647;
+ position: absolute;
+ margin-top: 0;
+ left: 2px;
+ width: 90%;
+}
+
+.conditionEditorInner {
+ position: relative;
+ top: -26px;
+ height: 0;
+}
+
+.conditionCaption {
+ margin-bottom: 2px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ font-size: 11px;
+ color: #226679;
+}
+
+.conditionInput {
+ width: 100%;
+ border: 1px solid #0096C0;
+ font-family: monospace;
+ font-size: inherit;
+}
+
+.conditionEditorInner1 {
+ padding-left: 37px;
+ background: url(condBorders.png) repeat-y;
+}
+
+.conditionEditorInner2 {
+ padding-right: 25px;
+ background: url(condBorders.png) repeat-y 100% 0;
+}
+
+.conditionEditorTop1 {
+ background: url(condCorners.png) no-repeat 100% 0;
+ margin-left: 37px;
+ height: 35px;
+}
+
+.conditionEditorTop2 {
+ position: relative;
+ left: -37px;
+ width: 37px;
+ height: 35px;
+ background: url(condCorners.png) no-repeat;
+}
+
+.conditionEditorBottom1 {
+ background: url(condCorners.png) no-repeat 100% 100%;
+ margin-left: 37px;
+ height: 33px;
+}
+
+.conditionEditorBottom2 {
+ position: relative; left: -37px;
+ width: 37px;
+ height: 33px;
+ background: url(condCorners.png) no-repeat 0 100%;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.upsideDown {
+ margin-top: 2px;
+}
+
+.upsideDown .conditionEditorInner {
+ top: -8px;
+}
+
+.upsideDown .conditionEditorInner1 {
+ padding-left: 33px;
+ background: url(condBordersUps.png) repeat-y;
+}
+
+.upsideDown .conditionEditorInner2 {
+ padding-right: 25px;
+ background: url(condBordersUps.png) repeat-y 100% 0;
+}
+
+.upsideDown .conditionEditorTop1 {
+ background: url(condCornersUps.png) no-repeat 100% 0;
+ margin-left: 33px;
+ height: 25px;
+}
+
+.upsideDown .conditionEditorTop2 {
+ position: relative;
+ left: -33px;
+ width: 33px;
+ height: 25px;
+ background: url(condCornersUps.png) no-repeat;
+}
+
+.upsideDown .conditionEditorBottom1 {
+ background: url(condCornersUps.png) no-repeat 100% 100%;
+ margin-left: 33px;
+ height: 43px;
+}
+
+.upsideDown .conditionEditorBottom2 {
+ position: relative;
+ left: -33px;
+ width: 33px;
+ height: 43px;
+ background: url(condCornersUps.png) no-repeat 0 100%;
+}
+
+/************************************************************************************************/
+
+.breakpointsGroupListBox {
+ overflow: hidden;
+}
+
+.breakpointBlockHead {
+ position: relative;
+ padding-top: 4px;
+}
+
+.breakpointBlockHead > .checkbox {
+ margin-right: 4px;
+}
+
+.breakpointBlockHead > .objectLink-sourceLink {
+ top: 4px;
+ right: 20px;
+ background-color: #FFFFFF; /* issue 3308 */
+}
+
+.breakpointBlockHead > .closeButton {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+}
+
+.breakpointCheckbox {
+ margin-top: 0;
+ vertical-align: top;
+}
+
+.breakpointName {
+ margin-left: 4px;
+ font-weight: bold;
+}
+
+.breakpointRow[aria-checked="false"] > .breakpointBlockHead > *,
+.breakpointRow[aria-checked="false"] > .breakpointCode {
+ opacity: 0.5;
+}
+
+.breakpointRow[aria-checked="false"] .breakpointCheckbox,
+.breakpointRow[aria-checked="false"] .objectLink-sourceLink,
+.breakpointRow[aria-checked="false"] .closeButton,
+.breakpointRow[aria-checked="false"] .breakpointMutationType {
+ opacity: 1.0 !important;
+}
+
+.breakpointCode {
+ overflow: hidden;
+ white-space: nowrap;
+ padding-left: 24px;
+ padding-bottom: 2px;
+ border-bottom: 1px solid #D7D7D7;
+ font-family: monospace;
+ color: DarkGreen;
+}
+
+.breakpointCondition {
+ white-space: nowrap;
+ padding-left: 24px;
+ padding-bottom: 2px;
+ border-bottom: 1px solid #D7D7D7;
+ font-family: monospace;
+ color: Gray;
+}
+
+.breakpointBlock-breakpoints > .groupHeader {
+ display: none;
+}
+
+.breakpointBlock-monitors > .breakpointCode {
+ padding: 0;
+}
+
+.breakpointBlock-errorBreakpoints .breakpointCheckbox,
+.breakpointBlock-monitors .breakpointCheckbox {
+ display: none;
+}
+
+.breakpointHeader {
+ margin: 0 !important;
+ border-top: none !important;
+}
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detach.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detach.png
new file mode 100644
index 00000000..0ddb9a17
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detach.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detachHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detachHover.png
new file mode 100644
index 00000000..e4192729
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/detachHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.gif
new file mode 100644
index 00000000..dd9eb0e3
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.png
new file mode 100644
index 00000000..c28bcdf2
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disable.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.gif
new file mode 100644
index 00000000..70565a83
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.png
new file mode 100644
index 00000000..26fe3754
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/disableHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/down.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/down.png
new file mode 100644
index 00000000..acbbd30c
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/down.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downActive.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downActive.png
new file mode 100644
index 00000000..f4312b2f
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downActive.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downHover.png
new file mode 100644
index 00000000..8144e637
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/downHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png
new file mode 100644
index 00000000..0c377e30
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif
new file mode 100644
index 00000000..8ee8116a
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.png
new file mode 100644
index 00000000..2d75261b
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/errorIcon.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css
new file mode 100644
index 00000000..42f9faf5
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css
@@ -0,0 +1,817 @@
+.fbBtnPressed {
+ background: #ECEBE3;
+ padding: 3px 6px 2px 7px !important;
+ margin: 1px 0 0 1px;
+ _margin: 1px -1px 0 1px;
+ border: 1px solid #ACA899 !important;
+ border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;
+}
+
+.fbToolbarButtons {
+ display: none;
+}
+
+#fbStatusBarBox {
+ display: none;
+}
+
+/************************************************************************************************
+ Error Popup
+*************************************************************************************************/
+#fbErrorPopup {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ height: 19px;
+ width: 75px;
+ background: url(sprite.png) #f1f2ee 0 0;
+ z-index: 999;
+}
+
+#fbErrorPopupContent {
+ position: absolute;
+ right: 0;
+ top: 1px;
+ height: 18px;
+ width: 75px;
+ _width: 74px;
+ border-left: 1px solid #aca899;
+}
+
+#fbErrorIndicator {
+ position: absolute;
+ top: 2px;
+ right: 5px;
+}
+
+
+
+
+
+
+
+
+
+
+.fbBtnInspectActive {
+ background: #aaa;
+ color: #fff !important;
+}
+
+/************************************************************************************************
+ General
+*************************************************************************************************/
+html, body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+}
+
+body {
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ background: #fff;
+}
+
+.clear {
+ clear: both;
+}
+
+/************************************************************************************************
+ Mini Chrome
+*************************************************************************************************/
+#fbMiniChrome {
+ display: none;
+ right: 0;
+ height: 27px;
+ background: url(sprite.png) #f1f2ee 0 0;
+ margin-left: 1px;
+}
+
+#fbMiniContent {
+ display: block;
+ position: relative;
+ left: -1px;
+ right: 0;
+ top: 1px;
+ height: 25px;
+ border-left: 1px solid #aca899;
+}
+
+#fbToolbarSearch {
+ float: right;
+ border: 1px solid #ccc;
+ margin: 0 5px 0 0;
+ background: #fff url(search.png) no-repeat 4px 2px;
+ padding-left: 20px;
+ font-size: 11px;
+}
+
+#fbToolbarErrors {
+ float: right;
+ margin: 1px 4px 0 0;
+ font-size: 11px;
+}
+
+#fbLeftToolbarErrors {
+ float: left;
+ margin: 7px 0px 0 5px;
+ font-size: 11px;
+}
+
+.fbErrors {
+ padding-left: 20px;
+ height: 14px;
+ background: url(errorIcon.png) no-repeat;
+ color: #f00;
+ font-weight: bold;
+}
+
+#fbMiniErrors {
+ display: inline;
+ display: none;
+ float: right;
+ margin: 5px 2px 0 5px;
+}
+
+#fbMiniIcon {
+ float: right;
+ margin: 3px 4px 0;
+ height: 20px;
+ width: 20px;
+ float: right;
+ background: url(sprite.png) 0 -135px;
+ cursor: pointer;
+}
+
+
+/************************************************************************************************
+ Master Layout
+*************************************************************************************************/
+#fbChrome {
+ position: fixed;
+ overflow: hidden;
+ height: 100%;
+ width: 100%;
+ border-collapse: collapse;
+ background: #fff;
+}
+
+#fbTop {
+ height: 49px;
+}
+
+#fbToolbar {
+ position: absolute;
+ z-index: 5;
+ width: 100%;
+ top: 0;
+ background: url(sprite.png) #f1f2ee 0 0;
+ height: 27px;
+ font-size: 11px;
+ overflow: hidden;
+}
+
+#fbPanelBarBox {
+ top: 27px;
+ position: absolute;
+ z-index: 8;
+ width: 100%;
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ height: 22px;
+}
+
+#fbContent {
+ height: 100%;
+ vertical-align: top;
+}
+
+#fbBottom {
+ height: 18px;
+ background: #fff;
+}
+
+/************************************************************************************************
+ Sub-Layout
+*************************************************************************************************/
+
+/* fbToolbar
+*************************************************************************************************/
+#fbToolbarIcon {
+ float: left;
+ padding: 4px 5px 0;
+}
+
+#fbToolbarIcon a {
+ display: block;
+ height: 20px;
+ width: 20px;
+ background: url(sprite.png) 0 -135px;
+ text-decoration: none;
+ cursor: default;
+}
+
+#fbToolbarButtons {
+ float: left;
+ padding: 4px 2px 0 5px;
+}
+
+#fbToolbarButtons a {
+ text-decoration: none;
+ display: block;
+ float: left;
+ color: #000;
+ padding: 4px 8px 4px;
+ cursor: default;
+}
+
+#fbToolbarButtons a:hover {
+ color: #333;
+ padding: 3px 7px 3px;
+ border: 1px solid #fff;
+ border-bottom: 1px solid #bbb;
+ border-right: 1px solid #bbb;
+}
+
+#fbStatusBarBox {
+ position: relative;
+ top: 5px;
+ line-height: 19px;
+ cursor: default;
+}
+
+.fbToolbarSeparator{
+ overflow: hidden;
+ border: 1px solid;
+ border-color: transparent #fff transparent #777;
+ _border-color: #eee #fff #eee #777;
+ height: 7px;
+ margin: 10px 6px 0 0;
+ float: left;
+}
+
+.fbStatusBar span {
+ color: #808080;
+ padding: 0 4px 0 0;
+}
+
+.fbStatusBar span a {
+ text-decoration: none;
+ color: black;
+}
+
+.fbStatusBar span a:hover {
+ color: blue;
+ cursor: pointer;
+}
+
+
+#fbWindowButtons {
+ position: absolute;
+ white-space: nowrap;
+ right: 0;
+ top: 0;
+ height: 17px;
+ _width: 50px;
+ padding: 5px 0 5px 5px;
+ z-index: 6;
+ background: url(sprite.png) #f1f2ee 0 0;
+}
+
+/* fbPanelBarBox
+*************************************************************************************************/
+
+#fbPanelBar1 {
+ width: 255px; /* fixed width to avoid tabs breaking line */
+ z-index: 8;
+ left: 0;
+ white-space: nowrap;
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ position: absolute;
+ left: 4px;
+}
+
+#fbPanelBar2Box {
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ position: absolute;
+ height: 22px;
+ width: 300px; /* fixed width to avoid tabs breaking line */
+ z-index: 9;
+ right: 0;
+}
+
+#fbPanelBar2 {
+ position: absolute;
+ width: 290px; /* fixed width to avoid tabs breaking line */
+ height: 22px;
+ padding-left: 10px;
+}
+
+/* body
+*************************************************************************************************/
+.fbPanel {
+ display: none;
+}
+
+#fbPanelBox1, #fbPanelBox2 {
+ max-height: inherit;
+ height: 100%;
+ font-size: 11px;
+}
+
+#fbPanelBox2 {
+ background: #fff;
+}
+
+#fbPanelBox2 {
+ width: 300px;
+ background: #fff;
+}
+
+#fbPanel2 {
+ padding-left: 6px;
+ background: #fff;
+}
+
+.hide {
+ overflow: hidden !important;
+ position: fixed !important;
+ display: none !important;
+ visibility: hidden !important;
+}
+
+/* fbBottom
+*************************************************************************************************/
+
+#fbCommand {
+ height: 18px;
+}
+
+#fbCommandBox {
+ position: absolute;
+ width: 100%;
+ height: 18px;
+ bottom: 0;
+ overflow: hidden;
+ z-index: 9;
+ background: #fff;
+ border: 0;
+ border-top: 1px solid #ccc;
+}
+
+#fbCommandIcon {
+ position: absolute;
+ color: #00f;
+ top: 2px;
+ left: 7px;
+ display: inline;
+ font: 11px Monaco, monospace;
+ z-index: 10;
+}
+
+#fbCommandLine {
+ position: absolute;
+ width: 100%;
+ top: 0;
+ left: 0;
+ border: 0;
+ margin: 0;
+ padding: 2px 0 2px 32px;
+ font: 11px Monaco, monospace;
+ z-index: 9;
+}
+
+div.fbFitHeight {
+ overflow: auto;
+ _position: absolute;
+}
+
+
+/************************************************************************************************
+ Layout Controls
+*************************************************************************************************/
+
+/* fbToolbar buttons
+*************************************************************************************************/
+#fbWindowButtons a {
+ font-size: 1px;
+ width: 16px;
+ height: 16px;
+ display: block;
+ float: right;
+ margin-right: 4px;
+ text-decoration: none;
+ cursor: default;
+}
+
+#fbWindow_btClose {
+ background: url(sprite.png) 0 -119px;
+}
+
+#fbWindow_btClose:hover {
+ background: url(sprite.png) -16px -119px;
+}
+
+#fbWindow_btDetach {
+ background: url(sprite.png) -32px -119px;
+}
+
+#fbWindow_btDetach:hover {
+ background: url(sprite.png) -48px -119px;
+}
+
+/* fbPanelBarBox tabs
+*************************************************************************************************/
+.fbTab {
+ text-decoration: none;
+ display: none;
+ float: left;
+ width: auto;
+ float: left;
+ cursor: default;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ font-weight: bold;
+ height: 22px;
+ color: #565656;
+}
+
+.fbPanelBar span {
+ display: block;
+ float: left;
+}
+
+.fbPanelBar .fbTabL,.fbPanelBar .fbTabR {
+ height: 22px;
+ width: 8px;
+}
+
+.fbPanelBar .fbTabText {
+ padding: 4px 1px 0;
+}
+
+a.fbTab:hover {
+ background: url(sprite.png) 0 -73px;
+}
+
+a.fbTab:hover .fbTabL {
+ background: url(sprite.png) -16px -96px;
+}
+
+a.fbTab:hover .fbTabR {
+ background: url(sprite.png) -24px -96px;
+}
+
+.fbSelectedTab {
+ background: url(sprite.png) #f1f2ee 0 -50px !important;
+ color: #000;
+}
+
+.fbSelectedTab .fbTabL {
+ background: url(sprite.png) 0 -96px !important;
+}
+
+.fbSelectedTab .fbTabR {
+ background: url(sprite.png) -8px -96px !important;
+}
+
+/* splitters
+*************************************************************************************************/
+#fbHSplitter {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 5px;
+ overflow: hidden;
+ cursor: n-resize !important;
+ background: url(pixel_transparent.gif);
+ z-index: 9;
+}
+
+#fbHSplitter.fbOnMovingHSplitter {
+ height: 100%;
+ z-index: 100;
+}
+
+.fbVSplitter {
+ background: #ece9d8;
+ color: #000;
+ border: 1px solid #716f64;
+ border-width: 0 1px;
+ border-left-color: #aca899;
+ width: 4px;
+ cursor: e-resize;
+ overflow: hidden;
+ right: 294px;
+ text-decoration: none;
+ z-index: 9;
+ position: absolute;
+ height: 100%;
+ top: 27px;
+ _width: 6px;
+}
+
+/************************************************************************************************/
+div.lineNo {
+ font: 11px Monaco, monospace;
+ float: left;
+ display: inline;
+ position: relative;
+ margin: 0;
+ padding: 0 5px 0 20px;
+ background: #eee;
+ color: #888;
+ border-right: 1px solid #ccc;
+ text-align: right;
+}
+
+pre.nodeCode {
+ font: 11px Monaco, monospace;
+ margin: 0;
+ padding-left: 10px;
+ overflow: hidden;
+ /*
+ _width: 100%;
+ /**/
+}
+
+/************************************************************************************************/
+.nodeControl {
+ margin-top: 3px;
+ margin-left: -14px;
+ float: left;
+ width: 9px;
+ height: 9px;
+ overflow: hidden;
+ cursor: default;
+ background: url(tree_open.gif);
+ _float: none;
+ _display: inline;
+ _position: absolute;
+}
+
+div.nodeMaximized {
+ background: url(tree_close.gif);
+}
+
+div.objectBox-element {
+ padding: 1px 3px;
+}
+.objectBox-selector{
+ cursor: default;
+}
+
+.selectedElement{
+ background: highlight;
+ /* background: url(roundCorner.svg); Opera */
+ color: #fff !important;
+}
+.selectedElement span{
+ color: #fff !important;
+}
+
+/* Webkit CSS Hack - bug in "highlight" named color */
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ .selectedElement{
+ background: #316AC5;
+ color: #fff !important;
+ }
+}
+
+/************************************************************************************************/
+/************************************************************************************************/
+.logRow * {
+ font-size: 11px;
+}
+
+.logRow {
+ position: relative;
+ border-bottom: 1px solid #D7D7D7;
+ padding: 2px 4px 1px 6px;
+ background-color: #FFFFFF;
+}
+
+.logRow-command {
+ font-family: Monaco, monospace;
+ color: blue;
+}
+
+.objectBox-string,
+.objectBox-text,
+.objectBox-number,
+.objectBox-function,
+.objectLink-element,
+.objectLink-textNode,
+.objectLink-function,
+.objectBox-stackTrace,
+.objectLink-profile {
+ font-family: Monaco, monospace;
+}
+
+.objectBox-null {
+ padding: 0 2px;
+ border: 1px solid #666666;
+ background-color: #888888;
+ color: #FFFFFF;
+}
+
+.objectBox-string {
+ color: red;
+ white-space: pre;
+}
+
+.objectBox-number {
+ color: #000088;
+}
+
+.objectBox-function {
+ color: DarkGreen;
+}
+
+.objectBox-object {
+ color: DarkGreen;
+ font-weight: bold;
+ font-family: Lucida Grande, sans-serif;
+}
+
+.objectBox-array {
+ color: #000;
+}
+
+/************************************************************************************************/
+.logRow-info,.logRow-error,.logRow-warning {
+ background: #fff no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.logRow-info {
+ background-image: url(infoIcon.png);
+}
+
+.logRow-warning {
+ background-color: cyan;
+ background-image: url(warningIcon.png);
+}
+
+.logRow-error {
+ background-color: LightYellow;
+ background-image: url(errorIcon.png);
+ color: #f00;
+}
+
+.errorMessage {
+ vertical-align: top;
+ color: #f00;
+}
+
+.objectBox-sourceLink {
+ position: absolute;
+ right: 4px;
+ top: 2px;
+ padding-left: 8px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: #0000FF;
+}
+
+/************************************************************************************************/
+.logRow-group {
+ background: #EEEEEE;
+ border-bottom: none;
+}
+
+.logGroup {
+ background: #EEEEEE;
+}
+
+.logGroupBox {
+ margin-left: 24px;
+ border-top: 1px solid #D7D7D7;
+ border-left: 1px solid #D7D7D7;
+}
+
+/************************************************************************************************/
+.selectorTag,.selectorId,.selectorClass {
+ font-family: Monaco, monospace;
+ font-weight: normal;
+}
+
+.selectorTag {
+ color: #0000FF;
+}
+
+.selectorId {
+ color: DarkBlue;
+}
+
+.selectorClass {
+ color: red;
+}
+
+/************************************************************************************************/
+.objectBox-element {
+ font-family: Monaco, monospace;
+ color: #000088;
+}
+
+.nodeChildren {
+ padding-left: 26px;
+}
+
+.nodeTag {
+ color: blue;
+ cursor: pointer;
+}
+
+.nodeValue {
+ color: #FF0000;
+ font-weight: normal;
+}
+
+.nodeText,.nodeComment {
+ margin: 0 2px;
+ vertical-align: top;
+}
+
+.nodeText {
+ color: #333333;
+ font-family: Monaco, monospace;
+}
+
+.nodeComment {
+ color: DarkGreen;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeHidden, .nodeHidden * {
+ color: #888888;
+}
+
+.nodeHidden .nodeTag {
+ color: #5F82D9;
+}
+
+.nodeHidden .nodeValue {
+ color: #D86060;
+}
+
+.selectedElement .nodeHidden, .selectedElement .nodeHidden * {
+ color: SkyBlue !important;
+}
+
+
+/************************************************************************************************/
+.log-object {
+ /*
+ _position: relative;
+ _height: 100%;
+ /**/
+}
+
+.property {
+ position: relative;
+ clear: both;
+ height: 15px;
+}
+
+.propertyNameCell {
+ vertical-align: top;
+ float: left;
+ width: 28%;
+ position: absolute;
+ left: 0;
+ z-index: 0;
+}
+
+.propertyValueCell {
+ float: right;
+ width: 68%;
+ background: #fff;
+ position: absolute;
+ padding-left: 5px;
+ display: table-cell;
+ right: 0;
+ z-index: 1;
+ /*
+ _position: relative;
+ /**/
+}
+
+.propertyName {
+ font-weight: bold;
+}
+
+.FirebugPopup {
+ height: 100% !important;
+}
+
+.FirebugPopup #fbWindowButtons {
+ display: none !important;
+}
+
+.FirebugPopup #fbHSplitter {
+ display: none !important;
+}
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css
new file mode 100644
index 00000000..13a41d28
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css
@@ -0,0 +1,20 @@
+/************************************************************************************************/
+#fbToolbarSearch {
+ background-image: url(search.gif) !important;
+}
+/************************************************************************************************/
+.fbErrors {
+ background-image: url(errorIcon.gif) !important;
+}
+/************************************************************************************************/
+.logRow-info {
+ background-image: url(infoIcon.gif) !important;
+}
+
+.logRow-warning {
+ background-image: url(warningIcon.gif) !important;
+}
+
+.logRow-error {
+ background-image: url(errorIcon.gif) !important;
+}
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.css b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.css
new file mode 100644
index 00000000..a1465ec5
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.css
@@ -0,0 +1,3147 @@
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* Loose */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*
+.netInfoResponseHeadersTitle, netInfoResponseHeadersBody {
+ display: none;
+}
+/**/
+
+.obscured {
+ left: -999999px !important;
+}
+
+/* IE6 need a separated rule, otherwise it will not recognize it */
+.collapsed {
+ display: none;
+}
+
+[collapsed="true"] {
+ display: none;
+}
+
+#fbCSS {
+ padding: 0 !important;
+}
+
+.cssPropDisable {
+ float: left;
+ display: block;
+ width: 2em;
+ cursor: default;
+}
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* panelBase */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+/************************************************************************************************/
+
+.infoTip {
+ z-index: 2147483647;
+ position: fixed;
+ padding: 2px 3px;
+ border: 1px solid #CBE087;
+ background: LightYellow;
+ font-family: Monaco, monospace;
+ color: #000000;
+ display: none;
+ white-space: nowrap;
+ pointer-events: none;
+}
+
+.infoTip[active="true"] {
+ display: block;
+}
+
+.infoTipLoading {
+ width: 16px;
+ height: 16px;
+ background: url(chrome://firebug/skin/loading_16.gif) no-repeat;
+}
+
+.infoTipImageBox {
+ font-size: 11px;
+ min-width: 100px;
+ text-align: center;
+}
+
+.infoTipCaption {
+ font-size: 11px;
+ font: Monaco, monospace;
+}
+
+.infoTipLoading > .infoTipImage,
+.infoTipLoading > .infoTipCaption {
+ display: none;
+}
+
+/************************************************************************************************/
+
+h1.groupHeader {
+ padding: 2px 4px;
+ margin: 0 0 4px 0;
+ border-top: 1px solid #CCCCCC;
+ border-bottom: 1px solid #CCCCCC;
+ background: #eee url(group.gif) repeat-x;
+ font-size: 11px;
+ font-weight: bold;
+ _position: relative;
+}
+
+/************************************************************************************************/
+
+.inlineEditor,
+.fixedWidthEditor {
+ z-index: 2147483647;
+ position: absolute;
+ display: none;
+}
+
+.inlineEditor {
+ margin-left: -6px;
+ margin-top: -3px;
+ /*
+ _margin-left: -7px;
+ _margin-top: -5px;
+ /**/
+}
+
+.textEditorInner,
+.fixedWidthEditor {
+ margin: 0 0 0 0 !important;
+ padding: 0;
+ border: none !important;
+ font: inherit;
+ text-decoration: inherit;
+ background-color: #FFFFFF;
+}
+
+.fixedWidthEditor {
+ border-top: 1px solid #888888 !important;
+ border-bottom: 1px solid #888888 !important;
+}
+
+.textEditorInner {
+ position: relative;
+ top: -7px;
+ left: -5px;
+
+ outline: none;
+ resize: none;
+
+ /*
+ _border: 1px solid #999 !important;
+ _padding: 1px !important;
+ _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040");
+ /**/
+}
+
+.textEditorInner1 {
+ padding-left: 11px;
+ background: url(textEditorBorders.png) repeat-y;
+ _background: url(textEditorBorders.gif) repeat-y;
+ _overflow: hidden;
+}
+
+.textEditorInner2 {
+ position: relative;
+ padding-right: 2px;
+ background: url(textEditorBorders.png) repeat-y 100% 0;
+ _background: url(textEditorBorders.gif) repeat-y 100% 0;
+ _position: fixed;
+}
+
+.textEditorTop1 {
+ background: url(textEditorCorners.png) no-repeat 100% 0;
+ margin-left: 11px;
+ height: 10px;
+ _background: url(textEditorCorners.gif) no-repeat 100% 0;
+ _overflow: hidden;
+}
+
+.textEditorTop2 {
+ position: relative;
+ left: -11px;
+ width: 11px;
+ height: 10px;
+ background: url(textEditorCorners.png) no-repeat;
+ _background: url(textEditorCorners.gif) no-repeat;
+}
+
+.textEditorBottom1 {
+ position: relative;
+ background: url(textEditorCorners.png) no-repeat 100% 100%;
+ margin-left: 11px;
+ height: 12px;
+ _background: url(textEditorCorners.gif) no-repeat 100% 100%;
+}
+
+.textEditorBottom2 {
+ position: relative;
+ left: -11px;
+ width: 11px;
+ height: 12px;
+ background: url(textEditorCorners.png) no-repeat 0 100%;
+ _background: url(textEditorCorners.gif) no-repeat 0 100%;
+}
+
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* CSS */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+/* See license.txt for terms of usage */
+
+.panelNode-css {
+ overflow-x: hidden;
+}
+
+.cssSheet > .insertBefore {
+ height: 1.5em;
+}
+
+.cssRule {
+ position: relative;
+ margin: 0;
+ padding: 1em 0 0 6px;
+ font-family: Monaco, monospace;
+ color: #000000;
+}
+
+.cssRule:first-child {
+ padding-top: 6px;
+}
+
+.cssElementRuleContainer {
+ position: relative;
+}
+
+.cssHead {
+ padding-right: 150px;
+}
+
+.cssProp {
+ /*padding-left: 2em;*/
+}
+
+.cssPropName {
+ color: DarkGreen;
+}
+
+.cssPropValue {
+ margin-left: 8px;
+ color: DarkBlue;
+}
+
+.cssOverridden span {
+ text-decoration: line-through;
+}
+
+.cssInheritedRule {
+}
+
+.cssInheritLabel {
+ margin-right: 0.5em;
+ font-weight: bold;
+}
+
+.cssRule .objectLink-sourceLink {
+ top: 0;
+}
+
+.cssProp.editGroup:hover {
+ background: url(disable.png) no-repeat 2px 1px;
+ _background: url(disable.gif) no-repeat 2px 1px;
+}
+
+.cssProp.editGroup.editing {
+ background: none;
+}
+
+.cssProp.disabledStyle {
+ background: url(disableHover.png) no-repeat 2px 1px;
+ _background: url(disableHover.gif) no-repeat 2px 1px;
+ opacity: 1;
+ color: #CCCCCC;
+}
+
+.disabledStyle .cssPropName,
+.disabledStyle .cssPropValue {
+ color: #CCCCCC;
+}
+
+.cssPropValue.editing + .cssSemi,
+.inlineExpander + .cssSemi {
+ display: none;
+}
+
+.cssPropValue.editing {
+ white-space: nowrap;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.stylePropName {
+ font-weight: bold;
+ padding: 0 4px 4px 4px;
+ width: 50%;
+}
+
+.stylePropValue {
+ width: 50%;
+}
+/*
+.useA11y .a11yCSSView .focusRow:focus {
+ outline: none;
+ background-color: transparent
+ }
+
+ .useA11y .a11yCSSView .focusRow:focus .cssSelector,
+ .useA11y .a11yCSSView .focusRow:focus .cssPropName,
+ .useA11y .a11yCSSView .focusRow:focus .cssPropValue,
+ .useA11y .a11yCSSView .computedStyleRow:focus,
+ .useA11y .a11yCSSView .groupHeader:focus {
+ outline: 2px solid #FF9933;
+ outline-offset: -2px;
+ background-color: #FFFFD6;
+ }
+
+ .useA11y .a11yCSSView .groupHeader:focus {
+ outline-offset: -2px;
+ }
+/**/
+
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* Net */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+/* See license.txt for terms of usage */
+
+.panelNode-net {
+ overflow-x: hidden;
+}
+
+.netTable {
+ width: 100%;
+}
+
+/************************************************************************************************/
+
+.hideCategory-undefined .category-undefined,
+.hideCategory-html .category-html,
+.hideCategory-css .category-css,
+.hideCategory-js .category-js,
+.hideCategory-image .category-image,
+.hideCategory-xhr .category-xhr,
+.hideCategory-flash .category-flash,
+.hideCategory-txt .category-txt,
+.hideCategory-bin .category-bin {
+ display: none;
+}
+
+/************************************************************************************************/
+
+.netHeadRow {
+ background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF;
+}
+
+.netHeadCol {
+ border-bottom: 1px solid #CCCCCC;
+ padding: 2px 4px 2px 18px;
+ font-weight: bold;
+}
+
+.netHeadLabel {
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+/************************************************************************************************/
+/* Header for Net panel table */
+
+.netHeaderRow {
+ height: 16px;
+}
+
+.netHeaderCell {
+ cursor: pointer;
+ -moz-user-select: none;
+ border-bottom: 1px solid #9C9C9C;
+ padding: 0 !important;
+ font-weight: bold;
+ background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;
+ white-space: nowrap;
+}
+
+.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox {
+ padding: 2px 14px 2px 18px;
+}
+
+.netHeaderCellBox {
+ padding: 2px 14px 2px 10px;
+ border-left: 1px solid #D9D9D9;
+ border-right: 1px solid #9C9C9C;
+}
+
+.netHeaderCell:hover:active {
+ background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;
+}
+
+.netHeaderSorted {
+ background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;
+}
+
+.netHeaderSorted > .netHeaderCellBox {
+ border-right-color: #6B7C93;
+ background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;
+}
+
+.netHeaderSorted.sortedAscending > .netHeaderCellBox {
+ background-image: url(chrome://firebug/skin/arrowUp.png);
+}
+
+.netHeaderSorted:hover:active {
+ background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;
+}
+
+/************************************************************************************************/
+/* Breakpoints */
+
+.panelNode-net .netRowHeader {
+ display: block;
+}
+
+.netRowHeader {
+ cursor: pointer;
+ display: none;
+ height: 15px;
+ margin-right: 0 !important;
+}
+
+/* Display brekpoint disc */
+.netRow .netRowHeader {
+ background-position: 5px 1px;
+}
+
+.netRow[breakpoint="true"] .netRowHeader {
+ background-image: url(chrome://firebug/skin/breakpoint.png);
+}
+
+.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader {
+ background-image: url(chrome://firebug/skin/breakpointDisabled.png);
+}
+
+.netRow.category-xhr:hover .netRowHeader {
+ background-color: #F6F6F6;
+}
+
+#netBreakpointBar {
+ max-width: 38px;
+}
+
+#netHrefCol > .netHeaderCellBox {
+ border-left: 0px;
+}
+
+.netRow .netRowHeader {
+ width: 3px;
+}
+
+.netInfoRow .netRowHeader {
+ display: table-cell;
+}
+
+/************************************************************************************************/
+/* Column visibility */
+
+.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],
+.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,
+.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],
+.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,
+.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],
+.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,
+.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],
+.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,
+.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],
+.netTable[hiddenCols~=netTimeCol] TD.netTimeCol {
+ display: none;
+}
+
+/************************************************************************************************/
+
+.netRow {
+ background: LightYellow;
+}
+
+.netRow.loaded {
+ background: #FFFFFF;
+}
+
+.netRow.loaded:hover {
+ background: #EFEFEF;
+}
+
+.netCol {
+ padding: 0;
+ vertical-align: top;
+ border-bottom: 1px solid #EFEFEF;
+ white-space: nowrap;
+ height: 17px;
+}
+
+.netLabel {
+ width: 100%;
+}
+
+.netStatusCol {
+ padding-left: 10px;
+ color: rgb(128, 128, 128);
+}
+
+.responseError > .netStatusCol {
+ color: red;
+}
+
+.netDomainCol {
+ padding-left: 5px;
+}
+
+.netSizeCol {
+ text-align: right;
+ padding-right: 10px;
+}
+
+.netHrefLabel {
+ -moz-box-sizing: padding-box;
+ overflow: hidden;
+ z-index: 10;
+ position: absolute;
+ padding-left: 18px;
+ padding-top: 1px;
+ max-width: 15%;
+ font-weight: bold;
+}
+
+.netFullHrefLabel {
+ display: none;
+ -moz-user-select: none;
+ padding-right: 10px;
+ padding-bottom: 3px;
+ max-width: 100%;
+ background: #FFFFFF;
+ z-index: 200;
+}
+
+.netHrefCol:hover > .netFullHrefLabel {
+ display: block;
+}
+
+.netRow.loaded:hover .netCol > .netFullHrefLabel {
+ background-color: #EFEFEF;
+}
+
+.useA11y .a11yShowFullLabel {
+ display: block;
+ background-image: none !important;
+ border: 1px solid #CBE087;
+ background-color: LightYellow;
+ font-family: Monaco, monospace;
+ color: #000000;
+ font-size: 10px;
+ z-index: 2147483647;
+}
+
+.netSizeLabel {
+ padding-left: 6px;
+}
+
+.netStatusLabel,
+.netDomainLabel,
+.netSizeLabel,
+.netBar {
+ padding: 1px 0 2px 0 !important;
+}
+
+.responseError {
+ color: red;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.hasHeaders .netHrefLabel:hover {
+ cursor: pointer;
+ color: blue;
+ text-decoration: underline;
+}
+
+/************************************************************************************************/
+
+.netLoadingIcon {
+ position: absolute;
+ border: 0;
+ margin-left: 14px;
+ width: 16px;
+ height: 16px;
+ background: transparent no-repeat 0 0;
+ background-image: url(chrome://firebug/skin/loading_16.gif);
+ display:inline-block;
+}
+
+.loaded .netLoadingIcon {
+ display: none;
+}
+
+/************************************************************************************************/
+
+.netBar, .netSummaryBar {
+ position: relative;
+ border-right: 50px solid transparent;
+}
+
+.netResolvingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x;
+ z-index:60;
+}
+
+.netConnectingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x;
+ z-index:50;
+}
+
+.netBlockingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x;
+ z-index:40;
+}
+
+.netSendingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x;
+ z-index:30;
+}
+
+.netWaitingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x;
+ z-index:20;
+ min-width: 1px;
+}
+
+.netReceivingBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x;
+ z-index:10;
+}
+
+.netWindowLoadBar,
+.netContentLoadBar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 1px;
+ background-color: red;
+ z-index: 70;
+ opacity: 0.5;
+ display: none;
+ margin-bottom:-1px;
+}
+
+.netContentLoadBar {
+ background-color: Blue;
+}
+
+.netTimeLabel {
+ -moz-box-sizing: padding-box;
+ position: absolute;
+ top: 1px;
+ left: 100%;
+ padding-left: 6px;
+ color: #444444;
+ min-width: 16px;
+}
+
+/*
+ * Timing info tip is reusing net timeline styles to display the same
+ * colors for individual request phases. Notice that the info tip must
+ * respect also loaded and fromCache styles that also modify the
+ * actual color. These are used both on the same element in case
+ * of the tooltip.
+ */
+.loaded .netReceivingBar,
+.loaded.netReceivingBar {
+ background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x;
+ border-color: #B6B6B6;
+}
+
+.fromCache .netReceivingBar,
+.fromCache.netReceivingBar {
+ background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x;
+ border-color: #D6D6D6;
+}
+
+.netSummaryRow .netTimeLabel,
+.loaded .netTimeLabel {
+ background: transparent;
+}
+
+/************************************************************************************************/
+/* Time Info tip */
+
+.timeInfoTip {
+ width: 150px;
+ height: 40px
+}
+
+.timeInfoTipBar,
+.timeInfoTipEventBar {
+ position: relative;
+ display: block;
+ margin: 0;
+ opacity: 1;
+ height: 15px;
+ width: 4px;
+}
+
+.timeInfoTipEventBar {
+ width: 1px !important;
+}
+
+.timeInfoTipCell.startTime {
+ padding-right: 8px;
+}
+
+.timeInfoTipCell.elapsedTime {
+ text-align: right;
+ padding-right: 8px;
+}
+
+/************************************************************************************************/
+/* Size Info tip */
+
+.sizeInfoLabelCol {
+ font-weight: bold;
+ padding-right: 10px;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+}
+
+.sizeInfoSizeCol {
+ font-weight: bold;
+}
+
+.sizeInfoDetailCol {
+ color: gray;
+ text-align: right;
+}
+
+.sizeInfoDescCol {
+ font-style: italic;
+}
+
+/************************************************************************************************/
+/* Summary */
+
+.netSummaryRow .netReceivingBar {
+ background: #BBBBBB;
+ border: none;
+}
+
+.netSummaryLabel {
+ color: #222222;
+}
+
+.netSummaryRow {
+ background: #BBBBBB !important;
+ font-weight: bold;
+}
+
+.netSummaryRow .netBar {
+ border-right-color: #BBBBBB;
+}
+
+.netSummaryRow > .netCol {
+ border-top: 1px solid #999999;
+ border-bottom: 2px solid;
+ -moz-border-bottom-colors: #EFEFEF #999999;
+ padding-top: 1px;
+ padding-bottom: 2px;
+}
+
+.netSummaryRow > .netHrefCol:hover {
+ background: transparent !important;
+}
+
+.netCountLabel {
+ padding-left: 18px;
+}
+
+.netTotalSizeCol {
+ text-align: right;
+ padding-right: 10px;
+}
+
+.netTotalTimeCol {
+ text-align: right;
+}
+
+.netCacheSizeLabel {
+ position: absolute;
+ z-index: 1000;
+ left: 0;
+ top: 0;
+}
+
+/************************************************************************************************/
+
+.netLimitRow {
+ background: rgb(255, 255, 225) !important;
+ font-weight:normal;
+ color: black;
+ font-weight:normal;
+}
+
+.netLimitLabel {
+ padding-left: 18px;
+}
+
+.netLimitRow > .netCol {
+ border-bottom: 2px solid;
+ -moz-border-bottom-colors: #EFEFEF #999999;
+ vertical-align: middle !important;
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+.netLimitButton {
+ font-size: 11px;
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
+
+/************************************************************************************************/
+
+.netInfoCol {
+ border-top: 1px solid #EEEEEE;
+ background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF;
+}
+
+.netInfoBody {
+ margin: 10px 0 4px 10px;
+}
+
+.netInfoTabs {
+ position: relative;
+ padding-left: 17px;
+}
+
+.netInfoTab {
+ position: relative;
+ top: -3px;
+ margin-top: 10px;
+ padding: 4px 6px;
+ border: 1px solid transparent;
+ border-bottom: none;
+ _border: none;
+ font-weight: bold;
+ color: #565656;
+ cursor: pointer;
+}
+
+/*.netInfoTab:hover {
+ cursor: pointer;
+}*/
+
+/* replaced by .netInfoTabSelected for IE6 support
+.netInfoTab[selected="true"] {
+ cursor: default !important;
+ border: 1px solid #D7D7D7 !important;
+ border-bottom: none !important;
+ -moz-border-radius: 4px 4px 0 0;
+ background-color: #FFFFFF;
+}
+/**/
+.netInfoTabSelected {
+ cursor: default !important;
+ border: 1px solid #D7D7D7 !important;
+ border-bottom: none !important;
+ -moz-border-radius: 4px 4px 0 0;
+ -webkit-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+ background-color: #FFFFFF;
+}
+
+.logRow-netInfo.error .netInfoTitle {
+ color: red;
+}
+
+.logRow-netInfo.loading .netInfoResponseText {
+ font-style: italic;
+ color: #888888;
+}
+
+.loading .netInfoResponseHeadersTitle {
+ display: none;
+}
+
+.netInfoResponseSizeLimit {
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ padding-top: 10px;
+ font-size: 11px;
+}
+
+.netInfoText {
+ display: none;
+ margin: 0;
+ border: 1px solid #D7D7D7;
+ border-right: none;
+ padding: 8px;
+ background-color: #FFFFFF;
+ font-family: Monaco, monospace;
+ white-space: pre-wrap;
+ /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */
+}
+
+/* replaced by .netInfoTextSelected for IE6 support
+.netInfoText[selected="true"] {
+ display: block;
+}
+/**/
+.netInfoTextSelected {
+ display: block;
+}
+
+.netInfoParamName {
+ padding-right: 10px;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-weight: bold;
+ vertical-align: top;
+ text-align: right;
+ white-space: nowrap;
+}
+
+.netInfoPostText .netInfoParamName {
+ width: 1px; /* Google Chrome need this otherwise the first column of
+ the post variables table will be larger than expected */
+}
+
+.netInfoParamValue {
+ width: 100%;
+}
+
+.netInfoHeadersText,
+.netInfoPostText,
+.netInfoPutText {
+ padding-top: 0;
+}
+
+.netInfoHeadersGroup,
+.netInfoPostParams,
+.netInfoPostSource {
+ margin-bottom: 4px;
+ border-bottom: 1px solid #D7D7D7;
+ padding-top: 8px;
+ padding-bottom: 2px;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-weight: bold;
+ color: #565656;
+}
+
+.netInfoPostParamsTable,
+.netInfoPostPartsTable,
+.netInfoPostJSONTable,
+.netInfoPostXMLTable,
+.netInfoPostSourceTable {
+ margin-bottom: 10px;
+ width: 100%;
+}
+
+.netInfoPostContentType {
+ color: #bdbdbd;
+ padding-left: 50px;
+ font-weight: normal;
+}
+
+.netInfoHtmlPreview {
+ border: 0;
+ width: 100%;
+ height:100%;
+}
+
+/************************************************************************************************/
+/* Request & Response Headers */
+
+.netHeadersViewSource {
+ color: #bdbdbd;
+ margin-left: 200px;
+ font-weight: normal;
+}
+
+.netHeadersViewSource:hover {
+ color: blue;
+ cursor: pointer;
+}
+
+/************************************************************************************************/
+
+.netActivationRow,
+.netPageSeparatorRow {
+ background: rgb(229, 229, 229) !important;
+ font-weight: normal;
+ color: black;
+}
+
+.netActivationLabel {
+ background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;
+ padding-left: 22px;
+}
+
+/************************************************************************************************/
+
+.netPageSeparatorRow {
+ height: 5px !important;
+}
+
+.netPageSeparatorLabel {
+ padding-left: 22px;
+ height: 5px !important;
+}
+
+.netPageRow {
+ background-color: rgb(255, 255, 255);
+}
+
+.netPageRow:hover {
+ background: #EFEFEF;
+}
+
+.netPageLabel {
+ padding: 1px 0 2px 18px !important;
+ font-weight: bold;
+}
+
+/************************************************************************************************/
+
+.netActivationRow > .netCol {
+ border-bottom: 2px solid;
+ -moz-border-bottom-colors: #EFEFEF #999999;
+ padding-top: 2px;
+ padding-bottom: 3px;
+}
+/*
+.useA11y .panelNode-net .a11yFocus:focus,
+.useA11y .panelNode-net .focusRow:focus {
+ outline-offset: -2px;
+ background-color: #FFFFD6 !important;
+}
+
+.useA11y .panelNode-net .netHeaderCell:focus,
+.useA11y .panelNode-net :focus .netHeaderCell,
+.useA11y .panelNode-net :focus .netReceivingBar,
+.useA11y .netSummaryRow :focus .netBar,
+.useA11y .netSummaryRow:focus .netBar {
+ background-color: #FFFFD6;
+ background-image: none;
+ border-color: #FFFFD6;
+}
+/**/
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* Windows */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+
+/************************************************************************************************/
+/* Twisties */
+
+.twisty,
+.logRow-errorMessage > .hasTwisty > .errorTitle,
+.logRow-log > .objectBox-array.hasTwisty,
+.logRow-spy .spyHead .spyTitle,
+.logGroup > .logRow,
+.memberRow.hasChildren > .memberLabelCell > .memberLabel,
+.hasHeaders .netHrefLabel,
+.netPageRow > .netCol > .netPageTitle {
+ background-image: url(tree_open.gif);
+ background-repeat: no-repeat;
+ background-position: 2px 2px;
+ min-height: 12px;
+}
+
+.logRow-errorMessage > .hasTwisty.opened > .errorTitle,
+.logRow-log > .objectBox-array.hasTwisty.opened,
+.logRow-spy.opened .spyHead .spyTitle,
+.logGroup.opened > .logRow,
+.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
+.nodeBox.highlightOpen > .nodeLabel > .twisty,
+.nodeBox.open > .nodeLabel > .twisty,
+.netRow.opened > .netCol > .netHrefLabel,
+.netPageRow.opened > .netCol > .netPageTitle {
+ background-image: url(tree_close.gif);
+}
+
+.twisty {
+ background-position: 4px 4px;
+}
+
+
+
+/************************************************************************************************/
+/* Twisties IE6 */
+
+/* IE6 has problems with > operator, and multiple classes */
+
+* html .logRow-spy .spyHead .spyTitle,
+* html .logGroup .logGroupLabel,
+* html .hasChildren .memberLabelCell .memberLabel,
+* html .hasHeaders .netHrefLabel {
+ background-image: url(tree_open.gif);
+ background-repeat: no-repeat;
+ background-position: 2px 2px;
+}
+
+* html .opened .spyHead .spyTitle,
+* html .opened .logGroupLabel,
+* html .opened .memberLabelCell .memberLabel {
+ background-image: url(tree_close.gif);
+ background-repeat: no-repeat;
+ background-position: 2px 2px;
+}
+
+
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* Console */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+
+/* See license.txt for terms of usage */
+
+.panelNode-console {
+ overflow-x: hidden;
+}
+
+.objectLink {
+ text-decoration: none;
+}
+
+.objectLink:hover {
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+.logRow {
+ position: relative;
+ margin: 0;
+ border-bottom: 1px solid #D7D7D7;
+ padding: 2px 4px 1px 6px;
+ background-color: #FFFFFF;
+ overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */
+}
+
+.useA11y .logRow:focus {
+ border-bottom: 1px solid #000000 !important;
+ outline: none !important;
+ background-color: #FFFFAD !important;
+}
+
+.useA11y .logRow:focus a.objectLink-sourceLink {
+ background-color: #FFFFAD;
+}
+
+.useA11y .a11yFocus:focus, .useA11y .objectBox:focus {
+ outline: 2px solid #FF9933;
+ background-color: #FFFFAD;
+}
+
+.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{
+ background-color: #888888 !important;
+}
+
+.useA11y .logGroup.opened > .logRow {
+ border-bottom: 1px solid #ffffff;
+}
+
+.logGroup {
+ background: url(group.gif) repeat-x #FFFFFF;
+ padding: 0 !important;
+ border: none !important;
+}
+
+.logGroupBody {
+ display: none;
+ margin-left: 16px;
+ border-left: 1px solid #D7D7D7;
+ border-top: 1px solid #D7D7D7;
+ background: #FFFFFF;
+}
+
+.logGroup > .logRow {
+ background-color: transparent !important;
+ font-weight: bold;
+}
+
+.logGroup.opened > .logRow {
+ border-bottom: none;
+}
+
+.logGroup.opened > .logGroupBody {
+ display: block;
+}
+
+/*****************************************************************************************/
+
+.logRow-command > .objectBox-text {
+ font-family: Monaco, monospace;
+ color: #0000FF;
+ white-space: pre-wrap;
+}
+
+.logRow-info,
+.logRow-warn,
+.logRow-error,
+.logRow-assert,
+.logRow-warningMessage,
+.logRow-errorMessage {
+ padding-left: 22px;
+ background-repeat: no-repeat;
+ background-position: 4px 2px;
+}
+
+.logRow-assert,
+.logRow-warningMessage,
+.logRow-errorMessage {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+.logRow-info,
+.logRow-info .objectLink-sourceLink {
+ background-color: #FFFFFF;
+}
+
+.logRow-warn,
+.logRow-warningMessage,
+.logRow-warn .objectLink-sourceLink,
+.logRow-warningMessage .objectLink-sourceLink {
+ background-color: cyan;
+}
+
+.logRow-error,
+.logRow-assert,
+.logRow-errorMessage,
+.logRow-error .objectLink-sourceLink,
+.logRow-errorMessage .objectLink-sourceLink {
+ background-color: LightYellow;
+}
+
+.logRow-error,
+.logRow-assert,
+.logRow-errorMessage {
+ color: #FF0000;
+}
+
+.logRow-info {
+ /*background-image: url(chrome://firebug/skin/infoIcon.png);*/
+}
+
+.logRow-warn,
+.logRow-warningMessage {
+ /*background-image: url(chrome://firebug/skin/warningIcon.png);*/
+}
+
+.logRow-error,
+.logRow-assert,
+.logRow-errorMessage {
+ /*background-image: url(chrome://firebug/skin/errorIcon.png);*/
+}
+
+/*****************************************************************************************/
+
+.objectBox-string,
+.objectBox-text,
+.objectBox-number,
+.objectLink-element,
+.objectLink-textNode,
+.objectLink-function,
+.objectBox-stackTrace,
+.objectLink-profile {
+ font-family: Monaco, monospace;
+}
+
+.objectBox-string,
+.objectBox-text,
+.objectLink-textNode {
+ white-space: pre-wrap;
+}
+
+.objectBox-number,
+.objectLink-styleRule,
+.objectLink-element,
+.objectLink-textNode {
+ color: #000088;
+}
+
+.objectBox-string {
+ color: #FF0000;
+}
+
+.objectLink-function,
+.objectBox-stackTrace,
+.objectLink-profile {
+ color: DarkGreen;
+}
+
+.objectBox-null,
+.objectBox-undefined {
+ padding: 0 2px;
+ border: 1px solid #666666;
+ background-color: #888888;
+ color: #FFFFFF;
+}
+
+.objectBox-exception {
+ padding: 0 2px 0 18px;
+ /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/
+ color: red;
+}
+
+.objectLink-sourceLink {
+ position: absolute;
+ right: 4px;
+ top: 2px;
+ padding-left: 8px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: #0000FF;
+}
+
+/************************************************************************************************/
+
+.errorTitle {
+ margin-top: 0px;
+ margin-bottom: 1px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+.errorTrace {
+ margin-left: 17px;
+}
+
+.errorSourceBox {
+ margin: 2px 0;
+}
+
+.errorSource-none {
+ display: none;
+}
+
+.errorSource-syntax > .errorBreak {
+ visibility: hidden;
+}
+
+.errorSource {
+ cursor: pointer;
+ font-family: Monaco, monospace;
+ color: DarkGreen;
+}
+
+.errorSource:hover {
+ text-decoration: underline;
+}
+
+.errorBreak {
+ cursor: pointer;
+ display: none;
+ margin: 0 6px 0 0;
+ width: 13px;
+ height: 14px;
+ vertical-align: bottom;
+ /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/
+ opacity: 0.1;
+}
+
+.hasBreakSwitch .errorBreak {
+ display: inline;
+}
+
+.breakForError .errorBreak {
+ opacity: 1;
+}
+
+.assertDescription {
+ margin: 0;
+}
+
+/************************************************************************************************/
+
+.logRow-profile > .logRow > .objectBox-text {
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ color: #000000;
+}
+
+.logRow-profile > .logRow > .objectBox-text:last-child {
+ color: #555555;
+ font-style: italic;
+}
+
+.logRow-profile.opened > .logRow {
+ padding-bottom: 4px;
+}
+
+.profilerRunning > .logRow {
+ /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/
+ padding-left: 22px !important;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.profileSizer {
+ width:100%;
+ overflow-x:auto;
+ overflow-y: scroll;
+}
+
+.profileTable {
+ border-bottom: 1px solid #D7D7D7;
+ padding: 0 0 4px 0;
+}
+
+.profileTable tr[odd="1"] {
+ background-color: #F5F5F5;
+ vertical-align:middle;
+}
+
+.profileTable a {
+ vertical-align:middle;
+}
+
+.profileTable td {
+ padding: 1px 4px 0 4px;
+}
+
+.headerCell {
+ cursor: pointer;
+ -moz-user-select: none;
+ border-bottom: 1px solid #9C9C9C;
+ padding: 0 !important;
+ font-weight: bold;
+ /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/
+}
+
+.headerCellBox {
+ padding: 2px 4px;
+ border-left: 1px solid #D9D9D9;
+ border-right: 1px solid #9C9C9C;
+}
+
+.headerCell:hover:active {
+ /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/
+}
+
+.headerSorted {
+ /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/
+}
+
+.headerSorted > .headerCellBox {
+ border-right-color: #6B7C93;
+ /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/
+}
+
+.headerSorted.sortedAscending > .headerCellBox {
+ /*background-image: url(chrome://firebug/skin/arrowUp.png);*/
+}
+
+.headerSorted:hover:active {
+ /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/
+}
+
+.linkCell {
+ text-align: right;
+}
+
+.linkCell > .objectLink-sourceLink {
+ position: static;
+}
+
+/*****************************************************************************************/
+
+.logRow-stackTrace {
+ padding-top: 0;
+ background: #f8f8f8;
+}
+
+.logRow-stackTrace > .objectBox-stackFrame {
+ position: relative;
+ padding-top: 2px;
+}
+
+/************************************************************************************************/
+
+.objectLink-object {
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: DarkGreen;
+ white-space: pre-wrap;
+}
+
+/* xxxpedro reps object representation .................................... */
+.objectProp-object {
+ color: DarkGreen;
+}
+
+.objectProps {
+ color: #000;
+ font-weight: normal;
+}
+
+.objectPropName {
+ /*font-style: italic;*/
+ color: #777;
+}
+
+/*
+.objectProps .objectProp-string,
+.objectProps .objectProp-number,
+.objectProps .objectProp-object
+{
+ font-style: italic;
+}
+/**/
+
+.objectProps .objectProp-string
+{
+ /*font-family: Monaco, monospace;*/
+ color: #f55;
+}
+.objectProps .objectProp-number
+{
+ /*font-family: Monaco, monospace;*/
+ color: #55a;
+}
+.objectProps .objectProp-object
+{
+ /*font-family: Lucida Grande,sans-serif;*/
+ color: #585;
+}
+/* xxxpedro reps object representation .................................... */
+
+/************************************************************************************************/
+
+.selectorTag,
+.selectorId,
+.selectorClass {
+ font-family: Monaco, monospace;
+ font-weight: normal;
+}
+
+.selectorTag {
+ color: #0000FF;
+}
+
+.selectorId {
+ color: DarkBlue;
+}
+
+.selectorClass {
+ color: red;
+}
+
+.selectorHidden > .selectorTag {
+ color: #5F82D9;
+}
+
+.selectorHidden > .selectorId {
+ color: #888888;
+}
+
+.selectorHidden > .selectorClass {
+ color: #D86060;
+}
+
+.selectorValue {
+ font-family: Lucida Grande, sans-serif;
+ font-style: italic;
+ color: #555555;
+}
+
+/*****************************************************************************************/
+
+.panelNode.searching .logRow {
+ display: none;
+}
+
+.logRow.matched {
+ display: block !important;
+}
+
+.logRow.matching {
+ position: absolute;
+ left: -1000px;
+ top: -1000px;
+ max-width: 0;
+ max-height: 0;
+ overflow: hidden;
+}
+
+/*****************************************************************************************/
+
+.objectLeftBrace,
+.objectRightBrace,
+.objectEqual,
+.objectComma,
+.arrayLeftBracket,
+.arrayRightBracket,
+.arrayComma {
+ font-family: Monaco, monospace;
+}
+
+.objectLeftBrace,
+.objectRightBrace,
+.arrayLeftBracket,
+.arrayRightBracket {
+ font-weight: bold;
+}
+
+.objectLeftBrace,
+.arrayLeftBracket {
+ margin-right: 4px;
+}
+
+.objectRightBrace,
+.arrayRightBracket {
+ margin-left: 4px;
+}
+
+/*****************************************************************************************/
+
+.logRow-dir {
+ padding: 0;
+}
+
+/************************************************************************************************/
+
+/*
+.logRow-errorMessage > .hasTwisty > .errorTitle,
+.logRow-spy .spyHead .spyTitle,
+.logGroup > .logRow
+*/
+.logRow-errorMessage .hasTwisty .errorTitle,
+.logRow-spy .spyHead .spyTitle,
+.logGroup .logRow {
+ cursor: pointer;
+ padding-left: 18px;
+ background-repeat: no-repeat;
+ background-position: 3px 3px;
+}
+
+.logRow-errorMessage > .hasTwisty > .errorTitle {
+ background-position: 2px 3px;
+}
+
+.logRow-errorMessage > .hasTwisty > .errorTitle:hover,
+.logRow-spy .spyHead .spyTitle:hover,
+.logGroup > .logRow:hover {
+ text-decoration: underline;
+}
+
+/*****************************************************************************************/
+
+.logRow-spy {
+ padding: 0 !important;
+}
+
+.logRow-spy,
+.logRow-spy .objectLink-sourceLink {
+ background: url(group.gif) repeat-x #FFFFFF;
+ padding-right: 4px;
+ right: 0;
+}
+
+.logRow-spy.opened {
+ padding-bottom: 4px;
+ border-bottom: none;
+}
+
+.spyTitle {
+ color: #000000;
+ font-weight: bold;
+ -moz-box-sizing: padding-box;
+ overflow: hidden;
+ z-index: 100;
+ padding-left: 18px;
+}
+
+.spyCol {
+ padding: 0;
+ white-space: nowrap;
+ height: 16px;
+}
+
+.spyTitleCol:hover > .objectLink-sourceLink,
+.spyTitleCol:hover > .spyTime,
+.spyTitleCol:hover > .spyStatus,
+.spyTitleCol:hover > .spyTitle {
+ display: none;
+}
+
+.spyFullTitle {
+ display: none;
+ -moz-user-select: none;
+ max-width: 100%;
+ background-color: Transparent;
+}
+
+.spyTitleCol:hover > .spyFullTitle {
+ display: block;
+}
+
+.spyStatus {
+ padding-left: 10px;
+ color: rgb(128, 128, 128);
+}
+
+.spyTime {
+ margin-left:4px;
+ margin-right:4px;
+ color: rgb(128, 128, 128);
+}
+
+.spyIcon {
+ margin-right: 4px;
+ margin-left: 4px;
+ width: 16px;
+ height: 16px;
+ vertical-align: middle;
+ background: transparent no-repeat 0 0;
+ display: none;
+}
+
+.loading .spyHead .spyRow .spyIcon {
+ background-image: url(loading_16.gif);
+ display: block;
+}
+
+.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon {
+ width: 0;
+ margin: 0;
+}
+
+.logRow-spy.error .spyHead .spyRow .spyIcon {
+ background-image: url(errorIcon-sm.png);
+ display: block;
+ background-position: 2px 2px;
+}
+
+.logRow-spy .spyHead .netInfoBody {
+ display: none;
+}
+
+.logRow-spy.opened .spyHead .netInfoBody {
+ margin-top: 10px;
+ display: block;
+}
+
+.logRow-spy.error .spyTitle,
+.logRow-spy.error .spyStatus,
+.logRow-spy.error .spyTime {
+ color: red;
+}
+
+.logRow-spy.loading .spyResponseText {
+ font-style: italic;
+ color: #888888;
+}
+
+/************************************************************************************************/
+
+.caption {
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-weight: bold;
+ color: #444444;
+}
+
+.warning {
+ padding: 10px;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-weight: bold;
+ color: #888888;
+}
+
+
+
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* DOM */
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+
+
+/* See license.txt for terms of usage */
+
+.panelNode-dom {
+ overflow-x: hidden !important;
+}
+
+.domTable {
+ font-size: 1em;
+ width: 100%;
+ table-layout: fixed;
+ background: #fff;
+}
+
+.domTableIE {
+ width: auto;
+}
+
+.memberLabelCell {
+ padding: 2px 0 2px 0;
+ vertical-align: top;
+}
+
+.memberValueCell {
+ padding: 1px 0 1px 5px;
+ display: block;
+ overflow: hidden;
+}
+
+.memberLabel {
+ display: block;
+ cursor: default;
+ -moz-user-select: none;
+ overflow: hidden;
+ /*position: absolute;*/
+ padding-left: 18px;
+ /*max-width: 30%;*/
+ /*white-space: nowrap;*/
+ background-color: #FFFFFF;
+ text-decoration: none;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.memberRow.hasChildren .memberLabelCell .memberLabel:hover {
+ cursor: pointer;
+ color: blue;
+ text-decoration: underline;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.userLabel {
+ color: #000000;
+ font-weight: bold;
+}
+
+.userClassLabel {
+ color: #E90000;
+ font-weight: bold;
+}
+
+.userFunctionLabel {
+ color: #025E2A;
+ font-weight: bold;
+}
+
+.domLabel {
+ color: #000000;
+}
+
+.domFunctionLabel {
+ color: #025E2A;
+}
+
+.ordinalLabel {
+ color: SlateBlue;
+ font-weight: bold;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+.scopesRow {
+ padding: 2px 18px;
+ background-color: LightYellow;
+ border-bottom: 5px solid #BEBEBE;
+ color: #666666;
+}
+.scopesLabel {
+ background-color: LightYellow;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.watchEditCell {
+ padding: 2px 18px;
+ background-color: LightYellow;
+ border-bottom: 1px solid #BEBEBE;
+ color: #666666;
+}
+
+.editor-watchNewRow,
+.editor-memberRow {
+ font-family: Monaco, monospace !important;
+}
+
+.editor-memberRow {
+ padding: 1px 0 !important;
+}
+
+.editor-watchRow {
+ padding-bottom: 0 !important;
+}
+
+.watchRow > .memberLabelCell {
+ font-family: Monaco, monospace;
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
+
+.watchRow > .memberLabelCell > .memberLabel {
+ background-color: transparent;
+}
+
+.watchRow > .memberValueCell {
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+.watchRow > .memberLabelCell,
+.watchRow > .memberValueCell {
+ background-color: #F5F5F5;
+ border-bottom: 1px solid #BEBEBE;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.watchToolbox {
+ z-index: 2147483647;
+ position: absolute;
+ right: 0;
+ padding: 1px 2px;
+}
+
+
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/*************************************************************************************************/
+/* FROM ORIGINAL FIREBUG */
+
+
+
+
+/************************************************************************************************
+ CSS Not organized
+*************************************************************************************************/
+#fbConsole {
+ overflow-x: hidden !important;
+}
+
+#fbCSS {
+ font: 1em Monaco, monospace;
+ padding: 0 7px;
+}
+
+#fbstylesheetButtons select, #fbScriptButtons select {
+ font: 11px Lucida Grande, Tahoma, sans-serif;
+ margin-top: 1px;
+ padding-left: 3px;
+ background: #fafafa;
+ border: 1px inset #fff;
+ width: 220px;
+ outline: none;
+}
+
+.Selector { margin-top:10px }
+.CSSItem {margin-left: 4% }
+.CSSText { padding-left:20px; }
+.CSSProperty { color:#005500; }
+.CSSValue { padding-left:5px; color:#000088; }
+
+
+/************************************************************************************************
+ Not organized
+*************************************************************************************************/
+
+#fbHTMLStatusBar {
+ display: inline;
+}
+
+.fbToolbarButtons {
+ display: none;
+}
+
+.fbStatusSeparator{
+ display: block;
+ float: left;
+ padding-top: 4px;
+}
+
+#fbStatusBarBox {
+ display: none;
+}
+
+#fbToolbarContent {
+ display: block;
+ position: absolute;
+ _position: absolute;
+ top: 0;
+ padding-top: 4px;
+ height: 23px;
+ clip: rect(0, 2048px, 27px, 0);
+}
+
+.fbTabMenuTarget {
+ display: none !important;
+ float: left;
+ width: 10px;
+ height: 10px;
+ margin-top: 6px;
+ background: url(tabMenuTarget.png);
+}
+
+.fbTabMenuTarget:hover {
+ background: url(tabMenuTargetHover.png);
+}
+
+.fbShadow {
+ float: left;
+ background: url(shadowAlpha.png) no-repeat bottom right !important;
+ background: url(shadow2.gif) no-repeat bottom right;
+ margin: 10px 0 0 10px !important;
+ margin: 10px 0 0 5px;
+}
+
+.fbShadowContent {
+ display: block;
+ position: relative;
+ background-color: #fff;
+ border: 1px solid #a9a9a9;
+ top: -6px;
+ left: -6px;
+}
+
+.fbMenu {
+ display: none;
+ position: absolute;
+ font-size: 11px;
+ line-height: 13px;
+ z-index: 2147483647;
+}
+
+.fbMenuContent {
+ padding: 2px;
+}
+
+.fbMenuSeparator {
+ display: block;
+ position: relative;
+ padding: 1px 18px 0;
+ text-decoration: none;
+ color: #000;
+ cursor: default;
+ background: #ACA899;
+ margin: 4px 0;
+}
+
+.fbMenuOption
+{
+ display: block;
+ position: relative;
+ padding: 2px 18px;
+ text-decoration: none;
+ color: #000;
+ cursor: default;
+}
+
+.fbMenuOption:hover
+{
+ color: #fff;
+ background: #316AC5;
+}
+
+.fbMenuGroup {
+ background: transparent url(tabMenuPin.png) no-repeat right 0;
+}
+
+.fbMenuGroup:hover {
+ background: #316AC5 url(tabMenuPin.png) no-repeat right -17px;
+}
+
+.fbMenuGroupSelected {
+ color: #fff;
+ background: #316AC5 url(tabMenuPin.png) no-repeat right -17px;
+}
+
+.fbMenuChecked {
+ background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0;
+}
+
+.fbMenuChecked:hover {
+ background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px;
+}
+
+.fbMenuRadioSelected {
+ background: transparent url(tabMenuRadio.png) no-repeat 4px 0;
+}
+
+.fbMenuRadioSelected:hover {
+ background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px;
+}
+
+.fbMenuShortcut {
+ padding-right: 85px;
+}
+
+.fbMenuShortcutKey {
+ position: absolute;
+ right: 0;
+ top: 2px;
+ width: 77px;
+}
+
+#fbFirebugMenu {
+ top: 22px;
+ left: 0;
+}
+
+.fbMenuDisabled {
+ color: #ACA899 !important;
+}
+
+#fbFirebugSettingsMenu {
+ left: 245px;
+ top: 99px;
+}
+
+#fbConsoleMenu {
+ top: 42px;
+ left: 48px;
+}
+
+.fbIconButton {
+ display: block;
+}
+
+.fbIconButton {
+ display: block;
+}
+
+.fbIconButton {
+ display: block;
+ float: left;
+ height: 20px;
+ width: 20px;
+ color: #000;
+ margin-right: 2px;
+ text-decoration: none;
+ cursor: default;
+}
+
+.fbIconButton:hover {
+ position: relative;
+ top: -1px;
+ left: -1px;
+ margin-right: 0;
+ _margin-right: 1px;
+ color: #333;
+ border: 1px solid #fff;
+ border-bottom: 1px solid #bbb;
+ border-right: 1px solid #bbb;
+}
+
+.fbIconPressed {
+ position: relative;
+ margin-right: 0;
+ _margin-right: 1px;
+ top: 0 !important;
+ left: 0 !important;
+ height: 19px;
+ color: #333 !important;
+ border: 1px solid #bbb !important;
+ border-bottom: 1px solid #cfcfcf !important;
+ border-right: 1px solid #ddd !important;
+}
+
+
+
+/************************************************************************************************
+ Error Popup
+*************************************************************************************************/
+#fbErrorPopup {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ height: 19px;
+ width: 75px;
+ background: url(sprite.png) #f1f2ee 0 0;
+ z-index: 999;
+}
+
+#fbErrorPopupContent {
+ position: absolute;
+ right: 0;
+ top: 1px;
+ height: 18px;
+ width: 75px;
+ _width: 74px;
+ border-left: 1px solid #aca899;
+}
+
+#fbErrorIndicator {
+ position: absolute;
+ top: 2px;
+ right: 5px;
+}
+
+
+
+
+
+
+
+
+
+
+.fbBtnInspectActive {
+ background: #aaa;
+ color: #fff !important;
+}
+
+/************************************************************************************************
+ General
+*************************************************************************************************/
+.fbBody {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ background: #fff;
+}
+
+.clear {
+ clear: both;
+}
+
+/************************************************************************************************
+ Mini Chrome
+*************************************************************************************************/
+#fbMiniChrome {
+ display: none;
+ right: 0;
+ height: 27px;
+ background: url(sprite.png) #f1f2ee 0 0;
+ margin-left: 1px;
+}
+
+#fbMiniContent {
+ display: block;
+ position: relative;
+ left: -1px;
+ right: 0;
+ top: 1px;
+ height: 25px;
+ border-left: 1px solid #aca899;
+}
+
+#fbToolbarSearch {
+ float: right;
+ border: 1px solid #ccc;
+ margin: 0 5px 0 0;
+ background: #fff url(search.png) no-repeat 4px 2px !important;
+ background: #fff url(search.gif) no-repeat 4px 2px;
+ padding-left: 20px;
+ font-size: 11px;
+}
+
+#fbToolbarErrors {
+ float: right;
+ margin: 1px 4px 0 0;
+ font-size: 11px;
+}
+
+#fbLeftToolbarErrors {
+ float: left;
+ margin: 7px 0px 0 5px;
+ font-size: 11px;
+}
+
+.fbErrors {
+ padding-left: 20px;
+ height: 14px;
+ background: url(errorIcon.png) no-repeat !important;
+ background: url(errorIcon.gif) no-repeat;
+ color: #f00;
+ font-weight: bold;
+}
+
+#fbMiniErrors {
+ display: inline;
+ display: none;
+ float: right;
+ margin: 5px 2px 0 5px;
+}
+
+#fbMiniIcon {
+ float: right;
+ margin: 3px 4px 0;
+ height: 20px;
+ width: 20px;
+ float: right;
+ background: url(sprite.png) 0 -135px;
+ cursor: pointer;
+}
+
+
+/************************************************************************************************
+ Master Layout
+*************************************************************************************************/
+#fbChrome {
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ position: absolute;
+ _position: static;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+ background: #fff;
+ overflow: hidden;
+}
+
+#fbChrome > tbody > tr > td {
+ padding: 0;
+}
+
+#fbTop {
+ height: 49px;
+}
+
+#fbToolbar {
+ background: url(sprite.png) #f1f2ee 0 0;
+ height: 27px;
+ font-size: 11px;
+ line-height: 13px;
+}
+
+#fbPanelBarBox {
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ height: 22px;
+}
+
+#fbContent {
+ height: 100%;
+ vertical-align: top;
+}
+
+#fbBottom {
+ height: 18px;
+ background: #fff;
+}
+
+/************************************************************************************************
+ Sub-Layout
+*************************************************************************************************/
+
+/* fbToolbar
+*************************************************************************************************/
+#fbToolbarIcon {
+ float: left;
+ padding: 0 5px 0;
+}
+
+#fbToolbarIcon a {
+ background: url(sprite.png) 0 -135px;
+}
+
+#fbToolbarButtons {
+ padding: 0 2px 0 5px;
+}
+
+#fbToolbarButtons {
+ padding: 0 2px 0 5px;
+}
+/*
+#fbStatusBarBox a {
+ text-decoration: none;
+ display: block;
+ float: left;
+ color: #000;
+ padding: 4px 5px;
+ margin: 0 0 0 1px;
+ cursor: default;
+}
+
+#fbStatusBarBox a:hover {
+ color: #333;
+ padding: 3px 4px;
+ border: 1px solid #fff;
+ border-bottom: 1px solid #bbb;
+ border-right: 1px solid #bbb;
+}
+/**/
+
+.fbButton {
+ text-decoration: none;
+ display: block;
+ float: left;
+ color: #000;
+ padding: 4px 6px 4px 7px;
+ cursor: default;
+}
+
+.fbButton:hover {
+ color: #333;
+ background: #f5f5ef url(buttonBg.png);
+ padding: 3px 5px 3px 6px;
+ border: 1px solid #fff;
+ border-bottom: 1px solid #bbb;
+ border-right: 1px solid #bbb;
+}
+
+.fbBtnPressed {
+ background: #e3e3db url(buttonBgHover.png) !important;
+ padding: 3px 4px 2px 6px !important;
+ margin: 1px 0 0 1px !important;
+ border: 1px solid #ACA899 !important;
+ border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;
+}
+
+#fbStatusBarBox {
+ top: 4px;
+ cursor: default;
+}
+
+.fbToolbarSeparator {
+ overflow: hidden;
+ border: 1px solid;
+ border-color: transparent #fff transparent #777;
+ _border-color: #eee #fff #eee #777;
+ height: 7px;
+ margin: 6px 3px;
+ float: left;
+}
+
+.fbBtnSelected {
+ font-weight: bold;
+}
+
+.fbStatusBar {
+ color: #aca899;
+}
+
+.fbStatusBar a {
+ text-decoration: none;
+ color: black;
+}
+
+.fbStatusBar a:hover {
+ color: blue;
+ cursor: pointer;
+}
+
+
+#fbWindowButtons {
+ position: absolute;
+ white-space: nowrap;
+ right: 0;
+ top: 0;
+ height: 17px;
+ width: 48px;
+ padding: 5px;
+ z-index: 6;
+ background: url(sprite.png) #f1f2ee 0 0;
+}
+
+/* fbPanelBarBox
+*************************************************************************************************/
+
+#fbPanelBar1 {
+ width: 1024px; /* fixed width to avoid tabs breaking line */
+ z-index: 8;
+ left: 0;
+ white-space: nowrap;
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ position: absolute;
+ left: 4px;
+}
+
+#fbPanelBar2Box {
+ background: url(sprite.png) #dbd9c9 0 -27px;
+ position: absolute;
+ height: 22px;
+ width: 300px; /* fixed width to avoid tabs breaking line */
+ z-index: 9;
+ right: 0;
+}
+
+#fbPanelBar2 {
+ position: absolute;
+ width: 290px; /* fixed width to avoid tabs breaking line */
+ height: 22px;
+ padding-left: 4px;
+}
+
+/* body
+*************************************************************************************************/
+.fbPanel {
+ display: none;
+}
+
+#fbPanelBox1, #fbPanelBox2 {
+ max-height: inherit;
+ height: 100%;
+ font-size: 1em;
+}
+
+#fbPanelBox2 {
+ background: #fff;
+}
+
+#fbPanelBox2 {
+ width: 300px;
+ background: #fff;
+}
+
+#fbPanel2 {
+ margin-left: 6px;
+ background: #fff;
+}
+
+#fbLargeCommandLine {
+ display: none;
+ position: absolute;
+ z-index: 9;
+ top: 27px;
+ right: 0;
+ width: 294px;
+ height: 201px;
+ border-width: 0;
+ margin: 0;
+ padding: 2px 0 0 2px;
+ resize: none;
+ outline: none;
+ font-size: 11px;
+ overflow: auto;
+ border-top: 1px solid #B9B7AF;
+ _right: -1px;
+ _border-left: 1px solid #fff;
+}
+
+#fbLargeCommandButtons {
+ display: none;
+ background: #ECE9D8;
+ bottom: 0;
+ right: 0;
+ width: 294px;
+ height: 21px;
+ padding-top: 1px;
+ position: fixed;
+ border-top: 1px solid #ACA899;
+ z-index: 9;
+}
+
+#fbSmallCommandLineIcon {
+ background: url(down.png) no-repeat;
+ position: absolute;
+ right: 2px;
+ bottom: 3px;
+
+ z-index: 99;
+}
+
+#fbSmallCommandLineIcon:hover {
+ background: url(downHover.png) no-repeat;
+}
+
+.hide {
+ overflow: hidden !important;
+ position: fixed !important;
+ display: none !important;
+ visibility: hidden !important;
+}
+
+/* fbBottom
+*************************************************************************************************/
+
+#fbCommand {
+ height: 18px;
+}
+
+#fbCommandBox {
+ position: fixed;
+ _position: absolute;
+ width: 100%;
+ height: 18px;
+ bottom: 0;
+ overflow: hidden;
+ z-index: 9;
+ background: #fff;
+ border: 0;
+ border-top: 1px solid #ccc;
+}
+
+#fbCommandIcon {
+ position: absolute;
+ color: #00f;
+ top: 2px;
+ left: 6px;
+ display: inline;
+ font: 11px Monaco, monospace;
+ z-index: 10;
+}
+
+#fbCommandLine {
+ position: absolute;
+ width: 100%;
+ top: 0;
+ left: 0;
+ border: 0;
+ margin: 0;
+ padding: 2px 0 2px 32px;
+ font: 11px Monaco, monospace;
+ z-index: 9;
+ outline: none;
+}
+
+#fbLargeCommandLineIcon {
+ background: url(up.png) no-repeat;
+ position: absolute;
+ right: 1px;
+ bottom: 1px;
+ z-index: 10;
+}
+
+#fbLargeCommandLineIcon:hover {
+ background: url(upHover.png) no-repeat;
+}
+
+div.fbFitHeight {
+ overflow: auto;
+ position: relative;
+}
+
+
+/************************************************************************************************
+ Layout Controls
+*************************************************************************************************/
+
+/* fbToolbar buttons
+*************************************************************************************************/
+.fbSmallButton {
+ overflow: hidden;
+ width: 16px;
+ height: 16px;
+ display: block;
+ text-decoration: none;
+ cursor: default;
+}
+
+#fbWindowButtons .fbSmallButton {
+ float: right;
+}
+
+#fbWindow_btClose {
+ background: url(min.png);
+}
+
+#fbWindow_btClose:hover {
+ background: url(minHover.png);
+}
+
+#fbWindow_btDetach {
+ background: url(detach.png);
+}
+
+#fbWindow_btDetach:hover {
+ background: url(detachHover.png);
+}
+
+#fbWindow_btDeactivate {
+ background: url(off.png);
+}
+
+#fbWindow_btDeactivate:hover {
+ background: url(offHover.png);
+}
+
+
+/* fbPanelBarBox tabs
+*************************************************************************************************/
+.fbTab {
+ text-decoration: none;
+ display: none;
+ float: left;
+ width: auto;
+ float: left;
+ cursor: default;
+ font-family: Lucida Grande, Tahoma, sans-serif;
+ font-size: 11px;
+ line-height: 13px;
+ font-weight: bold;
+ height: 22px;
+ color: #565656;
+}
+
+.fbPanelBar span {
+ /*display: block; TODO: safe to remove this? */
+ float: left;
+}
+
+.fbPanelBar .fbTabL,.fbPanelBar .fbTabR {
+ height: 22px;
+ width: 8px;
+}
+
+.fbPanelBar .fbTabText {
+ padding: 4px 1px 0;
+}
+
+a.fbTab:hover {
+ background: url(sprite.png) 0 -73px;
+}
+
+a.fbTab:hover .fbTabL {
+ background: url(sprite.png) -16px -96px;
+}
+
+a.fbTab:hover .fbTabR {
+ background: url(sprite.png) -24px -96px;
+}
+
+.fbSelectedTab {
+ background: url(sprite.png) #f1f2ee 0 -50px !important;
+ color: #000;
+}
+
+.fbSelectedTab .fbTabL {
+ background: url(sprite.png) 0 -96px !important;
+}
+
+.fbSelectedTab .fbTabR {
+ background: url(sprite.png) -8px -96px !important;
+}
+
+/* splitters
+*************************************************************************************************/
+#fbHSplitter {
+ position: fixed;
+ _position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 5px;
+ overflow: hidden;
+ cursor: n-resize !important;
+ background: url(pixel_transparent.gif);
+ z-index: 9;
+}
+
+#fbHSplitter.fbOnMovingHSplitter {
+ height: 100%;
+ z-index: 100;
+}
+
+.fbVSplitter {
+ background: #ece9d8;
+ color: #000;
+ border: 1px solid #716f64;
+ border-width: 0 1px;
+ border-left-color: #aca899;
+ width: 4px;
+ cursor: e-resize;
+ overflow: hidden;
+ right: 294px;
+ text-decoration: none;
+ z-index: 10;
+ position: absolute;
+ height: 100%;
+ top: 27px;
+}
+
+/************************************************************************************************/
+div.lineNo {
+ font: 1em/1.4545em Monaco, monospace;
+ position: relative;
+ float: left;
+ top: 0;
+ left: 0;
+ margin: 0 5px 0 0;
+ padding: 0 5px 0 10px;
+ background: #eee;
+ color: #888;
+ border-right: 1px solid #ccc;
+ text-align: right;
+}
+
+.sourceBox {
+ position: absolute;
+}
+
+.sourceCode {
+ font: 1em Monaco, monospace;
+ overflow: hidden;
+ white-space: pre;
+ display: inline;
+}
+
+/************************************************************************************************/
+.nodeControl {
+ margin-top: 3px;
+ margin-left: -14px;
+ float: left;
+ width: 9px;
+ height: 9px;
+ overflow: hidden;
+ cursor: default;
+ background: url(tree_open.gif);
+ _float: none;
+ _display: inline;
+ _position: absolute;
+}
+
+div.nodeMaximized {
+ background: url(tree_close.gif);
+}
+
+div.objectBox-element {
+ padding: 1px 3px;
+}
+.objectBox-selector{
+ cursor: default;
+}
+
+.selectedElement{
+ background: highlight;
+ /* background: url(roundCorner.svg); Opera */
+ color: #fff !important;
+}
+.selectedElement span{
+ color: #fff !important;
+}
+
+/* IE6 need this hack */
+* html .selectedElement {
+ position: relative;
+}
+
+/* Webkit CSS Hack - bug in "highlight" named color */
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ .selectedElement{
+ background: #316AC5;
+ color: #fff !important;
+ }
+}
+
+/************************************************************************************************/
+/************************************************************************************************/
+.logRow * {
+ font-size: 1em;
+}
+
+/* TODO: remove this? */
+/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to
+position. if so, override it at chrome.js initialization when creating the div */
+.logRow {
+ position: relative;
+ border-bottom: 1px solid #D7D7D7;
+ padding: 2px 4px 1px 6px;
+ zbackground-color: #FFFFFF;
+}
+/**/
+
+.logRow-command {
+ font-family: Monaco, monospace;
+ color: blue;
+}
+
+.objectBox-string,
+.objectBox-text,
+.objectBox-number,
+.objectBox-function,
+.objectLink-element,
+.objectLink-textNode,
+.objectLink-function,
+.objectBox-stackTrace,
+.objectLink-profile {
+ font-family: Monaco, monospace;
+}
+
+.objectBox-null {
+ padding: 0 2px;
+ border: 1px solid #666666;
+ background-color: #888888;
+ color: #FFFFFF;
+}
+
+.objectBox-string {
+ color: red;
+
+ /* TODO: xxxpedro make long strings break line */
+ /*white-space: pre; */
+}
+
+.objectBox-number {
+ color: #000088;
+}
+
+.objectBox-function {
+ color: DarkGreen;
+}
+
+.objectBox-object {
+ color: DarkGreen;
+ font-weight: bold;
+ font-family: Lucida Grande, sans-serif;
+}
+
+.objectBox-array {
+ color: #000;
+}
+
+/************************************************************************************************/
+.logRow-info,.logRow-error,.logRow-warn {
+ background: #fff no-repeat 2px 2px;
+ padding-left: 20px;
+ padding-bottom: 3px;
+}
+
+.logRow-info {
+ background-image: url(infoIcon.png) !important;
+ background-image: url(infoIcon.gif);
+}
+
+.logRow-warn {
+ background-color: cyan;
+ background-image: url(warningIcon.png) !important;
+ background-image: url(warningIcon.gif);
+}
+
+.logRow-error {
+ background-color: LightYellow;
+ background-image: url(errorIcon.png) !important;
+ background-image: url(errorIcon.gif);
+ color: #f00;
+}
+
+.errorMessage {
+ vertical-align: top;
+ color: #f00;
+}
+
+.objectBox-sourceLink {
+ position: absolute;
+ right: 4px;
+ top: 2px;
+ padding-left: 8px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ color: #0000FF;
+}
+
+/************************************************************************************************/
+/*
+//TODO: remove this when console2 is finished
+*/
+/*
+.logRow-group {
+ background: #EEEEEE;
+ border-bottom: none;
+}
+
+.logGroup {
+ background: #EEEEEE;
+}
+
+.logGroupBox {
+ margin-left: 24px;
+ border-top: 1px solid #D7D7D7;
+ border-left: 1px solid #D7D7D7;
+}/**/
+
+/************************************************************************************************/
+.selectorTag,.selectorId,.selectorClass {
+ font-family: Monaco, monospace;
+ font-weight: normal;
+}
+
+.selectorTag {
+ color: #0000FF;
+}
+
+.selectorId {
+ color: DarkBlue;
+}
+
+.selectorClass {
+ color: red;
+}
+
+/************************************************************************************************/
+.objectBox-element {
+ font-family: Monaco, monospace;
+ color: #000088;
+}
+
+.nodeChildren {
+ padding-left: 26px;
+}
+
+.nodeTag {
+ color: blue;
+ cursor: pointer;
+}
+
+.nodeValue {
+ color: #FF0000;
+ font-weight: normal;
+}
+
+.nodeText,.nodeComment {
+ margin: 0 2px;
+ vertical-align: top;
+}
+
+.nodeText {
+ color: #333333;
+ font-family: Monaco, monospace;
+}
+
+.nodeComment {
+ color: DarkGreen;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeHidden, .nodeHidden * {
+ color: #888888;
+}
+
+.nodeHidden .nodeTag {
+ color: #5F82D9;
+}
+
+.nodeHidden .nodeValue {
+ color: #D86060;
+}
+
+.selectedElement .nodeHidden, .selectedElement .nodeHidden * {
+ color: SkyBlue !important;
+}
+
+
+/************************************************************************************************/
+.log-object {
+ /*
+ _position: relative;
+ _height: 100%;
+ /**/
+}
+
+.property {
+ position: relative;
+ clear: both;
+ height: 15px;
+}
+
+.propertyNameCell {
+ vertical-align: top;
+ float: left;
+ width: 28%;
+ position: absolute;
+ left: 0;
+ z-index: 0;
+}
+
+.propertyValueCell {
+ float: right;
+ width: 68%;
+ background: #fff;
+ position: absolute;
+ padding-left: 5px;
+ display: table-cell;
+ right: 0;
+ z-index: 1;
+ /*
+ _position: relative;
+ /**/
+}
+
+.propertyName {
+ font-weight: bold;
+}
+
+.FirebugPopup {
+ height: 100% !important;
+}
+
+.FirebugPopup #fbWindowButtons {
+ display: none !important;
+}
+
+.FirebugPopup #fbHSplitter {
+ display: none !important;
+}
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.html b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.html
new file mode 100644
index 00000000..aa078099
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.html
@@ -0,0 +1,215 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/DTD/strict.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>Firebug Lite</title>
+<!-- An empty script to avoid FOUC when loading the stylesheet -->
+<script type="text/javascript"></script>
+<style type="text/css" media="screen">@import "firebug.css";</style>
+<style>html,body{margin:0;padding:0;overflow:hidden;}</style>
+</head>
+<body class="fbBody">
+<table id="fbChrome" cellpadding="0" cellspacing="0" border="0">
+ <tbody>
+ <tr>
+ <!-- Interface - Top Area -->
+ <td id="fbTop" colspan="2">
+
+ <!--
+ <div>
+ --><!-- <span id="fbToolbarErrors" class="fbErrors">2 errors</span> --><!--
+ <input type="text" id="fbToolbarSearch" />
+ </div>
+ -->
+
+ <!-- Window Buttons -->
+ <div id="fbWindowButtons">
+ <a id="fbWindow_btDeactivate" class="fbSmallButton fbHover" title="Deactivate Firebug for this web page">&nbsp;</a>
+ <a id="fbWindow_btDetach" class="fbSmallButton fbHover" title="Open Firebug in popup window">&nbsp;</a>
+ <a id="fbWindow_btClose" class="fbSmallButton fbHover" title="Minimize Firebug">&nbsp;</a>
+ </div>
+
+ <!-- Toolbar buttons and Status Bar -->
+ <div id="fbToolbar">
+ <div id="fbToolbarContent">
+
+ <!-- Firebug Button -->
+ <span id="fbToolbarIcon">
+ <a id="fbFirebugButton" class="fbIconButton" class="fbHover" target="_blank">&nbsp;</a>
+ </span>
+
+ <!--
+ <span id="fbLeftToolbarErrors" class="fbErrors">2 errors</span>
+ -->
+
+ <!-- Toolbar Buttons -->
+ <span id="fbToolbarButtons">
+ <!-- Fixed Toolbar Buttons -->
+ <span id="fbFixedButtons">
+ <a id="fbChrome_btInspect" class="fbButton fbHover" title="Click an element in the page to inspect">Inspect</a>
+ </span>
+
+ <!-- Console Panel Toolbar Buttons -->
+ <span id="fbConsoleButtons" class="fbToolbarButtons">
+ <a id="fbConsole_btClear" class="fbButton fbHover" title="Clear the console">Clear</a>
+ </span>
+
+ <!-- HTML Panel Toolbar Buttons -->
+ <!--
+ <span id="fbHTMLButtons" class="fbToolbarButtons">
+ <a id="fbHTML_btEdit" class="fbHover" title="Edit this HTML">Edit</a>
+ </span>
+ -->
+ </span>
+
+ <!-- Status Bar -->
+ <span id="fbStatusBarBox">
+ <span class="fbToolbarSeparator"></span>
+ <!-- HTML Panel Status Bar -->
+ <!--
+ <span id="fbHTMLStatusBar" class="fbStatusBar fbToolbarButtons">
+ </span>
+ -->
+ </span>
+
+ </div>
+
+ </div>
+
+ <!-- PanelBars -->
+ <div id="fbPanelBarBox">
+
+ <!-- Main PanelBar -->
+ <div id="fbPanelBar1" class="fbPanelBar">
+ <a id="fbConsoleTab" class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">Console</span>
+ <span class="fbTabMenuTarget"></span>
+ <span class="fbTabR"></span>
+ </a>
+ <a id="fbHTMLTab" class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">HTML</span>
+ <span class="fbTabR"></span>
+ </a>
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">CSS</span>
+ <span class="fbTabR"></span>
+ </a>
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">Script</span>
+ <span class="fbTabR"></span>
+ </a>
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">DOM</span>
+ <span class="fbTabR"></span>
+ </a>
+ </div>
+
+ <!-- Side PanelBars -->
+ <div id="fbPanelBar2Box" class="hide">
+ <div id="fbPanelBar2" class="fbPanelBar">
+ <!--
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">Style</span>
+ <span class="fbTabR"></span>
+ </a>
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">Layout</span>
+ <span class="fbTabR"></span>
+ </a>
+ <a class="fbTab fbHover">
+ <span class="fbTabL"></span>
+ <span class="fbTabText">DOM</span>
+ <span class="fbTabR"></span>
+ </a>
+ -->
+ </div>
+ </div>
+
+ </div>
+
+ <!-- Horizontal Splitter -->
+ <div id="fbHSplitter">&nbsp;</div>
+
+ </td>
+ </tr>
+
+ <!-- Interface - Main Area -->
+ <tr id="fbContent">
+
+ <!-- Panels -->
+ <td id="fbPanelBox1">
+ <div id="fbPanel1" class="fbFitHeight">
+ <div id="fbConsole" class="fbPanel"></div>
+ <div id="fbHTML" class="fbPanel"></div>
+ </div>
+ </td>
+
+ <!-- Side Panel Box -->
+ <td id="fbPanelBox2" class="hide">
+
+ <!-- VerticalSplitter -->
+ <div id="fbVSplitter" class="fbVSplitter">&nbsp;</div>
+
+ <!-- Side Panels -->
+ <div id="fbPanel2" class="fbFitHeight">
+
+ <!-- HTML Side Panels -->
+ <div id="fbHTML_Style" class="fbPanel"></div>
+ <div id="fbHTML_Layout" class="fbPanel"></div>
+ <div id="fbHTML_DOM" class="fbPanel"></div>
+
+ </div>
+
+ <!-- Large Command Line -->
+ <textarea id="fbLargeCommandLine" class="fbFitHeight"></textarea>
+
+ <!-- Large Command Line Buttons -->
+ <div id="fbLargeCommandButtons">
+ <a id="fbCommand_btRun" class="fbButton fbHover">Run</a>
+ <a id="fbCommand_btClear" class="fbButton fbHover">Clear</a>
+
+ <a id="fbSmallCommandLineIcon" class="fbSmallButton fbHover"></a>
+ </div>
+
+ </td>
+
+ </tr>
+
+ <!-- Interface - Bottom Area -->
+ <tr id="fbBottom" class="hide">
+
+ <!-- Command Line -->
+ <td id="fbCommand" colspan="2">
+ <div id="fbCommandBox">
+ <div id="fbCommandIcon">&gt;&gt;&gt;</div>
+ <input id="fbCommandLine" name="fbCommandLine" type="text" />
+ <a id="fbLargeCommandLineIcon" class="fbSmallButton fbHover"></a>
+ </div>
+ </td>
+
+ </tr>
+
+ </tbody>
+</table>
+<span id="fbMiniChrome">
+ <span id="fbMiniContent">
+ <span id="fbMiniIcon" title="Open Firebug Lite"></span>
+ <span id="fbMiniErrors" class="fbErrors"><!-- 2 errors --></span>
+ </span>
+</span>
+<!--
+<div id="fbErrorPopup">
+ <div id="fbErrorPopupContent">
+ <div id="fbErrorIndicator" class="fbErrors">2 errors</div>
+ </div>
+</div>
+ -->
+</body>
+</html> \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.png
new file mode 100644
index 00000000..e10affeb
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/firebug.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/group.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/group.gif
new file mode 100644
index 00000000..8db97c21
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/group.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/html.css b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/html.css
new file mode 100644
index 00000000..5b7c5f4b
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/html.css
@@ -0,0 +1,272 @@
+/* See license.txt for terms of usage */
+
+.panelNode-html {
+ -moz-box-sizing: padding-box;
+ padding: 4px 0 0 2px;
+}
+
+.nodeBox {
+ position: relative;
+ font-family: Monaco, monospace;
+ padding-left: 13px;
+ -moz-user-select: -moz-none;
+}
+.nodeBox.search-selection {
+ -moz-user-select: text;
+}
+.twisty {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 14px;
+ height: 14px;
+}
+
+.nodeChildBox {
+ margin-left: 12px;
+ display: none;
+}
+
+.nodeLabel,
+.nodeCloseLabel {
+ margin: -2px 2px 0 2px;
+ border: 2px solid transparent;
+ -moz-border-radius: 3px;
+ padding: 0 2px;
+ color: #000088;
+}
+
+.nodeCloseLabel {
+ display: none;
+}
+
+.nodeTag {
+ cursor: pointer;
+ color: blue;
+}
+
+.nodeValue {
+ color: #FF0000;
+ font-weight: normal;
+}
+
+.nodeText,
+.nodeComment {
+ margin: 0 2px;
+ vertical-align: top;
+}
+
+.nodeText {
+ color: #333333;
+}
+
+.nodeWhiteSpace {
+ border: 1px solid LightGray;
+ white-space: pre; /* otherwise the border will be collapsed around zero pixels */
+ margin-left: 1px;
+ color: gray;
+}
+
+
+.nodeWhiteSpace_Space {
+ border: 1px solid #ddd;
+}
+
+.nodeTextEntity {
+ border: 1px solid gray;
+ white-space: pre; /* otherwise the border will be collapsed around zero pixels */
+ margin-left: 1px;
+}
+
+.nodeComment {
+ color: DarkGreen;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeBox.highlightOpen > .nodeLabel {
+ background-color: #EEEEEE;
+}
+
+.nodeBox.highlightOpen > .nodeCloseLabel,
+.nodeBox.highlightOpen > .nodeChildBox,
+.nodeBox.open > .nodeCloseLabel,
+.nodeBox.open > .nodeChildBox {
+ display: block;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeBox.selected > .nodeLabel > .nodeLabelBox,
+.nodeBox.selected > .nodeLabel {
+ border-color: Highlight;
+ background-color: Highlight;
+ color: HighlightText !important;
+}
+
+.nodeBox.selected > .nodeLabel > .nodeLabelBox,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText {
+ color: inherit !important;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeBox.highlighted > .nodeLabel {
+ border-color: Highlight !important;
+ background-color: cyan !important;
+ color: #000000 !important;
+}
+
+.nodeBox.highlighted > .nodeLabel > .nodeLabelBox,
+.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag,
+.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
+.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText {
+ color: #000000 !important;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox,
+.nodeBox.nodeHidden .nodeCloseLabel,
+.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText,
+.nodeBox.nodeHidden .nodeText {
+ color: #888888;
+}
+
+.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag,
+.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag {
+ color: #5F82D9;
+}
+
+.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue {
+ color: #D86060;
+}
+
+.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox,
+.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
+.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
+.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText {
+ color: SkyBlue !important;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+.nodeBox.mutated > .nodeLabel,
+.nodeAttr.mutated,
+.nodeValue.mutated,
+.nodeText.mutated,
+.nodeBox.mutated > .nodeText {
+ background-color: #EFFF79;
+ color: #FF0000 !important;
+}
+
+.nodeBox.selected.mutated > .nodeLabel,
+.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated,
+.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated {
+ background-color: #EFFF79;
+ border-color: #EFFF79;
+ color: #FF0000 !important;
+}
+
+/************************************************************************************************/
+
+.logRow-dirxml {
+ padding-left: 0;
+}
+
+.soloElement > .nodeBox {
+ padding-left: 0;
+}
+
+.useA11y .nodeLabel.focused {
+ outline: 2px solid #FF9933;
+ -moz-outline-radius: 3px;
+ outline-offset: -2px;
+}
+
+.useA11y .nodeLabelBox:focus {
+ outline: none;
+}
+
+/************************************************************************************************/
+
+.breakpointCode .twisty {
+ display: none;
+}
+
+.breakpointCode .nodeBox.containerNodeBox,
+.breakpointCode .nodeLabel {
+ padding-left: 0px;
+ margin-left: 0px;
+ font-family: Monaco, monospace !important;
+}
+
+.breakpointCode .nodeTag,
+.breakpointCode .nodeAttr,
+.breakpointCode .nodeText,
+.breakpointCode .nodeValue,
+.breakpointCode .nodeLabel {
+ color: DarkGreen !important;
+}
+
+.breakpointMutationType {
+ position: absolute;
+ top: 4px;
+ right: 20px;
+ color: gray;
+}
+
+
+
+
+
+
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+/************************************************************************************************/
+
+
+
+/************************************************************************************************/
+/* Twisties */
+
+.twisty,
+.logRow-errorMessage > .hasTwisty > .errorTitle,
+.logRow-log > .objectBox-array.hasTwisty,
+.logRow-spy .spyHead .spyTitle,
+.logGroup > .logRow,
+.memberRow.hasChildren > .memberLabelCell > .memberLabel,
+.hasHeaders .netHrefLabel,
+.netPageRow > .netCol > .netPageTitle {
+ background-image: url(twistyClosed.png);
+ background-repeat: no-repeat;
+ background-position: 2px 2px;
+ min-height: 12px;
+}
+
+.logRow-errorMessage > .hasTwisty.opened > .errorTitle,
+.logRow-log > .objectBox-array.hasTwisty.opened,
+.logRow-spy.opened .spyHead .spyTitle,
+.logGroup.opened > .logRow,
+.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
+.nodeBox.highlightOpen > .nodeLabel > .twisty,
+.nodeBox.open > .nodeLabel > .twisty,
+.netRow.opened > .netCol > .netHrefLabel,
+.netPageRow.opened > .netCol > .netPageTitle {
+ background-image: url(twistyOpen.png);
+}
+
+.twisty {
+ background-position: 4px 4px;
+} \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif
new file mode 100644
index 00000000..0618e208
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.png
new file mode 100644
index 00000000..da1e5334
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/infoIcon.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/loading_16.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/loading_16.gif
new file mode 100644
index 00000000..085ccaec
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/loading_16.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/min.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/min.png
new file mode 100644
index 00000000..1034d66f
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/min.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/minHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/minHover.png
new file mode 100644
index 00000000..b0d1e1af
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/minHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/off.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/off.png
new file mode 100644
index 00000000..b70b1d24
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/off.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/offHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/offHover.png
new file mode 100644
index 00000000..f3670f19
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/offHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif
new file mode 100644
index 00000000..6865c960
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg
new file mode 100644
index 00000000..2dfa7280
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg">
+ <rect fill="white" x="0" y="0" width="100%" height="100%" />
+ <rect fill="highlight" x="0" y="0" width="100%" height="100%" rx="2px"/>
+</svg>
+
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.gif
new file mode 100644
index 00000000..2a620987
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.png
new file mode 100644
index 00000000..fba33b8a
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/search.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow.gif
new file mode 100644
index 00000000..af7f537e
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow2.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow2.gif
new file mode 100644
index 00000000..099cbf35
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadow2.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png
new file mode 100644
index 00000000..a2561df9
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/sprite.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/sprite.png
new file mode 100644
index 00000000..33d2c4d4
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/sprite.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png
new file mode 100644
index 00000000..0fb24d0c
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png
new file mode 100644
index 00000000..fbccab54
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png
new file mode 100644
index 00000000..3db0f361
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabLeft.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabLeft.png
new file mode 100644
index 00000000..a6cc9e94
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabLeft.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png
new file mode 100644
index 00000000..4726e622
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png
new file mode 100644
index 00000000..eb4b11ef
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png
new file mode 100644
index 00000000..55b982d7
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png
new file mode 100644
index 00000000..957bd9f2
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png
new file mode 100644
index 00000000..200a3708
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMid.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMid.png
new file mode 100644
index 00000000..68986c3b
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabMid.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabRight.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabRight.png
new file mode 100644
index 00000000..50113079
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tabRight.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif
new file mode 100644
index 00000000..0ee54978
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png
new file mode 100644
index 00000000..21682c3d
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif
new file mode 100644
index 00000000..04f84215
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png
new file mode 100644
index 00000000..a0f839dc
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png
new file mode 100644
index 00000000..10998ae7
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png
new file mode 100644
index 00000000..aa21dee6
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_close.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_close.gif
new file mode 100644
index 00000000..e26728ab
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_close.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_open.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_open.gif
new file mode 100644
index 00000000..edf662f3
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/tree_open.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png
new file mode 100644
index 00000000..f80319b0
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png
new file mode 100644
index 00000000..86801243
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/up.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/up.png
new file mode 100644
index 00000000..2174d03a
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/up.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upActive.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upActive.png
new file mode 100644
index 00000000..236cf676
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upActive.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upHover.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upHover.png
new file mode 100644
index 00000000..cd813170
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/upHover.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif
new file mode 100644
index 00000000..84972788
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.png b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.png
new file mode 100644
index 00000000..de51084e
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/skin/xp/warningIcon.png
Binary files differ
diff --git a/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/src/firebug-lite-debug.js b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/src/firebug-lite-debug.js
new file mode 100644
index 00000000..40b1ae70
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/lodash/vendor/firebug-lite/src/firebug-lite-debug.js
@@ -0,0 +1,31176 @@
+(function(){
+
+/*!*************************************************************
+ *
+ * Firebug Lite 1.4.0
+ *
+ * Copyright (c) 2007, Parakey Inc.
+ * Released under BSD license.
+ * More information: http://getfirebug.com/firebuglite
+ *
+ **************************************************************/
+
+/*!
+ * CSS selectors powered by:
+ *
+ * Sizzle CSS Selector Engine - v1.0
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+
+/** @namespace describe lib */
+
+// FIXME: xxxpedro if we use "var FBL = {}" the FBL won't appear in the DOM Panel in IE
+var FBL = {};
+
+( /** @scope s_lib @this FBL */ function() {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Constants
+
+var productionDir = "http://getfirebug.com/releases/lite/";
+var bookmarkletVersion = 4;
+
+// ************************************************************************************************
+
+var reNotWhitespace = /[^\s]/;
+var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/;
+
+// Globals
+this.reJavascript = /\s*javascript:\s*(.*)/;
+this.reChrome = /chrome:\/\/([^\/]*)\//;
+this.reFile = /file:\/\/([^\/]*)\//;
+
+
+// ************************************************************************************************
+// properties
+
+var userAgent = navigator.userAgent.toLowerCase();
+this.isFirefox = /firefox/.test(userAgent);
+this.isOpera = /opera/.test(userAgent);
+this.isSafari = /webkit/.test(userAgent);
+this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent);
+this.isIE6 = /msie 6/i.test(navigator.appVersion);
+this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1];
+this.isIElt8 = this.isIE && (this.browserVersion-0 < 8);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.NS = null;
+this.pixelsPerInch = null;
+
+
+// ************************************************************************************************
+// Namespaces
+
+var namespaces = [];
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.ns = function(fn)
+{
+ var ns = {};
+ namespaces.push(fn, ns);
+ return ns;
+};
+
+var FBTrace = null;
+
+this.initialize = function()
+{
+ // Firebug Lite is already running in persistent mode so we just quit
+ if (window.firebug && firebug.firebuglite || window.console && console.firebuglite)
+ return;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // initialize environment
+
+ // point the FBTrace object to the local variable
+ if (FBL.FBTrace)
+ FBTrace = FBL.FBTrace;
+ else
+ FBTrace = FBL.FBTrace = {};
+
+ // check if the actual window is a persisted chrome context
+ var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object";
+
+ // chrome context of the persistent application
+ if (isChromeContext)
+ {
+ // TODO: xxxpedro persist - make a better synchronization
+ sharedEnv = window.Firebug.SharedEnv;
+ delete window.Firebug.SharedEnv;
+
+ FBL.Env = sharedEnv;
+ FBL.Env.isChromeContext = true;
+ FBTrace.messageQueue = FBL.Env.traceMessageQueue;
+ }
+ // non-persistent application
+ else
+ {
+ FBL.NS = document.documentElement.namespaceURI;
+ FBL.Env.browser = window;
+ FBL.Env.destroy = destroyEnvironment;
+
+ if (document.documentElement.getAttribute("debug") == "true")
+ FBL.Env.Options.startOpened = true;
+
+ // find the URL location of the loaded application
+ findLocation();
+
+ // TODO: get preferences here...
+ // The problem is that we don't have the Firebug object yet, so we can't use
+ // Firebug.loadPrefs. We're using the Store module directly instead.
+ var prefs = FBL.Store.get("FirebugLite") || {};
+ FBL.Env.DefaultOptions = FBL.Env.Options;
+ FBL.Env.Options = FBL.extend(FBL.Env.Options, prefs.options || {});
+
+ if (FBL.isFirefox &&
+ typeof FBL.Env.browser.console == "object" &&
+ FBL.Env.browser.console.firebug &&
+ FBL.Env.Options.disableWhenFirebugActive)
+ return;
+ }
+
+ // exposes the FBL to the global namespace when in debug mode
+ if (FBL.Env.isDebugMode)
+ {
+ FBL.Env.browser.FBL = FBL;
+ }
+
+ // check browser compatibilities
+ this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat";
+ this.isIEQuiksMode = this.isIE && this.isQuiksMode;
+ this.isIEStantandMode = this.isIE && !this.isQuiksMode;
+
+ this.noFixedPosition = this.isIE6 || this.isIEQuiksMode;
+
+ // after creating/synchronizing the environment, initialize the FBTrace module
+ if (FBL.Env.Options.enableTrace) FBTrace.initialize();
+
+ if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context");
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // initialize namespaces
+
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN");
+
+ for (var i = 0; i < namespaces.length; i += 2)
+ {
+ var fn = namespaces[i];
+ var ns = namespaces[i+1];
+ fn.apply(ns);
+ }
+
+ if (FBTrace.DBG_INITIALIZE) {
+ FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END");
+ FBTrace.sysout("FBL waitForDocument", "waiting document load");
+ }
+
+ FBL.Ajax.initialize();
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // finish environment initialization
+ FBL.Firebug.loadPrefs();
+
+ if (FBL.Env.Options.enablePersistent)
+ {
+ // TODO: xxxpedro persist - make a better synchronization
+ if (isChromeContext)
+ {
+ FBL.FirebugChrome.clone(FBL.Env.FirebugChrome);
+ }
+ else
+ {
+ FBL.Env.FirebugChrome = FBL.FirebugChrome;
+ FBL.Env.traceMessageQueue = FBTrace.messageQueue;
+ }
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // wait document load
+
+ waitForDocument();
+};
+
+var waitForDocument = function waitForDocument()
+{
+ // document.body not available in XML+XSL documents in Firefox
+ var doc = FBL.Env.browser.document;
+ var body = doc.getElementsByTagName("body")[0];
+
+ if (body)
+ {
+ calculatePixelsPerInch(doc, body);
+ onDocumentLoad();
+ }
+ else
+ setTimeout(waitForDocument, 50);
+};
+
+var onDocumentLoad = function onDocumentLoad()
+{
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded");
+
+ // fix IE6 problem with cache of background images, causing a lot of flickering
+ if (FBL.isIE6)
+ fixIE6BackgroundImageCache();
+
+ // chrome context of the persistent application
+ if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext)
+ {
+ // finally, start the application in the chrome context
+ FBL.Firebug.initialize();
+
+ // if is not development mode, remove the shared environment cache object
+ // used to synchronize the both persistent contexts
+ if (!FBL.Env.isDevelopmentMode)
+ {
+ sharedEnv.destroy();
+ sharedEnv = null;
+ }
+ }
+ // non-persistent application
+ else
+ {
+ FBL.FirebugChrome.create();
+ }
+};
+
+// ************************************************************************************************
+// Env
+
+var sharedEnv;
+
+this.Env =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Env Options (will be transported to Firebug options)
+ Options:
+ {
+ saveCookies: true,
+
+ saveWindowPosition: false,
+ saveCommandLineHistory: false,
+
+ startOpened: false,
+ startInNewWindow: false,
+ showIconWhenHidden: true,
+
+ overrideConsole: true,
+ ignoreFirebugElements: true,
+ disableWhenFirebugActive: true,
+
+ disableXHRListener: false,
+ disableResourceFetching: false,
+
+ enableTrace: false,
+ enablePersistent: false
+
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Library location
+ Location:
+ {
+ sourceDir: null,
+ baseDir: null,
+ skinDir: null,
+ skin: null,
+ app: null
+ },
+
+ skin: "xp",
+ useLocalSkin: false,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Env states
+ isDevelopmentMode: false,
+ isDebugMode: false,
+ isChromeContext: false,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Env references
+ browser: null,
+ chrome: null
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var destroyEnvironment = function destroyEnvironment()
+{
+ setTimeout(function()
+ {
+ FBL = null;
+ }, 100);
+};
+
+// ************************************************************************************************
+// Library location
+
+var findLocation = function findLocation()
+{
+ var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/;
+ var reGetFirebugSite = /(?:http|https):\/\/getfirebug.com\//;
+ var isGetFirebugSite;
+
+ var rePath = /^(.*\/)/;
+ var reProtocol = /^\w+:\/\//;
+ var path = null;
+ var doc = document;
+
+ // Firebug Lite 1.3.0 bookmarklet identification
+ var script = doc.getElementById("FirebugLite");
+
+ var scriptSrc;
+ var hasSrcAttribute = true;
+
+ // If the script was loaded via bookmarklet, we already have the script tag
+ if (script)
+ {
+ scriptSrc = script.src;
+ file = reFirebugFile.exec(scriptSrc);
+
+ var version = script.getAttribute("FirebugLite");
+ var number = version ? parseInt(version) : 0;
+
+ if (!version || !number || number < bookmarkletVersion)
+ {
+ FBL.Env.bookmarkletOutdated = true;
+ }
+ }
+ // otherwise we must search for the correct script tag
+ else
+ {
+ for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++)
+ {
+ var file = null;
+ if ( si.nodeName.toLowerCase() == "script" )
+ {
+ if (file = reFirebugFile.exec(si.getAttribute("firebugSrc")))
+ {
+ scriptSrc = si.getAttribute("firebugSrc");
+ hasSrcAttribute = false;
+ }
+ else if (file = reFirebugFile.exec(si.src))
+ {
+ scriptSrc = si.src;
+ }
+ else
+ continue;
+
+ script = si;
+ break;
+ }
+ }
+ }
+
+ // mark the script tag to be ignored by Firebug Lite
+ if (script)
+ script.firebugIgnore = true;
+
+ if (file)
+ {
+ var fileName = file[1];
+ var fileOptions = file[2];
+
+ // absolute path
+ if (reProtocol.test(scriptSrc)) {
+ path = rePath.exec(scriptSrc)[1];
+
+ }
+ // relative path
+ else
+ {
+ var r = rePath.exec(scriptSrc);
+ var src = r ? r[1] : scriptSrc;
+ var backDir = /^((?:\.\.\/)+)(.*)/.exec(src);
+ var reLastDir = /^(.*\/)[^\/]+\/$/;
+ path = rePath.exec(location.href)[1];
+
+ // "../some/path"
+ if (backDir)
+ {
+ var j = backDir[1].length/3;
+ var p;
+ while (j-- > 0)
+ path = reLastDir.exec(path)[1];
+
+ path += backDir[2];
+ }
+
+ else if(src.indexOf("/") != -1)
+ {
+ // "./some/path"
+ if(/^\.\/./.test(src))
+ {
+ path += src.substring(2);
+ }
+ // "/some/path"
+ else if(/^\/./.test(src))
+ {
+ var domain = /^(\w+:\/\/[^\/]+)/.exec(path);
+ path = domain[1] + src;
+ }
+ // "some/path"
+ else
+ {
+ path += src;
+ }
+ }
+ }
+ }
+
+ FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome";
+ if (FBL.Env.isChromeExtension)
+ {
+ path = productionDir;
+ FBL.Env.bookmarkletOutdated = false;
+ script = {innerHTML: "{showIconWhenHidden:false}"};
+ }
+
+ isGetFirebugSite = reGetFirebugSite.test(path);
+
+ if (isGetFirebugSite && path.indexOf("/releases/lite/") == -1)
+ {
+ // See Issue 4587 - If we are loading the script from getfirebug.com shortcut, like
+ // https://getfirebug.com/firebug-lite.js, then we must manually add the full path,
+ // otherwise the Env.Location will hold the wrong path, which will in turn lead to
+ // undesirable effects like the problem in Issue 4587
+ path += "releases/lite/" + (fileName == "firebug-lite-beta.js" ? "beta/" : "latest/");
+ }
+
+ var m = path && path.match(/([^\/]+)\/$/) || null;
+
+ if (path && m)
+ {
+ var Env = FBL.Env;
+
+ // Always use the local skin when running in the same domain
+ // See Issue 3554: Firebug Lite should use local images when loaded locally
+ Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0 &&
+ // but we cannot use the locan skin when loaded from getfirebug.com, otherwise
+ // the bookmarklet won't work when visiting getfirebug.com
+ !isGetFirebugSite;
+
+ // detecting development and debug modes via file name
+ if (fileName == "firebug-lite-dev.js")
+ {
+ Env.isDevelopmentMode = true;
+ Env.isDebugMode = true;
+ }
+ else if (fileName == "firebug-lite-debug.js")
+ {
+ Env.isDebugMode = true;
+ }
+
+ // process the <html debug="true">
+ if (Env.browser.document.documentElement.getAttribute("debug") == "true")
+ {
+ Env.Options.startOpened = true;
+ }
+
+ // process the Script URL Options
+ if (fileOptions)
+ {
+ var options = fileOptions.split(",");
+
+ for (var i = 0, length = options.length; i < length; i++)
+ {
+ var option = options[i];
+ var name, value;
+
+ if (option.indexOf("=") != -1)
+ {
+ var parts = option.split("=");
+ name = parts[0];
+ value = eval(unescape(parts[1]));
+ }
+ else
+ {
+ name = option;
+ value = true;
+ }
+
+ if (name == "debug")
+ {
+ Env.isDebugMode = !!value;
+ }
+ else if (name in Env.Options)
+ {
+ Env.Options[name] = value;
+ }
+ else
+ {
+ Env[name] = value;
+ }
+ }
+ }
+
+ // process the Script JSON Options
+ if (hasSrcAttribute)
+ {
+ var innerOptions = FBL.trim(script.innerHTML);
+ if (innerOptions)
+ {
+ var innerOptionsObject = eval("(" + innerOptions + ")");
+
+ for (var name in innerOptionsObject)
+ {
+ var value = innerOptionsObject[name];
+
+ if (name == "debug")
+ {
+ Env.isDebugMode = !!value;
+ }
+ else if (name in Env.Options)
+ {
+ Env.Options[name] = value;
+ }
+ else
+ {
+ Env[name] = value;
+ }
+ }
+ }
+ }
+
+ if (!Env.Options.saveCookies)
+ FBL.Store.remove("FirebugLite");
+
+ // process the Debug Mode
+ if (Env.isDebugMode)
+ {
+ Env.Options.startOpened = true;
+ Env.Options.enableTrace = true;
+ Env.Options.disableWhenFirebugActive = false;
+ }
+
+ var loc = Env.Location;
+ var isProductionRelease = path.indexOf(productionDir) != -1;
+
+ loc.sourceDir = path;
+ loc.baseDir = path.substr(0, path.length - m[1].length - 1);
+ loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/";
+ loc.skin = loc.skinDir + "firebug.html";
+ loc.app = path + fileName;
+ }
+ else
+ {
+ throw new Error("Firebug Error: Library path not found");
+ }
+};
+
+// ************************************************************************************************
+// Basics
+
+this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments);
+{
+ var args = cloneArray(arguments), fn = args.shift(), object = args.shift();
+ return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); };
+};
+
+this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args);
+{
+ var args = cloneArray(arguments), fn = args.shift(), object = args.shift();
+ return function() { return fn.apply(object, args); };
+};
+
+this.extend = function(l, r)
+{
+ var newOb = {};
+ for (var n in l)
+ newOb[n] = l[n];
+ for (var n in r)
+ newOb[n] = r[n];
+ return newOb;
+};
+
+this.descend = function(prototypeParent, childProperties)
+{
+ function protoSetter() {};
+ protoSetter.prototype = prototypeParent;
+ var newOb = new protoSetter();
+ for (var n in childProperties)
+ newOb[n] = childProperties[n];
+ return newOb;
+};
+
+this.append = function(l, r)
+{
+ for (var n in r)
+ l[n] = r[n];
+
+ return l;
+};
+
+this.keys = function(map) // At least sometimes the keys will be on user-level window objects
+{
+ var keys = [];
+ try
+ {
+ for (var name in map) // enumeration is safe
+ keys.push(name); // name is string, safe
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions trying to iterate properties
+ }
+
+ return keys; // return is safe
+};
+
+this.values = function(map)
+{
+ var values = [];
+ try
+ {
+ for (var name in map)
+ {
+ try
+ {
+ values.push(map[name]);
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions trying to access properties
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("lib.values FAILED ", exc);
+ }
+
+ }
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions trying to iterate properties
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("lib.values FAILED ", exc);
+ }
+
+ return values;
+};
+
+this.remove = function(list, item)
+{
+ for (var i = 0; i < list.length; ++i)
+ {
+ if (list[i] == item)
+ {
+ list.splice(i, 1);
+ break;
+ }
+ }
+};
+
+this.sliceArray = function(array, index)
+{
+ var slice = [];
+ for (var i = index; i < array.length; ++i)
+ slice.push(array[i]);
+
+ return slice;
+};
+
+function cloneArray(array, fn)
+{
+ var newArray = [];
+
+ if (fn)
+ for (var i = 0; i < array.length; ++i)
+ newArray.push(fn(array[i]));
+ else
+ for (var i = 0; i < array.length; ++i)
+ newArray.push(array[i]);
+
+ return newArray;
+}
+
+function extendArray(array, array2)
+{
+ var newArray = [];
+ newArray.push.apply(newArray, array);
+ newArray.push.apply(newArray, array2);
+ return newArray;
+}
+
+this.extendArray = extendArray;
+this.cloneArray = cloneArray;
+
+function arrayInsert(array, index, other)
+{
+ for (var i = 0; i < other.length; ++i)
+ array.splice(i+index, 0, other[i]);
+
+ return array;
+}
+
+// ************************************************************************************************
+
+this.createStyleSheet = function(doc, url)
+{
+ //TODO: xxxpedro
+ //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
+ var style = this.createElement("link");
+ style.setAttribute("charset","utf-8");
+ style.firebugIgnore = true;
+ style.setAttribute("rel", "stylesheet");
+ style.setAttribute("type", "text/css");
+ style.setAttribute("href", url);
+
+ //TODO: xxxpedro
+ //style.innerHTML = this.getResource(url);
+ return style;
+};
+
+this.addStyleSheet = function(doc, style)
+{
+ var heads = doc.getElementsByTagName("head");
+ if (heads.length)
+ heads[0].appendChild(style);
+ else
+ doc.documentElement.appendChild(style);
+};
+
+this.appendStylesheet = function(doc, uri)
+{
+ // Make sure the stylesheet is not appended twice.
+ if (this.$(uri, doc))
+ return;
+
+ var styleSheet = this.createStyleSheet(doc, uri);
+ styleSheet.setAttribute("id", uri);
+ this.addStyleSheet(doc, styleSheet);
+};
+
+this.addScript = function(doc, id, src)
+{
+ var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script");
+ element.setAttribute("type", "text/javascript");
+ element.setAttribute("id", id);
+ if (!FBTrace.DBG_CONSOLE)
+ FBL.unwrapObject(element).firebugIgnore = true;
+
+ element.innerHTML = src;
+ if (doc.documentElement)
+ doc.documentElement.appendChild(element);
+ else
+ {
+ // See issue 1079, the svg test case gives this error
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("lib.addScript doc has no documentElement:", doc);
+ }
+ return element;
+};
+
+
+// ************************************************************************************************
+
+this.getStyle = this.isIE ?
+ function(el, name)
+ {
+ return el.currentStyle[name] || el.style[name] || undefined;
+ }
+ :
+ function(el, name)
+ {
+ return el.ownerDocument.defaultView.getComputedStyle(el,null)[name]
+ || el.style[name] || undefined;
+ };
+
+
+// ************************************************************************************************
+// Whitespace and Entity conversions
+
+var entityConversionLists = this.entityConversionLists = {
+ normal : {
+ whitespace : {
+ '\t' : '\u200c\u2192',
+ '\n' : '\u200c\u00b6',
+ '\r' : '\u200c\u00ac',
+ ' ' : '\u200c\u00b7'
+ }
+ },
+ reverse : {
+ whitespace : {
+ '&Tab;' : '\t',
+ '&NewLine;' : '\n',
+ '\u200c\u2192' : '\t',
+ '\u200c\u00b6' : '\n',
+ '\u200c\u00ac' : '\r',
+ '\u200c\u00b7' : ' '
+ }
+ }
+};
+
+var normal = entityConversionLists.normal,
+ reverse = entityConversionLists.reverse;
+
+function addEntityMapToList(ccode, entity)
+{
+ var lists = Array.prototype.slice.call(arguments, 2),
+ len = lists.length,
+ ch = String.fromCharCode(ccode);
+ for (var i = 0; i < len; i++)
+ {
+ var list = lists[i];
+ normal[list]=normal[list] || {};
+ normal[list][ch] = '&' + entity + ';';
+ reverse[list]=reverse[list] || {};
+ reverse[list]['&' + entity + ';'] = ch;
+ }
+};
+
+var e = addEntityMapToList,
+ white = 'whitespace',
+ text = 'text',
+ attr = 'attributes',
+ css = 'css',
+ editor = 'editor';
+
+e(0x0022, 'quot', attr, css);
+e(0x0026, 'amp', attr, text, css);
+e(0x0027, 'apos', css);
+e(0x003c, 'lt', attr, text, css);
+e(0x003e, 'gt', attr, text, css);
+e(0xa9, 'copy', text, editor);
+e(0xae, 'reg', text, editor);
+e(0x2122, 'trade', text, editor);
+
+// See http://en.wikipedia.org/wiki/Dash
+e(0x2012, '#8210', attr, text, editor); // figure dash
+e(0x2013, 'ndash', attr, text, editor); // en dash
+e(0x2014, 'mdash', attr, text, editor); // em dash
+e(0x2015, '#8213', attr, text, editor); // horizontal bar
+
+e(0x00a0, 'nbsp', attr, text, white, editor);
+e(0x2002, 'ensp', attr, text, white, editor);
+e(0x2003, 'emsp', attr, text, white, editor);
+e(0x2009, 'thinsp', attr, text, white, editor);
+e(0x200c, 'zwnj', attr, text, white, editor);
+e(0x200d, 'zwj', attr, text, white, editor);
+e(0x200e, 'lrm', attr, text, white, editor);
+e(0x200f, 'rlm', attr, text, white, editor);
+e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP)
+
+//************************************************************************************************
+// Entity escaping
+
+var entityConversionRegexes = {
+ normal : {},
+ reverse : {}
+ };
+
+var escapeEntitiesRegEx = {
+ normal : function(list)
+ {
+ var chars = [];
+ for ( var ch in list)
+ {
+ chars.push(ch);
+ }
+ return new RegExp('([' + chars.join('') + '])', 'gm');
+ },
+ reverse : function(list)
+ {
+ var chars = [];
+ for ( var ch in list)
+ {
+ chars.push(ch);
+ }
+ return new RegExp('(' + chars.join('|') + ')', 'gm');
+ }
+};
+
+function getEscapeRegexp(direction, lists)
+{
+ var name = '', re;
+ var groups = [].concat(lists);
+ for (i = 0; i < groups.length; i++)
+ {
+ name += groups[i].group;
+ }
+ re = entityConversionRegexes[direction][name];
+ if (!re)
+ {
+ var list = {};
+ if (groups.length > 1)
+ {
+ for ( var i = 0; i < groups.length; i++)
+ {
+ var aList = entityConversionLists[direction][groups[i].group];
+ for ( var item in aList)
+ list[item] = aList[item];
+ }
+ } else if (groups.length==1)
+ {
+ list = entityConversionLists[direction][groups[0].group]; // faster for special case
+ } else {
+ list = {}; // perhaps should print out an error here?
+ }
+ re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list);
+ }
+ return re;
+};
+
+function createSimpleEscape(name, direction)
+{
+ return function(value)
+ {
+ var list = entityConversionLists[direction][name];
+ return String(value).replace(
+ getEscapeRegexp(direction, {
+ group : name,
+ list : list
+ }),
+ function(ch)
+ {
+ return list[ch];
+ }
+ );
+ };
+};
+
+function escapeGroupsForEntities(str, lists)
+{
+ lists = [].concat(lists);
+ var re = getEscapeRegexp('normal', lists),
+ split = String(str).split(re),
+ len = split.length,
+ results = [],
+ cur, r, i, ri = 0, l, list, last = '';
+ if (!len)
+ return [ {
+ str : String(str),
+ group : '',
+ name : ''
+ } ];
+ for (i = 0; i < len; i++)
+ {
+ cur = split[i];
+ if (cur == '')
+ continue;
+ for (l = 0; l < lists.length; l++)
+ {
+ list = lists[l];
+ r = entityConversionLists.normal[list.group][cur];
+ // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space
+ // r = ' ';
+ if (r)
+ {
+ results[ri] = {
+ 'str' : r,
+ 'class' : list['class'],
+ 'extra' : list.extra[cur] ? list['class']
+ + list.extra[cur] : ''
+ };
+ break;
+ }
+ }
+ // last=cur;
+ if (!r)
+ results[ri] = {
+ 'str' : cur,
+ 'class' : '',
+ 'extra' : ''
+ };
+ ri++;
+ }
+ return results;
+};
+
+this.escapeGroupsForEntities = escapeGroupsForEntities;
+
+
+function unescapeEntities(str, lists)
+{
+ var re = getEscapeRegexp('reverse', lists),
+ split = String(str).split(re),
+ len = split.length,
+ results = [],
+ cur, r, i, ri = 0, l, list;
+ if (!len)
+ return str;
+ lists = [].concat(lists);
+ for (i = 0; i < len; i++)
+ {
+ cur = split[i];
+ if (cur == '')
+ continue;
+ for (l = 0; l < lists.length; l++)
+ {
+ list = lists[l];
+ r = entityConversionLists.reverse[list.group][cur];
+ if (r)
+ {
+ results[ri] = r;
+ break;
+ }
+ }
+ if (!r)
+ results[ri] = cur;
+ ri++;
+ }
+ return results.join('') || '';
+};
+
+
+// ************************************************************************************************
+// String escaping
+
+var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal');
+var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal');
+var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal');
+var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal');
+
+// deprecated compatibility functions
+//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal');
+//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse');
+//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML);
+//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML);
+
+var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal');
+
+var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse');
+
+this.unescapeForTextNode = function(str)
+{
+ if (Firebug.showTextNodesWithWhitespace)
+ str = unescapeWhitespace(str);
+ if (!Firebug.showTextNodesWithEntities)
+ str = escapeForElementAttribute(str);
+ return str;
+};
+
+this.escapeNewLines = function(value)
+{
+ return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n");
+};
+
+this.stripNewLines = function(value)
+{
+ return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value;
+};
+
+this.escapeJS = function(value)
+{
+ return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g");
+};
+
+function escapeHTMLAttribute(value)
+{
+ function replaceChars(ch)
+ {
+ switch (ch)
+ {
+ case "&":
+ return "&amp;";
+ case "'":
+ return apos;
+ case '"':
+ return quot;
+ }
+ return "?";
+ };
+ var apos = "&#39;", quot = "&quot;", around = '"';
+ if( value.indexOf('"') == -1 ) {
+ quot = '"';
+ apos = "'";
+ } else if( value.indexOf("'") == -1 ) {
+ quot = '"';
+ around = "'";
+ }
+ return around + (String(value).replace(/[&'"]/g, replaceChars)) + around;
+}
+
+
+function escapeHTML(value)
+{
+ function replaceChars(ch)
+ {
+ switch (ch)
+ {
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ case "'":
+ return "&#39;";
+ case '"':
+ return "&quot;";
+ }
+ return "?";
+ };
+ return String(value).replace(/[<>&"']/g, replaceChars);
+}
+
+this.escapeHTML = escapeHTML;
+
+this.cropString = function(text, limit)
+{
+ text = text + "";
+
+ if (!limit)
+ var halfLimit = 50;
+ else
+ var halfLimit = limit / 2;
+
+ if (text.length > limit)
+ return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit));
+ else
+ return this.escapeNewLines(text);
+};
+
+this.isWhitespace = function(text)
+{
+ return !reNotWhitespace.exec(text);
+};
+
+this.splitLines = function(text)
+{
+ var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg;
+ var lines;
+ if (text.match)
+ {
+ lines = text.match(reSplitLines2);
+ }
+ else
+ {
+ var str = text+"";
+ lines = str.match(reSplitLines2);
+ }
+ lines.pop();
+ return lines;
+};
+
+
+// ************************************************************************************************
+
+this.safeToString = function(ob)
+{
+ if (this.isIE)
+ {
+ try
+ {
+ // FIXME: xxxpedro this is failing in IE for the global "external" object
+ return ob + "";
+ }
+ catch(E)
+ {
+ FBTrace.sysout("Lib.safeToString() failed for ", ob);
+ return "";
+ }
+ }
+
+ try
+ {
+ if (ob && "toString" in ob && typeof ob.toString == "function")
+ return ob.toString();
+ }
+ catch (exc)
+ {
+ // xxxpedro it is not safe to use ob+""?
+ return ob + "";
+ ///return "[an object with no toString() function]";
+ }
+};
+
+// ************************************************************************************************
+
+this.hasProperties = function(ob)
+{
+ try
+ {
+ for (var name in ob)
+ return true;
+ } catch (exc) {}
+ return false;
+};
+
+// ************************************************************************************************
+// String Util
+
+var reTrim = /^\s+|\s+$/g;
+this.trim = function(s)
+{
+ return s.replace(reTrim, "");
+};
+
+
+// ************************************************************************************************
+// Empty
+
+this.emptyFn = function(){};
+
+
+
+// ************************************************************************************************
+// Visibility
+
+this.isVisible = function(elt)
+{
+ /*
+ if (elt instanceof XULElement)
+ {
+ //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n");
+ return (!elt.hidden && !elt.collapsed);
+ }
+ /**/
+
+ return this.getStyle(elt, "visibility") != "hidden" &&
+ ( elt.offsetWidth > 0 || elt.offsetHeight > 0
+ || elt.tagName in invisibleTags
+ || elt.namespaceURI == "http://www.w3.org/2000/svg"
+ || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" );
+};
+
+this.collapse = function(elt, collapsed)
+{
+ // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector,
+ // but it is causing a bug (the element disappears when you set the "collapsed"
+ // attribute, but it doesn't appear when you remove the attribute. So, for those
+ // cases, we need to use the class attribute.
+ if (this.isIElt8)
+ {
+ if (collapsed)
+ this.setClass(elt, "collapsed");
+ else
+ this.removeClass(elt, "collapsed");
+ }
+ else
+ elt.setAttribute("collapsed", collapsed ? "true" : "false");
+};
+
+this.obscure = function(elt, obscured)
+{
+ if (obscured)
+ this.setClass(elt, "obscured");
+ else
+ this.removeClass(elt, "obscured");
+};
+
+this.hide = function(elt, hidden)
+{
+ elt.style.visibility = hidden ? "hidden" : "visible";
+};
+
+this.clearNode = function(node)
+{
+ var nodeName = " " + node.nodeName.toLowerCase() + " ";
+ var ignoreTags = " table tbody thead tfoot th tr td ";
+
+ // IE can't use innerHTML of table elements
+ if (this.isIE && ignoreTags.indexOf(nodeName) != -1)
+ this.eraseNode(node);
+ else
+ node.innerHTML = "";
+};
+
+this.eraseNode = function(node)
+{
+ while (node.lastChild)
+ node.removeChild(node.lastChild);
+};
+
+// ************************************************************************************************
+// Window iteration
+
+this.iterateWindows = function(win, handler)
+{
+ if (!win || !win.document)
+ return;
+
+ handler(win);
+
+ if (win == top || !win.frames) return; // XXXjjb hack for chromeBug
+
+ for (var i = 0; i < win.frames.length; ++i)
+ {
+ var subWin = win.frames[i];
+ if (subWin != win)
+ this.iterateWindows(subWin, handler);
+ }
+};
+
+this.getRootWindow = function(win)
+{
+ for (; win; win = win.parent)
+ {
+ if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window"))
+ return win;
+ }
+ return null;
+};
+
+// ************************************************************************************************
+// Graphics
+
+this.getClientOffset = function(elt)
+{
+ var addOffset = function addOffset(elt, coords, view)
+ {
+ var p = elt.offsetParent;
+
+ ///var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, "");
+ var chrome = Firebug.chrome;
+
+ if (elt.offsetLeft)
+ ///coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth);
+ coords.x += elt.offsetLeft + chrome.getMeasurementInPixels(elt, "borderLeft");
+ if (elt.offsetTop)
+ ///coords.y += elt.offsetTop + parseInt(style.borderTopWidth);
+ coords.y += elt.offsetTop + chrome.getMeasurementInPixels(elt, "borderTop");
+
+ if (p)
+ {
+ if (p.nodeType == 1)
+ addOffset(p, coords, view);
+ }
+ else
+ {
+ var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView;
+ // IE will fail when reading the frameElement property of a popup window.
+ // We don't need it anyway once it is outside the (popup) viewport, so we're
+ // ignoring the frameElement check when the window is a popup
+ if (!otherView.opener && otherView.frameElement)
+ addOffset(otherView.frameElement, coords, otherView);
+ }
+ };
+
+ var isIE = this.isIE;
+ var coords = {x: 0, y: 0};
+ if (elt)
+ {
+ var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView;
+ addOffset(elt, coords, view);
+ }
+
+ return coords;
+};
+
+this.getViewOffset = function(elt, singleFrame)
+{
+ function addOffset(elt, coords, view)
+ {
+ var p = elt.offsetParent;
+ coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0);
+ coords.y += elt.offsetTop - (p ? p.scrollTop : 0);
+
+ if (p)
+ {
+ if (p.nodeType == 1)
+ {
+ var parentStyle = view.getComputedStyle(p, "");
+ if (parentStyle.position != "static")
+ {
+ coords.x += parseInt(parentStyle.borderLeftWidth);
+ coords.y += parseInt(parentStyle.borderTopWidth);
+
+ if (p.localName == "TABLE")
+ {
+ coords.x += parseInt(parentStyle.paddingLeft);
+ coords.y += parseInt(parentStyle.paddingTop);
+ }
+ else if (p.localName == "BODY")
+ {
+ var style = view.getComputedStyle(elt, "");
+ coords.x += parseInt(style.marginLeft);
+ coords.y += parseInt(style.marginTop);
+ }
+ }
+ else if (p.localName == "BODY")
+ {
+ coords.x += parseInt(parentStyle.borderLeftWidth);
+ coords.y += parseInt(parentStyle.borderTopWidth);
+ }
+
+ var parent = elt.parentNode;
+ while (p != parent)
+ {
+ coords.x -= parent.scrollLeft;
+ coords.y -= parent.scrollTop;
+ parent = parent.parentNode;
+ }
+ addOffset(p, coords, view);
+ }
+ }
+ else
+ {
+ if (elt.localName == "BODY")
+ {
+ var style = view.getComputedStyle(elt, "");
+ coords.x += parseInt(style.borderLeftWidth);
+ coords.y += parseInt(style.borderTopWidth);
+
+ var htmlStyle = view.getComputedStyle(elt.parentNode, "");
+ coords.x -= parseInt(htmlStyle.paddingLeft);
+ coords.y -= parseInt(htmlStyle.paddingTop);
+ }
+
+ if (elt.scrollLeft)
+ coords.x += elt.scrollLeft;
+ if (elt.scrollTop)
+ coords.y += elt.scrollTop;
+
+ var win = elt.ownerDocument.defaultView;
+ if (win && (!singleFrame && win.frameElement))
+ addOffset(win.frameElement, coords, win);
+ }
+
+ }
+
+ var coords = {x: 0, y: 0};
+ if (elt)
+ addOffset(elt, coords, elt.ownerDocument.defaultView);
+
+ return coords;
+};
+
+this.getLTRBWH = function(elt)
+{
+ var bcrect,
+ dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0};
+
+ if (elt)
+ {
+ bcrect = elt.getBoundingClientRect();
+ dims.left = bcrect.left;
+ dims.top = bcrect.top;
+ dims.right = bcrect.right;
+ dims.bottom = bcrect.bottom;
+
+ if(bcrect.width)
+ {
+ dims.width = bcrect.width;
+ dims.height = bcrect.height;
+ }
+ else
+ {
+ dims.width = dims.right - dims.left;
+ dims.height = dims.bottom - dims.top;
+ }
+ }
+ return dims;
+};
+
+this.applyBodyOffsets = function(elt, clientRect)
+{
+ var od = elt.ownerDocument;
+ if (!od.body)
+ return clientRect;
+
+ var style = od.defaultView.getComputedStyle(od.body, null);
+
+ var pos = style.getPropertyValue('position');
+ if(pos === 'absolute' || pos === 'relative')
+ {
+ var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0;
+ var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0;
+ var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0;
+ var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0;
+ var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0;
+ var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0;
+
+ var offsetX = borderLeft + paddingLeft + marginLeft;
+ var offsetY = borderTop + paddingTop + marginTop;
+
+ clientRect.left -= offsetX;
+ clientRect.top -= offsetY;
+ clientRect.right -= offsetX;
+ clientRect.bottom -= offsetY;
+ }
+
+ return clientRect;
+};
+
+this.getOffsetSize = function(elt)
+{
+ return {width: elt.offsetWidth, height: elt.offsetHeight};
+};
+
+this.getOverflowParent = function(element)
+{
+ for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent)
+ {
+ if (scrollParent.scrollHeight > scrollParent.offsetHeight)
+ return scrollParent;
+ }
+};
+
+this.isScrolledToBottom = function(element)
+{
+ var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight;
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom);
+ return onBottom;
+};
+
+this.scrollToBottom = function(element)
+{
+ element.scrollTop = element.scrollHeight;
+
+ if (FBTrace.DBG_CONSOLE)
+ {
+ FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight);
+ if (element.scrollHeight == element.offsetHeight)
+ FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element);
+ }
+
+ return (element.scrollTop == element.scrollHeight);
+};
+
+this.move = function(element, x, y)
+{
+ element.style.left = x + "px";
+ element.style.top = y + "px";
+};
+
+this.resize = function(element, w, h)
+{
+ element.style.width = w + "px";
+ element.style.height = h + "px";
+};
+
+this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int}
+{
+ if (!scrollBox)
+ scrollBox = this.getOverflowParent(element);
+
+ if (!scrollBox)
+ return;
+
+ var offset = this.getClientOffset(element);
+
+ var topSpace = offset.y - scrollBox.scrollTop;
+ var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight)
+ - (offset.y + element.offsetHeight);
+
+ if (topSpace < 0 || bottomSpace < 0)
+ {
+ var split = (scrollBox.clientHeight/2);
+ var centerY = offset.y - split;
+ scrollBox.scrollTop = centerY;
+ topSpace = split;
+ bottomSpace = split - element.offsetHeight;
+ }
+
+ return {before: Math.round((topSpace/element.offsetHeight) + 0.5),
+ after: Math.round((bottomSpace/element.offsetHeight) + 0.5) };
+};
+
+this.scrollIntoCenterView = function(element, scrollBox, notX, notY)
+{
+ if (!element)
+ return;
+
+ if (!scrollBox)
+ scrollBox = this.getOverflowParent(element);
+
+ if (!scrollBox)
+ return;
+
+ var offset = this.getClientOffset(element);
+
+ if (!notY)
+ {
+ var topSpace = offset.y - scrollBox.scrollTop;
+ var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight)
+ - (offset.y + element.offsetHeight);
+
+ if (topSpace < 0 || bottomSpace < 0)
+ {
+ var centerY = offset.y - (scrollBox.clientHeight/2);
+ scrollBox.scrollTop = centerY;
+ }
+ }
+
+ if (!notX)
+ {
+ var leftSpace = offset.x - scrollBox.scrollLeft;
+ var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth)
+ - (offset.x + element.clientWidth);
+
+ if (leftSpace < 0 || rightSpace < 0)
+ {
+ var centerX = offset.x - (scrollBox.clientWidth/2);
+ scrollBox.scrollLeft = centerX;
+ }
+ }
+ if (FBTrace.DBG_SOURCEFILES)
+ FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML);
+};
+
+
+// ************************************************************************************************
+// CSS
+
+var cssKeywordMap = null;
+var cssPropNames = null;
+var cssColorNames = null;
+var imageRules = null;
+
+this.getCSSKeywordsByProperty = function(propName)
+{
+ if (!cssKeywordMap)
+ {
+ cssKeywordMap = {};
+
+ for (var name in this.cssInfo)
+ {
+ var list = [];
+
+ var types = this.cssInfo[name];
+ for (var i = 0; i < types.length; ++i)
+ {
+ var keywords = this.cssKeywords[types[i]];
+ if (keywords)
+ list.push.apply(list, keywords);
+ }
+
+ cssKeywordMap[name] = list;
+ }
+ }
+
+ return propName in cssKeywordMap ? cssKeywordMap[propName] : [];
+};
+
+this.getCSSPropertyNames = function()
+{
+ if (!cssPropNames)
+ {
+ cssPropNames = [];
+
+ for (var name in this.cssInfo)
+ cssPropNames.push(name);
+ }
+
+ return cssPropNames;
+};
+
+this.isColorKeyword = function(keyword)
+{
+ if (keyword == "transparent")
+ return false;
+
+ if (!cssColorNames)
+ {
+ cssColorNames = [];
+
+ var colors = this.cssKeywords["color"];
+ for (var i = 0; i < colors.length; ++i)
+ cssColorNames.push(colors[i].toLowerCase());
+
+ var systemColors = this.cssKeywords["systemColor"];
+ for (var i = 0; i < systemColors.length; ++i)
+ cssColorNames.push(systemColors[i].toLowerCase());
+ }
+
+ return cssColorNames.indexOf ? // Array.indexOf is not available in IE
+ cssColorNames.indexOf(keyword.toLowerCase()) != -1 :
+ (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1;
+};
+
+this.isImageRule = function(rule)
+{
+ if (!imageRules)
+ {
+ imageRules = [];
+
+ for (var i in this.cssInfo)
+ {
+ var r = i.toLowerCase();
+ var suffix = "image";
+ if (r.match(suffix + "$") == suffix || r == "background")
+ imageRules.push(r);
+ }
+ }
+
+ return imageRules.indexOf ? // Array.indexOf is not available in IE
+ imageRules.indexOf(rule.toLowerCase()) != -1 :
+ (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1;
+};
+
+this.copyTextStyles = function(fromNode, toNode, style)
+{
+ var view = this.isIE ?
+ fromNode.ownerDocument.parentWindow :
+ fromNode.ownerDocument.defaultView;
+
+ if (view)
+ {
+ if (!style)
+ style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, "");
+
+ toNode.style.fontFamily = style.fontFamily;
+
+ // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE
+ // returns wrong computed styles for inherited properties (like font-*)
+ //
+ // Also would be good to create a FBL.getStyle()
+ toNode.style.fontSize = style.fontSize;
+ toNode.style.fontWeight = style.fontWeight;
+ toNode.style.fontStyle = style.fontStyle;
+
+ return style;
+ }
+};
+
+this.copyBoxStyles = function(fromNode, toNode, style)
+{
+ var view = this.isIE ?
+ fromNode.ownerDocument.parentWindow :
+ fromNode.ownerDocument.defaultView;
+
+ if (view)
+ {
+ if (!style)
+ style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, "");
+
+ toNode.style.marginTop = style.marginTop;
+ toNode.style.marginRight = style.marginRight;
+ toNode.style.marginBottom = style.marginBottom;
+ toNode.style.marginLeft = style.marginLeft;
+ toNode.style.borderTopWidth = style.borderTopWidth;
+ toNode.style.borderRightWidth = style.borderRightWidth;
+ toNode.style.borderBottomWidth = style.borderBottomWidth;
+ toNode.style.borderLeftWidth = style.borderLeftWidth;
+
+ return style;
+ }
+};
+
+this.readBoxStyles = function(style)
+{
+ var styleNames = {
+ "margin-top": "marginTop", "margin-right": "marginRight",
+ "margin-left": "marginLeft", "margin-bottom": "marginBottom",
+ "border-top-width": "borderTop", "border-right-width": "borderRight",
+ "border-left-width": "borderLeft", "border-bottom-width": "borderBottom",
+ "padding-top": "paddingTop", "padding-right": "paddingRight",
+ "padding-left": "paddingLeft", "padding-bottom": "paddingBottom",
+ "z-index": "zIndex"
+ };
+
+ var styles = {};
+ for (var styleName in styleNames)
+ styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0;
+ if (FBTrace.DBG_INSPECT)
+ FBTrace.sysout("readBoxStyles ", styles);
+ return styles;
+};
+
+this.getBoxFromStyles = function(style, element)
+{
+ var args = this.readBoxStyles(style);
+ args.width = element.offsetWidth
+ - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight);
+ args.height = element.offsetHeight
+ - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom);
+ return args;
+};
+
+this.getElementCSSSelector = function(element)
+{
+ var label = element.localName.toLowerCase();
+ if (element.id)
+ label += "#" + element.id;
+ if (element.hasAttribute("class"))
+ label += "." + element.getAttribute("class").split(" ")[0];
+
+ return label;
+};
+
+this.getURLForStyleSheet= function(styleSheet)
+{
+ //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null.
+ return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL);
+};
+
+this.getDocumentForStyleSheet = function(styleSheet)
+{
+ while (styleSheet.parentStyleSheet && !styleSheet.ownerNode)
+ {
+ styleSheet = styleSheet.parentStyleSheet;
+ }
+ if (styleSheet.ownerNode)
+ return styleSheet.ownerNode.ownerDocument;
+};
+
+/**
+ * Retrieves the instance number for a given style sheet. The instance number
+ * is sheet's index within the set of all other sheets whose URL is the same.
+ */
+this.getInstanceForStyleSheet = function(styleSheet, ownerDocument)
+{
+ // System URLs are always unique (or at least we are making this assumption)
+ if (FBL.isSystemStyleSheet(styleSheet))
+ return 0;
+
+ // ownerDocument is an optional hint for performance
+ if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument);
+ ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet);
+
+ var ret = 0,
+ styleSheets = ownerDocument.styleSheets,
+ href = styleSheet.href;
+ for (var i = 0; i < styleSheets.length; i++)
+ {
+ var curSheet = styleSheets[i];
+ if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode)));
+ if (curSheet == styleSheet)
+ break;
+ if (curSheet.href == href)
+ ret++;
+ }
+ return ret;
+};
+
+// ************************************************************************************************
+// HTML and XML Serialization
+
+
+var getElementType = this.getElementType = function(node)
+{
+ if (isElementXUL(node))
+ return 'xul';
+ else if (isElementSVG(node))
+ return 'svg';
+ else if (isElementMathML(node))
+ return 'mathml';
+ else if (isElementXHTML(node))
+ return 'xhtml';
+ else if (isElementHTML(node))
+ return 'html';
+};
+
+var getElementSimpleType = this.getElementSimpleType = function(node)
+{
+ if (isElementSVG(node))
+ return 'svg';
+ else if (isElementMathML(node))
+ return 'mathml';
+ else
+ return 'html';
+};
+
+var isElementHTML = this.isElementHTML = function(node)
+{
+ return node.nodeName == node.nodeName.toUpperCase();
+};
+
+var isElementXHTML = this.isElementXHTML = function(node)
+{
+ return node.nodeName == node.nodeName.toLowerCase();
+};
+
+var isElementMathML = this.isElementMathML = function(node)
+{
+ return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML';
+};
+
+var isElementSVG = this.isElementSVG = function(node)
+{
+ return node.namespaceURI == 'http://www.w3.org/2000/svg';
+};
+
+var isElementXUL = this.isElementXUL = function(node)
+{
+ return node instanceof XULElement;
+};
+
+this.isSelfClosing = function(element)
+{
+ if (isElementSVG(element) || isElementMathML(element))
+ return true;
+ var tag = element.localName.toLowerCase();
+ return (this.selfClosingTags.hasOwnProperty(tag));
+};
+
+this.getElementHTML = function(element)
+{
+ var self=this;
+ function toHTML(elt)
+ {
+ if (elt.nodeType == Node.ELEMENT_NODE)
+ {
+ if (unwrapObject(elt).firebugIgnore)
+ return;
+
+ html.push('<', elt.nodeName.toLowerCase());
+
+ for (var i = 0; i < elt.attributes.length; ++i)
+ {
+ var attr = elt.attributes[i];
+
+ // Hide attributes set by Firebug
+ if (attr.localName.indexOf("firebug-") == 0)
+ continue;
+
+ // MathML
+ if (attr.localName.indexOf("-moz-math") == 0)
+ {
+ // just hide for now
+ continue;
+ }
+
+ html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"');
+ }
+
+ if (elt.firstChild)
+ {
+ html.push('>');
+
+ var pureText=true;
+ for (var child = element.firstChild; child; child = child.nextSibling)
+ pureText=pureText && (child.nodeType == Node.TEXT_NODE);
+
+ if (pureText)
+ html.push(escapeForHtmlEditor(elt.textContent));
+ else {
+ for (var child = elt.firstChild; child; child = child.nextSibling)
+ toHTML(child);
+ }
+
+ html.push('</', elt.nodeName.toLowerCase(), '>');
+ }
+ else if (isElementSVG(elt) || isElementMathML(elt))
+ {
+ html.push('/>');
+ }
+ else if (self.isSelfClosing(elt))
+ {
+ html.push((isElementXHTML(elt))?'/>':'>');
+ }
+ else
+ {
+ html.push('></', elt.nodeName.toLowerCase(), '>');
+ }
+ }
+ else if (elt.nodeType == Node.TEXT_NODE)
+ html.push(escapeForTextNode(elt.textContent));
+ else if (elt.nodeType == Node.CDATA_SECTION_NODE)
+ html.push('<![CDATA[', elt.nodeValue, ']]>');
+ else if (elt.nodeType == Node.COMMENT_NODE)
+ html.push('<!--', elt.nodeValue, '-->');
+ }
+
+ var html = [];
+ toHTML(element);
+ return html.join("");
+};
+
+this.getElementXML = function(element)
+{
+ function toXML(elt)
+ {
+ if (elt.nodeType == Node.ELEMENT_NODE)
+ {
+ if (unwrapObject(elt).firebugIgnore)
+ return;
+
+ xml.push('<', elt.nodeName.toLowerCase());
+
+ for (var i = 0; i < elt.attributes.length; ++i)
+ {
+ var attr = elt.attributes[i];
+
+ // Hide attributes set by Firebug
+ if (attr.localName.indexOf("firebug-") == 0)
+ continue;
+
+ // MathML
+ if (attr.localName.indexOf("-moz-math") == 0)
+ {
+ // just hide for now
+ continue;
+ }
+
+ xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"');
+ }
+
+ if (elt.firstChild)
+ {
+ xml.push('>');
+
+ for (var child = elt.firstChild; child; child = child.nextSibling)
+ toXML(child);
+
+ xml.push('</', elt.nodeName.toLowerCase(), '>');
+ }
+ else
+ xml.push('/>');
+ }
+ else if (elt.nodeType == Node.TEXT_NODE)
+ xml.push(elt.nodeValue);
+ else if (elt.nodeType == Node.CDATA_SECTION_NODE)
+ xml.push('<![CDATA[', elt.nodeValue, ']]>');
+ else if (elt.nodeType == Node.COMMENT_NODE)
+ xml.push('<!--', elt.nodeValue, '-->');
+ }
+
+ var xml = [];
+ toXML(element);
+ return xml.join("");
+};
+
+
+// ************************************************************************************************
+// CSS classes
+
+this.hasClass = function(node, name) // className, className, ...
+{
+ // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments?
+ // this function can be optimized a lot if assumed 2 arguments only,
+ // which seems to be what happens 99% of the time
+ if (arguments.length == 2)
+ return (' '+node.className+' ').indexOf(' '+name+' ') != -1;
+
+ if (!node || node.nodeType != 1)
+ return false;
+ else
+ {
+ for (var i=1; i<arguments.length; ++i)
+ {
+ var name = arguments[i];
+ var re = new RegExp("(^|\\s)"+name+"($|\\s)");
+ if (!re.exec(node.className))
+ return false;
+ }
+
+ return true;
+ }
+};
+
+this.old_hasClass = function(node, name) // className, className, ...
+{
+ if (!node || node.nodeType != 1)
+ return false;
+ else
+ {
+ for (var i=1; i<arguments.length; ++i)
+ {
+ var name = arguments[i];
+ var re = new RegExp("(^|\\s)"+name+"($|\\s)");
+ if (!re.exec(node.className))
+ return false;
+ }
+
+ return true;
+ }
+};
+
+this.setClass = function(node, name)
+{
+ if (node && (' '+node.className+' ').indexOf(' '+name+' ') == -1)
+ ///if (node && !this.hasClass(node, name))
+ node.className += " " + name;
+};
+
+this.getClassValue = function(node, name)
+{
+ var re = new RegExp(name+"-([^ ]+)");
+ var m = re.exec(node.className);
+ return m ? m[1] : "";
+};
+
+this.removeClass = function(node, name)
+{
+ if (node && node.className)
+ {
+ var index = node.className.indexOf(name);
+ if (index >= 0)
+ {
+ var size = name.length;
+ node.className = node.className.substr(0,index-1) + node.className.substr(index+size);
+ }
+ }
+};
+
+this.toggleClass = function(elt, name)
+{
+ if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1)
+ ///if (this.hasClass(elt, name))
+ this.removeClass(elt, name);
+ else
+ this.setClass(elt, name);
+};
+
+this.setClassTimed = function(elt, name, context, timeout)
+{
+ if (!timeout)
+ timeout = 1300;
+
+ if (elt.__setClassTimeout)
+ context.clearTimeout(elt.__setClassTimeout);
+ else
+ this.setClass(elt, name);
+
+ elt.__setClassTimeout = context.setTimeout(function()
+ {
+ delete elt.__setClassTimeout;
+
+ FBL.removeClass(elt, name);
+ }, timeout);
+};
+
+this.cancelClassTimed = function(elt, name, context)
+{
+ if (elt.__setClassTimeout)
+ {
+ FBL.removeClass(elt, name);
+ context.clearTimeout(elt.__setClassTimeout);
+ delete elt.__setClassTimeout;
+ }
+};
+
+
+// ************************************************************************************************
+// DOM queries
+
+this.$ = function(id, doc)
+{
+ if (doc)
+ return doc.getElementById(id);
+ else
+ {
+ return FBL.Firebug.chrome.document.getElementById(id);
+ }
+};
+
+this.$$ = function(selector, doc)
+{
+ if (doc || !FBL.Firebug.chrome)
+ return FBL.Firebug.Selector(selector, doc);
+ else
+ {
+ return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document);
+ }
+};
+
+this.getChildByClass = function(node) // ,classname, classname, classname...
+{
+ for (var i = 1; i < arguments.length; ++i)
+ {
+ var className = arguments[i];
+ var child = node.firstChild;
+ node = null;
+ for (; child; child = child.nextSibling)
+ {
+ if (this.hasClass(child, className))
+ {
+ node = child;
+ break;
+ }
+ }
+ }
+
+ return node;
+};
+
+this.getAncestorByClass = function(node, className)
+{
+ for (var parent = node; parent; parent = parent.parentNode)
+ {
+ if (this.hasClass(parent, className))
+ return parent;
+ }
+
+ return null;
+};
+
+
+this.getElementsByClass = function(node, className)
+{
+ var result = [];
+
+ for (var child = node.firstChild; child; child = child.nextSibling)
+ {
+ if (this.hasClass(child, className))
+ result.push(child);
+ }
+
+ return result;
+};
+
+this.getElementByClass = function(node, className) // className, className, ...
+{
+ var args = cloneArray(arguments); args.splice(0, 1);
+ for (var child = node.firstChild; child; child = child.nextSibling)
+ {
+ var args1 = cloneArray(args); args1.unshift(child);
+ if (FBL.hasClass.apply(null, args1))
+ return child;
+ else
+ {
+ var found = FBL.getElementByClass.apply(null, args1);
+ if (found)
+ return found;
+ }
+ }
+
+ return null;
+};
+
+this.isAncestor = function(node, potentialAncestor)
+{
+ for (var parent = node; parent; parent = parent.parentNode)
+ {
+ if (parent == potentialAncestor)
+ return true;
+ }
+
+ return false;
+};
+
+this.getNextElement = function(node)
+{
+ while (node && node.nodeType != 1)
+ node = node.nextSibling;
+
+ return node;
+};
+
+this.getPreviousElement = function(node)
+{
+ while (node && node.nodeType != 1)
+ node = node.previousSibling;
+
+ return node;
+};
+
+this.getBody = function(doc)
+{
+ if (doc.body)
+ return doc.body;
+
+ var body = doc.getElementsByTagName("body")[0];
+ if (body)
+ return body;
+
+ return doc.firstChild; // For non-HTML docs
+};
+
+this.findNextDown = function(node, criteria)
+{
+ if (!node)
+ return null;
+
+ for (var child = node.firstChild; child; child = child.nextSibling)
+ {
+ if (criteria(child))
+ return child;
+
+ var next = this.findNextDown(child, criteria);
+ if (next)
+ return next;
+ }
+};
+
+this.findPreviousUp = function(node, criteria)
+{
+ if (!node)
+ return null;
+
+ for (var child = node.lastChild; child; child = child.previousSibling)
+ {
+ var next = this.findPreviousUp(child, criteria);
+ if (next)
+ return next;
+
+ if (criteria(child))
+ return child;
+ }
+};
+
+this.findNext = function(node, criteria, upOnly, maxRoot)
+{
+ if (!node)
+ return null;
+
+ if (!upOnly)
+ {
+ var next = this.findNextDown(node, criteria);
+ if (next)
+ return next;
+ }
+
+ for (var sib = node.nextSibling; sib; sib = sib.nextSibling)
+ {
+ if (criteria(sib))
+ return sib;
+
+ var next = this.findNextDown(sib, criteria);
+ if (next)
+ return next;
+ }
+
+ if (node.parentNode && node.parentNode != maxRoot)
+ return this.findNext(node.parentNode, criteria, true);
+};
+
+this.findPrevious = function(node, criteria, downOnly, maxRoot)
+{
+ if (!node)
+ return null;
+
+ for (var sib = node.previousSibling; sib; sib = sib.previousSibling)
+ {
+ var prev = this.findPreviousUp(sib, criteria);
+ if (prev)
+ return prev;
+
+ if (criteria(sib))
+ return sib;
+ }
+
+ if (!downOnly)
+ {
+ var next = this.findPreviousUp(node, criteria);
+ if (next)
+ return next;
+ }
+
+ if (node.parentNode && node.parentNode != maxRoot)
+ {
+ if (criteria(node.parentNode))
+ return node.parentNode;
+
+ return this.findPrevious(node.parentNode, criteria, true);
+ }
+};
+
+this.getNextByClass = function(root, state)
+{
+ var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); };
+ return this.findNext(root, iter);
+};
+
+this.getPreviousByClass = function(root, state)
+{
+ var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); };
+ return this.findPrevious(root, iter);
+};
+
+this.isElement = function(o)
+{
+ try {
+ return o && this.instanceOf(o, "Element");
+ }
+ catch (ex) {
+ return false;
+ }
+};
+
+
+// ************************************************************************************************
+// DOM Modification
+
+// TODO: xxxpedro use doc fragments in Context API
+var appendFragment = null;
+
+this.appendInnerHTML = function(element, html, referenceElement)
+{
+ // if undefined, we must convert it to null otherwise it will throw an error in IE
+ // when executing element.insertBefore(firstChild, referenceElement)
+ referenceElement = referenceElement || null;
+
+ var doc = element.ownerDocument;
+
+ // doc.createRange not available in IE
+ if (doc.createRange)
+ {
+ var range = doc.createRange(); // a helper object
+ range.selectNodeContents(element); // the environment to interpret the html
+
+ var fragment = range.createContextualFragment(html); // parse
+ var firstChild = fragment.firstChild;
+ element.insertBefore(fragment, referenceElement);
+ }
+ else
+ {
+ if (!appendFragment || appendFragment.ownerDocument != doc)
+ appendFragment = doc.createDocumentFragment();
+
+ var div = doc.createElement("div");
+ div.innerHTML = html;
+
+ var firstChild = div.firstChild;
+ while (div.firstChild)
+ appendFragment.appendChild(div.firstChild);
+
+ element.insertBefore(appendFragment, referenceElement);
+
+ div = null;
+ }
+
+ return firstChild;
+};
+
+
+// ************************************************************************************************
+// DOM creation
+
+this.createElement = function(tagName, properties)
+{
+ properties = properties || {};
+ var doc = properties.document || FBL.Firebug.chrome.document;
+
+ var element = doc.createElement(tagName);
+
+ for(var name in properties)
+ {
+ if (name != "document")
+ {
+ element[name] = properties[name];
+ }
+ }
+
+ return element;
+};
+
+this.createGlobalElement = function(tagName, properties)
+{
+ properties = properties || {};
+ var doc = FBL.Env.browser.document;
+
+ var element = this.NS && doc.createElementNS ?
+ doc.createElementNS(FBL.NS, tagName) :
+ doc.createElement(tagName);
+
+ for(var name in properties)
+ {
+ var propname = name;
+ if (FBL.isIE && name == "class") propname = "className";
+
+ if (name != "document")
+ {
+ element.setAttribute(propname, properties[name]);
+ }
+ }
+
+ return element;
+};
+
+//************************************************************************************************
+
+this.safeGetWindowLocation = function(window)
+{
+ try
+ {
+ if (window)
+ {
+ if (window.closed)
+ return "(window.closed)";
+ if ("location" in window)
+ return window.location+"";
+ else
+ return "(no window.location)";
+ }
+ else
+ return "(no context.window)";
+ }
+ catch(exc)
+ {
+ if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS)
+ FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc);
+ FBTrace.sysout("TabContext.getWindowLocation failed window:", window);
+ return "(getWindowLocation: "+exc+")";
+ }
+};
+
+// ************************************************************************************************
+// Events
+
+this.isLeftClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 1 : // IE "click" and "dblclick" button model
+ event.button == 0) && // others
+ this.noKeyModifiers(event);
+};
+
+this.isMiddleClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 4 : // IE "click" and "dblclick" button model
+ event.button == 1) &&
+ this.noKeyModifiers(event);
+};
+
+this.isRightClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 2 : // IE "click" and "dblclick" button model
+ event.button == 2) &&
+ this.noKeyModifiers(event);
+};
+
+this.noKeyModifiers = function(event)
+{
+ return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
+};
+
+this.isControlClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 1 : // IE "click" and "dblclick" button model
+ event.button == 0) &&
+ this.isControl(event);
+};
+
+this.isShiftClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 1 : // IE "click" and "dblclick" button model
+ event.button == 0) &&
+ this.isShift(event);
+};
+
+this.isControl = function(event)
+{
+ return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey;
+};
+
+this.isAlt = function(event)
+{
+ return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey;
+};
+
+this.isAltClick = function(event)
+{
+ return (this.isIE && event.type != "click" && event.type != "dblclick" ?
+ event.button == 1 : // IE "click" and "dblclick" button model
+ event.button == 0) &&
+ this.isAlt(event);
+};
+
+this.isControlShift = function(event)
+{
+ return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey;
+};
+
+this.isShift = function(event)
+{
+ return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
+};
+
+this.addEvent = function(object, name, handler, useCapture)
+{
+ if (object.addEventListener)
+ object.addEventListener(name, handler, useCapture);
+ else
+ object.attachEvent("on"+name, handler);
+};
+
+this.removeEvent = function(object, name, handler, useCapture)
+{
+ try
+ {
+ if (object.removeEventListener)
+ object.removeEventListener(name, handler, useCapture);
+ else
+ object.detachEvent("on"+name, handler);
+ }
+ catch(e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("FBL.removeEvent error: ", object, name);
+ }
+};
+
+this.cancelEvent = function(e, preventDefault)
+{
+ if (!e) return;
+
+ if (preventDefault)
+ {
+ if (e.preventDefault)
+ e.preventDefault();
+ else
+ e.returnValue = false;
+ }
+
+ if (e.stopPropagation)
+ e.stopPropagation();
+ else
+ e.cancelBubble = true;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.addGlobalEvent = function(name, handler)
+{
+ var doc = this.Firebug.browser.document;
+ var frames = this.Firebug.browser.window.frames;
+
+ this.addEvent(doc, name, handler);
+
+ if (this.Firebug.chrome.type == "popup")
+ this.addEvent(this.Firebug.chrome.document, name, handler);
+
+ for (var i = 0, frame; frame = frames[i]; i++)
+ {
+ try
+ {
+ this.addEvent(frame.document, name, handler);
+ }
+ catch(E)
+ {
+ // Avoid acess denied
+ }
+ }
+};
+
+this.removeGlobalEvent = function(name, handler)
+{
+ var doc = this.Firebug.browser.document;
+ var frames = this.Firebug.browser.window.frames;
+
+ this.removeEvent(doc, name, handler);
+
+ if (this.Firebug.chrome.type == "popup")
+ this.removeEvent(this.Firebug.chrome.document, name, handler);
+
+ for (var i = 0, frame; frame = frames[i]; i++)
+ {
+ try
+ {
+ this.removeEvent(frame.document, name, handler);
+ }
+ catch(E)
+ {
+ // Avoid acess denied
+ }
+ }
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.dispatch = function(listeners, name, args)
+{
+ if (!listeners) return;
+
+ try
+ {/**/
+ if (typeof listeners.length != "undefined")
+ {
+ if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners");
+
+ for (var i = 0; i < listeners.length; ++i)
+ {
+ var listener = listeners[i];
+ if ( listener[name] )
+ listener[name].apply(listener, args);
+ }
+ }
+ else
+ {
+ if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object");
+
+ for (var prop in listeners)
+ {
+ var listener = listeners[prop];
+ if ( listener[name] )
+ listener[name].apply(listener, args);
+ }
+ }
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.sysout(" Exception in lib.dispatch "+ name, exc);
+ //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener);
+ }
+ }
+ /**/
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var disableTextSelectionHandler = function(event)
+{
+ FBL.cancelEvent(event, true);
+
+ return false;
+};
+
+this.disableTextSelection = function(e)
+{
+ if (typeof e.onselectstart != "undefined") // IE
+ this.addEvent(e, "selectstart", disableTextSelectionHandler);
+
+ else // others
+ {
+ e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;";
+
+ // canceling the event in FF will prevent the menu popups to close when clicking over
+ // text-disabled elements
+ if (!this.isFirefox)
+ this.addEvent(e, "mousedown", disableTextSelectionHandler);
+ }
+
+ e.style.cursor = "default";
+};
+
+this.restoreTextSelection = function(e)
+{
+ if (typeof e.onselectstart != "undefined") // IE
+ this.removeEvent(e, "selectstart", disableTextSelectionHandler);
+
+ else // others
+ {
+ e.style.cssText = "cursor: default;";
+
+ // canceling the event in FF will prevent the menu popups to close when clicking over
+ // text-disabled elements
+ if (!this.isFirefox)
+ this.removeEvent(e, "mousedown", disableTextSelectionHandler);
+ }
+};
+
+// ************************************************************************************************
+// DOM Events
+
+var eventTypes =
+{
+ composition: [
+ "composition",
+ "compositionstart",
+ "compositionend" ],
+ contextmenu: [
+ "contextmenu" ],
+ drag: [
+ "dragenter",
+ "dragover",
+ "dragexit",
+ "dragdrop",
+ "draggesture" ],
+ focus: [
+ "focus",
+ "blur" ],
+ form: [
+ "submit",
+ "reset",
+ "change",
+ "select",
+ "input" ],
+ key: [
+ "keydown",
+ "keyup",
+ "keypress" ],
+ load: [
+ "load",
+ "beforeunload",
+ "unload",
+ "abort",
+ "error" ],
+ mouse: [
+ "mousedown",
+ "mouseup",
+ "click",
+ "dblclick",
+ "mouseover",
+ "mouseout",
+ "mousemove" ],
+ mutation: [
+ "DOMSubtreeModified",
+ "DOMNodeInserted",
+ "DOMNodeRemoved",
+ "DOMNodeRemovedFromDocument",
+ "DOMNodeInsertedIntoDocument",
+ "DOMAttrModified",
+ "DOMCharacterDataModified" ],
+ paint: [
+ "paint",
+ "resize",
+ "scroll" ],
+ scroll: [
+ "overflow",
+ "underflow",
+ "overflowchanged" ],
+ text: [
+ "text" ],
+ ui: [
+ "DOMActivate",
+ "DOMFocusIn",
+ "DOMFocusOut" ],
+ xul: [
+ "popupshowing",
+ "popupshown",
+ "popuphiding",
+ "popuphidden",
+ "close",
+ "command",
+ "broadcast",
+ "commandupdate" ]
+};
+
+this.getEventFamily = function(eventType)
+{
+ if (!this.families)
+ {
+ this.families = {};
+
+ for (var family in eventTypes)
+ {
+ var types = eventTypes[family];
+ for (var i = 0; i < types.length; ++i)
+ this.families[types[i]] = family;
+ }
+ }
+
+ return this.families[eventType];
+};
+
+
+// ************************************************************************************************
+// URLs
+
+this.getFileName = function(url)
+{
+ var split = this.splitURLBase(url);
+ return split.name;
+};
+
+this.splitURLBase = function(url)
+{
+ if (this.isDataURL(url))
+ return this.splitDataURL(url);
+ return this.splitURLTrue(url);
+};
+
+this.splitDataURL = function(url)
+{
+ var mark = url.indexOf(':', 3);
+ if (mark != 4)
+ return false; // the first 5 chars must be 'data:'
+
+ var point = url.indexOf(',', mark+1);
+ if (point < mark)
+ return false; // syntax error
+
+ var props = { encodedContent: url.substr(point+1) };
+
+ var metadataBuffer = url.substr(mark+1, point);
+ var metadata = metadataBuffer.split(';');
+ for (var i = 0; i < metadata.length; i++)
+ {
+ var nv = metadata[i].split('=');
+ if (nv.length == 2)
+ props[nv[0]] = nv[1];
+ }
+
+ // Additional Firebug-specific properties
+ if (props.hasOwnProperty('fileName'))
+ {
+ var caller_URL = decodeURIComponent(props['fileName']);
+ var caller_split = this.splitURLTrue(caller_URL);
+
+ if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval()
+ {
+ props['path'] = caller_split.path;
+ props['line'] = props['baseLineNumber'];
+ var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, "");
+ props['name'] = 'eval->'+hint;
+ }
+ else
+ {
+ props['name'] = caller_split.name;
+ props['path'] = caller_split.path;
+ }
+ }
+ else
+ {
+ if (!props.hasOwnProperty('path'))
+ props['path'] = "data:";
+ if (!props.hasOwnProperty('name'))
+ props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, "");
+ }
+
+ return props;
+};
+
+this.splitURLTrue = function(url)
+{
+ var m = reSplitFile.exec(url);
+ if (!m)
+ return {name: url, path: url};
+ else if (!m[2])
+ return {path: m[1], name: m[1]};
+ else
+ return {path: m[1], name: m[2]+m[3]};
+};
+
+this.getFileExtension = function(url)
+{
+ if (!url)
+ return null;
+
+ // Remove query string from the URL if any.
+ var queryString = url.indexOf("?");
+ if (queryString != -1)
+ url = url.substr(0, queryString);
+
+ // Now get the file extension.
+ var lastDot = url.lastIndexOf(".");
+ return url.substr(lastDot+1);
+};
+
+this.isSystemURL = function(url)
+{
+ if (!url) return true;
+ if (url.length == 0) return true;
+ if (url[0] == 'h') return false;
+ if (url.substr(0, 9) == "resource:")
+ return true;
+ else if (url.substr(0, 16) == "chrome://firebug")
+ return true;
+ else if (url == "XPCSafeJSObjectWrapper.cpp")
+ return true;
+ else if (url.substr(0, 6) == "about:")
+ return true;
+ else if (url.indexOf("firebug-service.js") != -1)
+ return true;
+ else
+ return false;
+};
+
+this.isSystemPage = function(win)
+{
+ try
+ {
+ var doc = win.document;
+ if (!doc)
+ return false;
+
+ // Detect pages for pretty printed XML
+ if ((doc.styleSheets.length && doc.styleSheets[0].href
+ == "chrome://global/content/xml/XMLPrettyPrint.css")
+ || (doc.styleSheets.length > 1 && doc.styleSheets[1].href
+ == "chrome://browser/skin/feeds/subscribe.css"))
+ return true;
+
+ return FBL.isSystemURL(win.location.href);
+ }
+ catch (exc)
+ {
+ // Sometimes documents just aren't ready to be manipulated here, but don't let that
+ // gum up the works
+ ERROR("tabWatcher.isSystemPage document not ready:"+ exc);
+ return false;
+ }
+};
+
+this.isSystemStyleSheet = function(sheet)
+{
+ var href = sheet && sheet.href;
+ return href && FBL.isSystemURL(href);
+};
+
+this.getURIHost = function(uri)
+{
+ try
+ {
+ if (uri)
+ return uri.host;
+ else
+ return "";
+ }
+ catch (exc)
+ {
+ return "";
+ }
+};
+
+this.isLocalURL = function(url)
+{
+ if (url.substr(0, 5) == "file:")
+ return true;
+ else if (url.substr(0, 8) == "wyciwyg:")
+ return true;
+ else
+ return false;
+};
+
+this.isDataURL = function(url)
+{
+ return (url && url.substr(0,5) == "data:");
+};
+
+this.getLocalPath = function(url)
+{
+ if (this.isLocalURL(url))
+ {
+ var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
+ var file = fileHandler.getFileFromURLSpec(url);
+ return file.path;
+ }
+};
+
+this.getURLFromLocalFile = function(file)
+{
+ var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
+ var URL = fileHandler.getURLSpecFromFile(file);
+ return URL;
+};
+
+this.getDataURLForContent = function(content, url)
+{
+ // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10,<the-url-encoded-data>
+ var uri = "data:text/html;";
+ uri += "fileName="+encodeURIComponent(url)+ ",";
+ uri += encodeURIComponent(content);
+ return uri;
+},
+
+this.getDomain = function(url)
+{
+ var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url);
+ return m ? m[1] : "";
+};
+
+this.getURLPath = function(url)
+{
+ var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url);
+ return m ? m[1] : "";
+};
+
+this.getPrettyDomain = function(url)
+{
+ var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url);
+ return m ? m[2] : "";
+};
+
+this.absoluteURL = function(url, baseURL)
+{
+ return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g");
+};
+
+this.absoluteURLWithDots = function(url, baseURL)
+{
+ if (url[0] == "?")
+ return baseURL + url;
+
+ var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/;
+ var m = reURL.exec(url);
+ if (m)
+ return url;
+
+ var m = reURL.exec(baseURL);
+ if (!m)
+ return "";
+
+ var head = m[1];
+ var tail = m[3];
+ if (url.substr(0, 2) == "//")
+ return m[2] + url;
+ else if (url[0] == "/")
+ {
+ return head + url;
+ }
+ else if (tail[tail.length-1] == "/")
+ return baseURL + url;
+ else
+ {
+ var parts = tail.split("/");
+ return head + parts.slice(0, parts.length-1).join("/") + "/" + url;
+ }
+};
+
+this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome
+{
+ if (!url)
+ return "";
+ // Replace one or more characters that are not forward-slash followed by /.., by space.
+ if (url.length < 255) // guard against monsters.
+ {
+ // Replace one or more characters that are not forward-slash followed by /.., by space.
+ url = url.replace(/[^\/]+\/\.\.\//, "", "g");
+ // Issue 1496, avoid #
+ url = url.replace(/#.*/,"");
+ // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they
+ // don't match up with the URLs we get back from the DOM
+ url = url.replace(/file:\/([^\/])/g, "file:///$1");
+ if (url.indexOf('chrome:')==0)
+ {
+ var m = reChromeCase.exec(url); // 1 is package name, 2 is path
+ if (m)
+ {
+ url = "chrome://"+m[1].toLowerCase()+"/"+m[2];
+ }
+ }
+ }
+ return url;
+};
+
+this.denormalizeURL = function(url)
+{
+ return url.replace(/file:\/\/\//g, "file:/");
+};
+
+this.parseURLParams = function(url)
+{
+ var q = url ? url.indexOf("?") : -1;
+ if (q == -1)
+ return [];
+
+ var search = url.substr(q+1);
+ var h = search.lastIndexOf("#");
+ if (h != -1)
+ search = search.substr(0, h);
+
+ if (!search)
+ return [];
+
+ return this.parseURLEncodedText(search);
+};
+
+this.parseURLEncodedText = function(text)
+{
+ var maxValueLength = 25000;
+
+ var params = [];
+
+ // Unescape '+' characters that are used to encode a space.
+ // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt
+ text = text.replace(/\+/g, " ");
+
+ var args = text.split("&");
+ for (var i = 0; i < args.length; ++i)
+ {
+ try {
+ var parts = args[i].split("=");
+ if (parts.length == 2)
+ {
+ if (parts[1].length > maxValueLength)
+ parts[1] = this.$STR("LargeData");
+
+ params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])});
+ }
+ else
+ params.push({name: decodeURIComponent(parts[0]), value: ""});
+ }
+ catch (e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.sysout("parseURLEncodedText EXCEPTION ", e);
+ FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]);
+ }
+ }
+ }
+
+ params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; });
+
+ return params;
+};
+
+// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters
+// as in response/request headers and get/post parameters in Net module?
+this.parseURLParamsArray = function(url)
+{
+ var q = url ? url.indexOf("?") : -1;
+ if (q == -1)
+ return [];
+
+ var search = url.substr(q+1);
+ var h = search.lastIndexOf("#");
+ if (h != -1)
+ search = search.substr(0, h);
+
+ if (!search)
+ return [];
+
+ return this.parseURLEncodedTextArray(search);
+};
+
+this.parseURLEncodedTextArray = function(text)
+{
+ var maxValueLength = 25000;
+
+ var params = [];
+
+ // Unescape '+' characters that are used to encode a space.
+ // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt
+ text = text.replace(/\+/g, " ");
+
+ var args = text.split("&");
+ for (var i = 0; i < args.length; ++i)
+ {
+ try {
+ var parts = args[i].split("=");
+ if (parts.length == 2)
+ {
+ if (parts[1].length > maxValueLength)
+ parts[1] = this.$STR("LargeData");
+
+ params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]});
+ }
+ else
+ params.push({name: decodeURIComponent(parts[0]), value: [""]});
+ }
+ catch (e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.sysout("parseURLEncodedText EXCEPTION ", e);
+ FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]);
+ }
+ }
+ }
+
+ params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; });
+
+ return params;
+};
+
+this.reEncodeURL = function(file, text)
+{
+ var lines = text.split("\n");
+ var params = this.parseURLEncodedText(lines[lines.length-1]);
+
+ var args = [];
+ for (var i = 0; i < params.length; ++i)
+ args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value));
+
+ var url = file.href;
+ url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&");
+
+ return url;
+};
+
+this.getResource = function(aURL)
+{
+ try
+ {
+ var channel=ioService.newChannel(aURL,null,null);
+ var input=channel.open();
+ return FBL.readFromStream(input);
+ }
+ catch (e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("lib.getResource FAILS for "+aURL, e);
+ }
+};
+
+this.parseJSONString = function(jsonString, originURL)
+{
+ // See if this is a Prototype style *-secure request.
+ var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/);
+ var matches = regex.exec(jsonString);
+
+ if (matches)
+ {
+ jsonString = matches[1];
+
+ if (jsonString[0] == "\\" && jsonString[1] == "n")
+ jsonString = jsonString.substr(2);
+
+ if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n")
+ jsonString = jsonString.substr(0, jsonString.length-2);
+ }
+
+ if (jsonString.indexOf("&&&START&&&"))
+ {
+ regex = new RegExp(/&&&START&&& (.+) &&&END&&&/);
+ matches = regex.exec(jsonString);
+ if (matches)
+ jsonString = matches[1];
+ }
+
+ // throw on the extra parentheses
+ jsonString = "(" + jsonString + ")";
+
+ ///var s = Components.utils.Sandbox(originURL);
+ var jsonObject = null;
+
+ try
+ {
+ ///jsonObject = Components.utils.evalInSandbox(jsonString, s);
+
+ //jsonObject = Firebug.context.eval(jsonString);
+ jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;});
+ }
+ catch(e)
+ {
+ /***
+ if (e.message.indexOf("is not defined"))
+ {
+ var parts = e.message.split(" ");
+ s[parts[0]] = function(str){ return str; };
+ try {
+ jsonObject = Components.utils.evalInSandbox(jsonString, s);
+ } catch(ex) {
+ if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER)
+ FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e);
+ return null;
+ }
+ }
+ else
+ {/**/
+ if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER)
+ FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e);
+ return null;
+ ///}
+ }
+
+ return jsonObject;
+};
+
+// ************************************************************************************************
+
+this.objectToString = function(object)
+{
+ try
+ {
+ return object+"";
+ }
+ catch (exc)
+ {
+ return null;
+ }
+};
+
+// ************************************************************************************************
+// Input Caret Position
+
+this.setSelectionRange = function(input, start, length)
+{
+ if (input.createTextRange)
+ {
+ var range = input.createTextRange();
+ range.moveStart("character", start);
+ range.moveEnd("character", length - input.value.length);
+ range.select();
+ }
+ else if (input.setSelectionRange)
+ {
+ input.setSelectionRange(start, length);
+ input.focus();
+ }
+};
+
+// ************************************************************************************************
+// Input Selection Start / Caret Position
+
+this.getInputSelectionStart = function(input)
+{
+ if (document.selection)
+ {
+ var range = input.ownerDocument.selection.createRange();
+ var text = range.text;
+
+ //console.log("range", range.text);
+
+ // if there is a selection, find the start position
+ if (text)
+ {
+ return input.value.indexOf(text);
+ }
+ // if there is no selection, find the caret position
+ else
+ {
+ range.moveStart("character", -input.value.length);
+
+ return range.text.length;
+ }
+ }
+ else if (typeof input.selectionStart != "undefined")
+ return input.selectionStart;
+
+ return 0;
+};
+
+// ************************************************************************************************
+// Opera Tab Fix
+
+function onOperaTabBlur(e)
+{
+ if (this.lastKey == 9)
+ this.focus();
+};
+
+function onOperaTabKeyDown(e)
+{
+ this.lastKey = e.keyCode;
+};
+
+function onOperaTabFocus(e)
+{
+ this.lastKey = null;
+};
+
+this.fixOperaTabKey = function(el)
+{
+ el.onfocus = onOperaTabFocus;
+ el.onblur = onOperaTabBlur;
+ el.onkeydown = onOperaTabKeyDown;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.Property = function(object, name)
+{
+ this.object = object;
+ this.name = name;
+
+ this.getObject = function()
+ {
+ return object[name];
+ };
+};
+
+this.ErrorCopy = function(message)
+{
+ this.message = message;
+};
+
+function EventCopy(event)
+{
+ // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to
+ // represent them long term in the inspector.
+ for (var name in event)
+ {
+ try {
+ this[name] = event[name];
+ } catch (exc) { }
+ }
+}
+
+this.EventCopy = EventCopy;
+
+
+// ************************************************************************************************
+// Type Checking
+
+var toString = Object.prototype.toString;
+var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/;
+
+this.isArray = function(object) {
+ return toString.call(object) === '[object Array]';
+};
+
+this.isFunction = function(object) {
+ if (!object) return false;
+
+ try
+ {
+ // FIXME: xxxpedro this is failing in IE for the global "external" object
+ return toString.call(object) === "[object Function]" ||
+ this.isIE && typeof object != "string" && reFunction.test(""+object);
+ }
+ catch (E)
+ {
+ FBTrace.sysout("Lib.isFunction() failed for ", object);
+ return false;
+ }
+};
+
+
+// ************************************************************************************************
+// Instance Checking
+
+this.instanceOf = function(object, className)
+{
+ if (!object || typeof object != "object")
+ return false;
+
+ // Try to use the native instanceof operator. We can only use it when we know
+ // exactly the window where the object is located at
+ if (object.ownerDocument)
+ {
+ // find the correct window of the object
+ var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow;
+
+ // if the class is accessible in the window, uses the native instanceof operator
+ // if the instanceof evaluates to "true" we can assume it is a instance, but if it
+ // evaluates to "false" we must continue with the duck type detection below because
+ // the native object may be extended, thus breaking the instanceof result
+ // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended
+ if (className in win && object instanceof win[className])
+ return true;
+ }
+ // If the object doesn't have the ownerDocument property, we'll try to look at
+ // the current context's window
+ else
+ {
+ // TODO: xxxpedro context
+ // Since we're not using yet a Firebug.context, we'll just use the top window
+ // (browser) as a reference
+ var win = Firebug.browser.window;
+ if (className in win)
+ return object instanceof win[className];
+ }
+
+ // get the duck type model from the cache
+ var cache = instanceCheckMap[className];
+ if (!cache)
+ return false;
+
+ // starts the hacky duck type detection
+ for(var n in cache)
+ {
+ var obj = cache[n];
+ var type = typeof obj;
+ obj = type == "object" ? obj : [obj];
+
+ for(var name in obj)
+ {
+ // avoid problems with extended native objects
+ // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended
+ if (!obj.hasOwnProperty(name))
+ continue;
+
+ var value = obj[name];
+
+ if( n == "property" && !(value in object) ||
+ n == "method" && !this.isFunction(object[value]) ||
+ n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() )
+ return false;
+ }
+ }
+
+ return true;
+};
+
+var instanceCheckMap =
+{
+ // DuckTypeCheck:
+ // {
+ // property: ["window", "document"],
+ // method: "setTimeout",
+ // value: {nodeType: 1}
+ // },
+
+ Window:
+ {
+ property: ["window", "document"],
+ method: "setTimeout"
+ },
+
+ Document:
+ {
+ property: ["body", "cookie"],
+ method: "getElementById"
+ },
+
+ Node:
+ {
+ property: "ownerDocument",
+ method: "appendChild"
+ },
+
+ Element:
+ {
+ property: "tagName",
+ value: {nodeType: 1}
+ },
+
+ Location:
+ {
+ property: ["hostname", "protocol"],
+ method: "assign"
+ },
+
+ HTMLImageElement:
+ {
+ property: "useMap",
+ value:
+ {
+ nodeType: 1,
+ tagName: "img"
+ }
+ },
+
+ HTMLAnchorElement:
+ {
+ property: "hreflang",
+ value:
+ {
+ nodeType: 1,
+ tagName: "a"
+ }
+ },
+
+ HTMLInputElement:
+ {
+ property: "form",
+ value:
+ {
+ nodeType: 1,
+ tagName: "input"
+ }
+ },
+
+ HTMLButtonElement:
+ {
+ // ?
+ },
+
+ HTMLFormElement:
+ {
+ method: "submit",
+ value:
+ {
+ nodeType: 1,
+ tagName: "form"
+ }
+ },
+
+ HTMLBodyElement:
+ {
+
+ },
+
+ HTMLHtmlElement:
+ {
+
+ },
+
+ CSSStyleRule:
+ {
+ property: ["selectorText", "style"]
+ }
+
+};
+
+
+// ************************************************************************************************
+// DOM Constants
+
+/*
+
+Problems:
+
+ - IE does not have window.Node, window.Element, etc
+ - for (var name in Node.prototype) return nothing on FF
+
+*/
+
+
+var domMemberMap2 = {};
+
+var domMemberMap2Sandbox = null;
+
+var getDomMemberMap2 = function(name)
+{
+ if (!domMemberMap2Sandbox)
+ {
+ var doc = Firebug.chrome.document;
+ var frame = doc.createElement("iframe");
+
+ frame.id = "FirebugSandbox";
+ frame.style.display = "none";
+ frame.src = "about:blank";
+
+ doc.body.appendChild(frame);
+
+ domMemberMap2Sandbox = frame.window || frame.contentWindow;
+ }
+
+ var props = [];
+
+ //var object = domMemberMap2Sandbox[name];
+ //object = object.prototype || object;
+
+ var object = null;
+
+ if (name == "Window")
+ object = domMemberMap2Sandbox.window;
+
+ else if (name == "Document")
+ object = domMemberMap2Sandbox.document;
+
+ else if (name == "HTMLScriptElement")
+ object = domMemberMap2Sandbox.document.createElement("script");
+
+ else if (name == "HTMLAnchorElement")
+ object = domMemberMap2Sandbox.document.createElement("a");
+
+ else if (name.indexOf("Element") != -1)
+ {
+ object = domMemberMap2Sandbox.document.createElement("div");
+ }
+
+ if (object)
+ {
+ //object = object.prototype || object;
+
+ //props = 'addEventListener,document,location,navigator,window'.split(',');
+
+ for (var n in object)
+ props.push(n);
+ }
+ /**/
+
+ return props;
+ return extendArray(props, domMemberMap[name]);
+};
+
+// xxxpedro experimental get DOM members
+this.getDOMMembers = function(object)
+{
+ if (!domMemberCache)
+ {
+ FBL.domMemberCache = domMemberCache = {};
+
+ for (var name in domMemberMap)
+ {
+ var builtins = getDomMemberMap2(name);
+ var cache = domMemberCache[name] = {};
+
+ /*
+ if (name.indexOf("Element") != -1)
+ {
+ this.append(cache, this.getDOMMembers("Node"));
+ this.append(cache, this.getDOMMembers("Element"));
+ }
+ /**/
+
+ for (var i = 0; i < builtins.length; ++i)
+ cache[builtins[i]] = i;
+ }
+ }
+
+ try
+ {
+ if (this.instanceOf(object, "Window"))
+ { return domMemberCache.Window; }
+ else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument"))
+ { return domMemberCache.Document; }
+ else if (this.instanceOf(object, "Location"))
+ { return domMemberCache.Location; }
+ else if (this.instanceOf(object, "HTMLImageElement"))
+ { return domMemberCache.HTMLImageElement; }
+ else if (this.instanceOf(object, "HTMLAnchorElement"))
+ { return domMemberCache.HTMLAnchorElement; }
+ else if (this.instanceOf(object, "HTMLInputElement"))
+ { return domMemberCache.HTMLInputElement; }
+ else if (this.instanceOf(object, "HTMLButtonElement"))
+ { return domMemberCache.HTMLButtonElement; }
+ else if (this.instanceOf(object, "HTMLFormElement"))
+ { return domMemberCache.HTMLFormElement; }
+ else if (this.instanceOf(object, "HTMLBodyElement"))
+ { return domMemberCache.HTMLBodyElement; }
+ else if (this.instanceOf(object, "HTMLHtmlElement"))
+ { return domMemberCache.HTMLHtmlElement; }
+ else if (this.instanceOf(object, "HTMLScriptElement"))
+ { return domMemberCache.HTMLScriptElement; }
+ else if (this.instanceOf(object, "HTMLTableElement"))
+ { return domMemberCache.HTMLTableElement; }
+ else if (this.instanceOf(object, "HTMLTableRowElement"))
+ { return domMemberCache.HTMLTableRowElement; }
+ else if (this.instanceOf(object, "HTMLTableCellElement"))
+ { return domMemberCache.HTMLTableCellElement; }
+ else if (this.instanceOf(object, "HTMLIFrameElement"))
+ { return domMemberCache.HTMLIFrameElement; }
+ else if (this.instanceOf(object, "SVGSVGElement"))
+ { return domMemberCache.SVGSVGElement; }
+ else if (this.instanceOf(object, "SVGElement"))
+ { return domMemberCache.SVGElement; }
+ else if (this.instanceOf(object, "Element"))
+ { return domMemberCache.Element; }
+ else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection"))
+ { return domMemberCache.Text; }
+ else if (this.instanceOf(object, "Attr"))
+ { return domMemberCache.Attr; }
+ else if (this.instanceOf(object, "Node"))
+ { return domMemberCache.Node; }
+ else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy"))
+ { return domMemberCache.Event; }
+ else
+ return {};
+ }
+ catch(E)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("lib.getDOMMembers FAILED ", E);
+
+ return {};
+ }
+};
+
+
+/*
+this.getDOMMembers = function(object)
+{
+ if (!domMemberCache)
+ {
+ domMemberCache = {};
+
+ for (var name in domMemberMap)
+ {
+ var builtins = domMemberMap[name];
+ var cache = domMemberCache[name] = {};
+
+ for (var i = 0; i < builtins.length; ++i)
+ cache[builtins[i]] = i;
+ }
+ }
+
+ try
+ {
+ if (this.instanceOf(object, "Window"))
+ { return domMemberCache.Window; }
+ else if (object instanceof Document || object instanceof XMLDocument)
+ { return domMemberCache.Document; }
+ else if (object instanceof Location)
+ { return domMemberCache.Location; }
+ else if (object instanceof HTMLImageElement)
+ { return domMemberCache.HTMLImageElement; }
+ else if (object instanceof HTMLAnchorElement)
+ { return domMemberCache.HTMLAnchorElement; }
+ else if (object instanceof HTMLInputElement)
+ { return domMemberCache.HTMLInputElement; }
+ else if (object instanceof HTMLButtonElement)
+ { return domMemberCache.HTMLButtonElement; }
+ else if (object instanceof HTMLFormElement)
+ { return domMemberCache.HTMLFormElement; }
+ else if (object instanceof HTMLBodyElement)
+ { return domMemberCache.HTMLBodyElement; }
+ else if (object instanceof HTMLHtmlElement)
+ { return domMemberCache.HTMLHtmlElement; }
+ else if (object instanceof HTMLScriptElement)
+ { return domMemberCache.HTMLScriptElement; }
+ else if (object instanceof HTMLTableElement)
+ { return domMemberCache.HTMLTableElement; }
+ else if (object instanceof HTMLTableRowElement)
+ { return domMemberCache.HTMLTableRowElement; }
+ else if (object instanceof HTMLTableCellElement)
+ { return domMemberCache.HTMLTableCellElement; }
+ else if (object instanceof HTMLIFrameElement)
+ { return domMemberCache.HTMLIFrameElement; }
+ else if (object instanceof SVGSVGElement)
+ { return domMemberCache.SVGSVGElement; }
+ else if (object instanceof SVGElement)
+ { return domMemberCache.SVGElement; }
+ else if (object instanceof Element)
+ { return domMemberCache.Element; }
+ else if (object instanceof Text || object instanceof CDATASection)
+ { return domMemberCache.Text; }
+ else if (object instanceof Attr)
+ { return domMemberCache.Attr; }
+ else if (object instanceof Node)
+ { return domMemberCache.Node; }
+ else if (object instanceof Event || object instanceof EventCopy)
+ { return domMemberCache.Event; }
+ else
+ return {};
+ }
+ catch(E)
+ {
+ return {};
+ }
+};
+/**/
+
+this.isDOMMember = function(object, propName)
+{
+ var members = this.getDOMMembers(object);
+ return members && propName in members;
+};
+
+var domMemberCache = null;
+var domMemberMap = {};
+
+domMemberMap.Window =
+[
+ "document",
+ "frameElement",
+
+ "innerWidth",
+ "innerHeight",
+ "outerWidth",
+ "outerHeight",
+ "screenX",
+ "screenY",
+ "pageXOffset",
+ "pageYOffset",
+ "scrollX",
+ "scrollY",
+ "scrollMaxX",
+ "scrollMaxY",
+
+ "status",
+ "defaultStatus",
+
+ "parent",
+ "opener",
+ "top",
+ "window",
+ "content",
+ "self",
+
+ "location",
+ "history",
+ "frames",
+ "navigator",
+ "screen",
+ "menubar",
+ "toolbar",
+ "locationbar",
+ "personalbar",
+ "statusbar",
+ "directories",
+ "scrollbars",
+ "fullScreen",
+ "netscape",
+ "java",
+ "console",
+ "Components",
+ "controllers",
+ "closed",
+ "crypto",
+ "pkcs11",
+
+ "name",
+ "property",
+ "length",
+
+ "sessionStorage",
+ "globalStorage",
+
+ "setTimeout",
+ "setInterval",
+ "clearTimeout",
+ "clearInterval",
+ "addEventListener",
+ "removeEventListener",
+ "dispatchEvent",
+ "getComputedStyle",
+ "captureEvents",
+ "releaseEvents",
+ "routeEvent",
+ "enableExternalCapture",
+ "disableExternalCapture",
+ "moveTo",
+ "moveBy",
+ "resizeTo",
+ "resizeBy",
+ "scroll",
+ "scrollTo",
+ "scrollBy",
+ "scrollByLines",
+ "scrollByPages",
+ "sizeToContent",
+ "setResizable",
+ "getSelection",
+ "open",
+ "openDialog",
+ "close",
+ "alert",
+ "confirm",
+ "prompt",
+ "dump",
+ "focus",
+ "blur",
+ "find",
+ "back",
+ "forward",
+ "home",
+ "stop",
+ "print",
+ "atob",
+ "btoa",
+ "updateCommands",
+ "XPCNativeWrapper",
+ "GeckoActiveXObject",
+ "applicationCache" // FF3
+];
+
+domMemberMap.Location =
+[
+ "href",
+ "protocol",
+ "host",
+ "hostname",
+ "port",
+ "pathname",
+ "search",
+ "hash",
+
+ "assign",
+ "reload",
+ "replace"
+];
+
+domMemberMap.Node =
+[
+ "id",
+ "className",
+
+ "nodeType",
+ "tagName",
+ "nodeName",
+ "localName",
+ "prefix",
+ "namespaceURI",
+ "nodeValue",
+
+ "ownerDocument",
+ "parentNode",
+ "offsetParent",
+ "nextSibling",
+ "previousSibling",
+ "firstChild",
+ "lastChild",
+ "childNodes",
+ "attributes",
+
+ "dir",
+ "baseURI",
+ "textContent",
+ "innerHTML",
+
+ "addEventListener",
+ "removeEventListener",
+ "dispatchEvent",
+ "cloneNode",
+ "appendChild",
+ "insertBefore",
+ "replaceChild",
+ "removeChild",
+ "compareDocumentPosition",
+ "hasAttributes",
+ "hasChildNodes",
+ "lookupNamespaceURI",
+ "lookupPrefix",
+ "normalize",
+ "isDefaultNamespace",
+ "isEqualNode",
+ "isSameNode",
+ "isSupported",
+ "getFeature",
+ "getUserData",
+ "setUserData"
+];
+
+domMemberMap.Document = extendArray(domMemberMap.Node,
+[
+ "documentElement",
+ "body",
+ "title",
+ "location",
+ "referrer",
+ "cookie",
+ "contentType",
+ "lastModified",
+ "characterSet",
+ "inputEncoding",
+ "xmlEncoding",
+ "xmlStandalone",
+ "xmlVersion",
+ "strictErrorChecking",
+ "documentURI",
+ "URL",
+
+ "defaultView",
+ "doctype",
+ "implementation",
+ "styleSheets",
+ "images",
+ "links",
+ "forms",
+ "anchors",
+ "embeds",
+ "plugins",
+ "applets",
+
+ "width",
+ "height",
+
+ "designMode",
+ "compatMode",
+ "async",
+ "preferredStylesheetSet",
+
+ "alinkColor",
+ "linkColor",
+ "vlinkColor",
+ "bgColor",
+ "fgColor",
+ "domain",
+
+ "addEventListener",
+ "removeEventListener",
+ "dispatchEvent",
+ "captureEvents",
+ "releaseEvents",
+ "routeEvent",
+ "clear",
+ "open",
+ "close",
+ "execCommand",
+ "execCommandShowHelp",
+ "getElementsByName",
+ "getSelection",
+ "queryCommandEnabled",
+ "queryCommandIndeterm",
+ "queryCommandState",
+ "queryCommandSupported",
+ "queryCommandText",
+ "queryCommandValue",
+ "write",
+ "writeln",
+ "adoptNode",
+ "appendChild",
+ "removeChild",
+ "renameNode",
+ "cloneNode",
+ "compareDocumentPosition",
+ "createAttribute",
+ "createAttributeNS",
+ "createCDATASection",
+ "createComment",
+ "createDocumentFragment",
+ "createElement",
+ "createElementNS",
+ "createEntityReference",
+ "createEvent",
+ "createExpression",
+ "createNSResolver",
+ "createNodeIterator",
+ "createProcessingInstruction",
+ "createRange",
+ "createTextNode",
+ "createTreeWalker",
+ "domConfig",
+ "evaluate",
+ "evaluateFIXptr",
+ "evaluateXPointer",
+ "getAnonymousElementByAttribute",
+ "getAnonymousNodes",
+ "addBinding",
+ "removeBinding",
+ "getBindingParent",
+ "getBoxObjectFor",
+ "setBoxObjectFor",
+ "getElementById",
+ "getElementsByTagName",
+ "getElementsByTagNameNS",
+ "hasAttributes",
+ "hasChildNodes",
+ "importNode",
+ "insertBefore",
+ "isDefaultNamespace",
+ "isEqualNode",
+ "isSameNode",
+ "isSupported",
+ "load",
+ "loadBindingDocument",
+ "lookupNamespaceURI",
+ "lookupPrefix",
+ "normalize",
+ "normalizeDocument",
+ "getFeature",
+ "getUserData",
+ "setUserData"
+]);
+
+domMemberMap.Element = extendArray(domMemberMap.Node,
+[
+ "clientWidth",
+ "clientHeight",
+ "offsetLeft",
+ "offsetTop",
+ "offsetWidth",
+ "offsetHeight",
+ "scrollLeft",
+ "scrollTop",
+ "scrollWidth",
+ "scrollHeight",
+
+ "style",
+
+ "tabIndex",
+ "title",
+ "lang",
+ "align",
+ "spellcheck",
+
+ "addEventListener",
+ "removeEventListener",
+ "dispatchEvent",
+ "focus",
+ "blur",
+ "cloneNode",
+ "appendChild",
+ "insertBefore",
+ "replaceChild",
+ "removeChild",
+ "compareDocumentPosition",
+ "getElementsByTagName",
+ "getElementsByTagNameNS",
+ "getAttribute",
+ "getAttributeNS",
+ "getAttributeNode",
+ "getAttributeNodeNS",
+ "setAttribute",
+ "setAttributeNS",
+ "setAttributeNode",
+ "setAttributeNodeNS",
+ "removeAttribute",
+ "removeAttributeNS",
+ "removeAttributeNode",
+ "hasAttribute",
+ "hasAttributeNS",
+ "hasAttributes",
+ "hasChildNodes",
+ "lookupNamespaceURI",
+ "lookupPrefix",
+ "normalize",
+ "isDefaultNamespace",
+ "isEqualNode",
+ "isSameNode",
+ "isSupported",
+ "getFeature",
+ "getUserData",
+ "setUserData"
+]);
+
+domMemberMap.SVGElement = extendArray(domMemberMap.Element,
+[
+ "x",
+ "y",
+ "width",
+ "height",
+ "rx",
+ "ry",
+ "transform",
+ "href",
+
+ "ownerSVGElement",
+ "viewportElement",
+ "farthestViewportElement",
+ "nearestViewportElement",
+
+ "getBBox",
+ "getCTM",
+ "getScreenCTM",
+ "getTransformToElement",
+ "getPresentationAttribute",
+ "preserveAspectRatio"
+]);
+
+domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element,
+[
+ "x",
+ "y",
+ "width",
+ "height",
+ "rx",
+ "ry",
+ "transform",
+
+ "viewBox",
+ "viewport",
+ "currentView",
+ "useCurrentView",
+ "pixelUnitToMillimeterX",
+ "pixelUnitToMillimeterY",
+ "screenPixelToMillimeterX",
+ "screenPixelToMillimeterY",
+ "currentScale",
+ "currentTranslate",
+ "zoomAndPan",
+
+ "ownerSVGElement",
+ "viewportElement",
+ "farthestViewportElement",
+ "nearestViewportElement",
+ "contentScriptType",
+ "contentStyleType",
+
+ "getBBox",
+ "getCTM",
+ "getScreenCTM",
+ "getTransformToElement",
+ "getEnclosureList",
+ "getIntersectionList",
+ "getViewboxToViewportTransform",
+ "getPresentationAttribute",
+ "getElementById",
+ "checkEnclosure",
+ "checkIntersection",
+ "createSVGAngle",
+ "createSVGLength",
+ "createSVGMatrix",
+ "createSVGNumber",
+ "createSVGPoint",
+ "createSVGRect",
+ "createSVGString",
+ "createSVGTransform",
+ "createSVGTransformFromMatrix",
+ "deSelectAll",
+ "preserveAspectRatio",
+ "forceRedraw",
+ "suspendRedraw",
+ "unsuspendRedraw",
+ "unsuspendRedrawAll",
+ "getCurrentTime",
+ "setCurrentTime",
+ "animationsPaused",
+ "pauseAnimations",
+ "unpauseAnimations"
+]);
+
+domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element,
+[
+ "src",
+ "naturalWidth",
+ "naturalHeight",
+ "width",
+ "height",
+ "x",
+ "y",
+ "name",
+ "alt",
+ "longDesc",
+ "lowsrc",
+ "border",
+ "complete",
+ "hspace",
+ "vspace",
+ "isMap",
+ "useMap"
+]);
+
+domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element,
+[
+ "name",
+ "target",
+ "accessKey",
+ "href",
+ "protocol",
+ "host",
+ "hostname",
+ "port",
+ "pathname",
+ "search",
+ "hash",
+ "hreflang",
+ "coords",
+ "shape",
+ "text",
+ "type",
+ "rel",
+ "rev",
+ "charset"
+]);
+
+domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element,
+[
+ "contentDocument",
+ "contentWindow",
+ "frameBorder",
+ "height",
+ "longDesc",
+ "marginHeight",
+ "marginWidth",
+ "name",
+ "scrolling",
+ "src",
+ "width"
+]);
+
+domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element,
+[
+ "bgColor",
+ "border",
+ "caption",
+ "cellPadding",
+ "cellSpacing",
+ "frame",
+ "rows",
+ "rules",
+ "summary",
+ "tBodies",
+ "tFoot",
+ "tHead",
+ "width",
+
+ "createCaption",
+ "createTFoot",
+ "createTHead",
+ "deleteCaption",
+ "deleteRow",
+ "deleteTFoot",
+ "deleteTHead",
+ "insertRow"
+]);
+
+domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element,
+[
+ "bgColor",
+ "cells",
+ "ch",
+ "chOff",
+ "rowIndex",
+ "sectionRowIndex",
+ "vAlign",
+
+ "deleteCell",
+ "insertCell"
+]);
+
+domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element,
+[
+ "abbr",
+ "axis",
+ "bgColor",
+ "cellIndex",
+ "ch",
+ "chOff",
+ "colSpan",
+ "headers",
+ "height",
+ "noWrap",
+ "rowSpan",
+ "scope",
+ "vAlign",
+ "width"
+
+]);
+
+domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element,
+[
+ "src"
+]);
+
+domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element,
+[
+ "accessKey",
+ "disabled",
+ "form",
+ "name",
+ "type",
+ "value",
+
+ "click"
+]);
+
+domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element,
+[
+ "type",
+ "value",
+ "checked",
+ "accept",
+ "accessKey",
+ "alt",
+ "controllers",
+ "defaultChecked",
+ "defaultValue",
+ "disabled",
+ "form",
+ "maxLength",
+ "name",
+ "readOnly",
+ "selectionEnd",
+ "selectionStart",
+ "size",
+ "src",
+ "textLength",
+ "useMap",
+
+ "click",
+ "select",
+ "setSelectionRange"
+]);
+
+domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element,
+[
+ "acceptCharset",
+ "action",
+ "author",
+ "elements",
+ "encoding",
+ "enctype",
+ "entry_id",
+ "length",
+ "method",
+ "name",
+ "post",
+ "target",
+ "text",
+ "url",
+
+ "reset",
+ "submit"
+]);
+
+domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element,
+[
+ "aLink",
+ "background",
+ "bgColor",
+ "link",
+ "text",
+ "vLink"
+]);
+
+domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element,
+[
+ "version"
+]);
+
+domMemberMap.Text = extendArray(domMemberMap.Node,
+[
+ "data",
+ "length",
+
+ "appendData",
+ "deleteData",
+ "insertData",
+ "replaceData",
+ "splitText",
+ "substringData"
+]);
+
+domMemberMap.Attr = extendArray(domMemberMap.Node,
+[
+ "name",
+ "value",
+ "specified",
+ "ownerElement"
+]);
+
+domMemberMap.Event =
+[
+ "type",
+ "target",
+ "currentTarget",
+ "originalTarget",
+ "explicitOriginalTarget",
+ "relatedTarget",
+ "rangeParent",
+ "rangeOffset",
+ "view",
+
+ "keyCode",
+ "charCode",
+ "screenX",
+ "screenY",
+ "clientX",
+ "clientY",
+ "layerX",
+ "layerY",
+ "pageX",
+ "pageY",
+
+ "detail",
+ "button",
+ "which",
+ "ctrlKey",
+ "shiftKey",
+ "altKey",
+ "metaKey",
+
+ "eventPhase",
+ "timeStamp",
+ "bubbles",
+ "cancelable",
+ "cancelBubble",
+
+ "isTrusted",
+ "isChar",
+
+ "getPreventDefault",
+ "initEvent",
+ "initMouseEvent",
+ "initKeyEvent",
+ "initUIEvent",
+ "preventBubble",
+ "preventCapture",
+ "preventDefault",
+ "stopPropagation"
+];
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.domConstantMap =
+{
+ "ELEMENT_NODE": 1,
+ "ATTRIBUTE_NODE": 1,
+ "TEXT_NODE": 1,
+ "CDATA_SECTION_NODE": 1,
+ "ENTITY_REFERENCE_NODE": 1,
+ "ENTITY_NODE": 1,
+ "PROCESSING_INSTRUCTION_NODE": 1,
+ "COMMENT_NODE": 1,
+ "DOCUMENT_NODE": 1,
+ "DOCUMENT_TYPE_NODE": 1,
+ "DOCUMENT_FRAGMENT_NODE": 1,
+ "NOTATION_NODE": 1,
+
+ "DOCUMENT_POSITION_DISCONNECTED": 1,
+ "DOCUMENT_POSITION_PRECEDING": 1,
+ "DOCUMENT_POSITION_FOLLOWING": 1,
+ "DOCUMENT_POSITION_CONTAINS": 1,
+ "DOCUMENT_POSITION_CONTAINED_BY": 1,
+ "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1,
+
+ "UNKNOWN_RULE": 1,
+ "STYLE_RULE": 1,
+ "CHARSET_RULE": 1,
+ "IMPORT_RULE": 1,
+ "MEDIA_RULE": 1,
+ "FONT_FACE_RULE": 1,
+ "PAGE_RULE": 1,
+
+ "CAPTURING_PHASE": 1,
+ "AT_TARGET": 1,
+ "BUBBLING_PHASE": 1,
+
+ "SCROLL_PAGE_UP": 1,
+ "SCROLL_PAGE_DOWN": 1,
+
+ "MOUSEUP": 1,
+ "MOUSEDOWN": 1,
+ "MOUSEOVER": 1,
+ "MOUSEOUT": 1,
+ "MOUSEMOVE": 1,
+ "MOUSEDRAG": 1,
+ "CLICK": 1,
+ "DBLCLICK": 1,
+ "KEYDOWN": 1,
+ "KEYUP": 1,
+ "KEYPRESS": 1,
+ "DRAGDROP": 1,
+ "FOCUS": 1,
+ "BLUR": 1,
+ "SELECT": 1,
+ "CHANGE": 1,
+ "RESET": 1,
+ "SUBMIT": 1,
+ "SCROLL": 1,
+ "LOAD": 1,
+ "UNLOAD": 1,
+ "XFER_DONE": 1,
+ "ABORT": 1,
+ "ERROR": 1,
+ "LOCATE": 1,
+ "MOVE": 1,
+ "RESIZE": 1,
+ "FORWARD": 1,
+ "HELP": 1,
+ "BACK": 1,
+ "TEXT": 1,
+
+ "ALT_MASK": 1,
+ "CONTROL_MASK": 1,
+ "SHIFT_MASK": 1,
+ "META_MASK": 1,
+
+ "DOM_VK_TAB": 1,
+ "DOM_VK_PAGE_UP": 1,
+ "DOM_VK_PAGE_DOWN": 1,
+ "DOM_VK_UP": 1,
+ "DOM_VK_DOWN": 1,
+ "DOM_VK_LEFT": 1,
+ "DOM_VK_RIGHT": 1,
+ "DOM_VK_CANCEL": 1,
+ "DOM_VK_HELP": 1,
+ "DOM_VK_BACK_SPACE": 1,
+ "DOM_VK_CLEAR": 1,
+ "DOM_VK_RETURN": 1,
+ "DOM_VK_ENTER": 1,
+ "DOM_VK_SHIFT": 1,
+ "DOM_VK_CONTROL": 1,
+ "DOM_VK_ALT": 1,
+ "DOM_VK_PAUSE": 1,
+ "DOM_VK_CAPS_LOCK": 1,
+ "DOM_VK_ESCAPE": 1,
+ "DOM_VK_SPACE": 1,
+ "DOM_VK_END": 1,
+ "DOM_VK_HOME": 1,
+ "DOM_VK_PRINTSCREEN": 1,
+ "DOM_VK_INSERT": 1,
+ "DOM_VK_DELETE": 1,
+ "DOM_VK_0": 1,
+ "DOM_VK_1": 1,
+ "DOM_VK_2": 1,
+ "DOM_VK_3": 1,
+ "DOM_VK_4": 1,
+ "DOM_VK_5": 1,
+ "DOM_VK_6": 1,
+ "DOM_VK_7": 1,
+ "DOM_VK_8": 1,
+ "DOM_VK_9": 1,
+ "DOM_VK_SEMICOLON": 1,
+ "DOM_VK_EQUALS": 1,
+ "DOM_VK_A": 1,
+ "DOM_VK_B": 1,
+ "DOM_VK_C": 1,
+ "DOM_VK_D": 1,
+ "DOM_VK_E": 1,
+ "DOM_VK_F": 1,
+ "DOM_VK_G": 1,
+ "DOM_VK_H": 1,
+ "DOM_VK_I": 1,
+ "DOM_VK_J": 1,
+ "DOM_VK_K": 1,
+ "DOM_VK_L": 1,
+ "DOM_VK_M": 1,
+ "DOM_VK_N": 1,
+ "DOM_VK_O": 1,
+ "DOM_VK_P": 1,
+ "DOM_VK_Q": 1,
+ "DOM_VK_R": 1,
+ "DOM_VK_S": 1,
+ "DOM_VK_T": 1,
+ "DOM_VK_U": 1,
+ "DOM_VK_V": 1,
+ "DOM_VK_W": 1,
+ "DOM_VK_X": 1,
+ "DOM_VK_Y": 1,
+ "DOM_VK_Z": 1,
+ "DOM_VK_CONTEXT_MENU": 1,
+ "DOM_VK_NUMPAD0": 1,
+ "DOM_VK_NUMPAD1": 1,
+ "DOM_VK_NUMPAD2": 1,
+ "DOM_VK_NUMPAD3": 1,
+ "DOM_VK_NUMPAD4": 1,
+ "DOM_VK_NUMPAD5": 1,
+ "DOM_VK_NUMPAD6": 1,
+ "DOM_VK_NUMPAD7": 1,
+ "DOM_VK_NUMPAD8": 1,
+ "DOM_VK_NUMPAD9": 1,
+ "DOM_VK_MULTIPLY": 1,
+ "DOM_VK_ADD": 1,
+ "DOM_VK_SEPARATOR": 1,
+ "DOM_VK_SUBTRACT": 1,
+ "DOM_VK_DECIMAL": 1,
+ "DOM_VK_DIVIDE": 1,
+ "DOM_VK_F1": 1,
+ "DOM_VK_F2": 1,
+ "DOM_VK_F3": 1,
+ "DOM_VK_F4": 1,
+ "DOM_VK_F5": 1,
+ "DOM_VK_F6": 1,
+ "DOM_VK_F7": 1,
+ "DOM_VK_F8": 1,
+ "DOM_VK_F9": 1,
+ "DOM_VK_F10": 1,
+ "DOM_VK_F11": 1,
+ "DOM_VK_F12": 1,
+ "DOM_VK_F13": 1,
+ "DOM_VK_F14": 1,
+ "DOM_VK_F15": 1,
+ "DOM_VK_F16": 1,
+ "DOM_VK_F17": 1,
+ "DOM_VK_F18": 1,
+ "DOM_VK_F19": 1,
+ "DOM_VK_F20": 1,
+ "DOM_VK_F21": 1,
+ "DOM_VK_F22": 1,
+ "DOM_VK_F23": 1,
+ "DOM_VK_F24": 1,
+ "DOM_VK_NUM_LOCK": 1,
+ "DOM_VK_SCROLL_LOCK": 1,
+ "DOM_VK_COMMA": 1,
+ "DOM_VK_PERIOD": 1,
+ "DOM_VK_SLASH": 1,
+ "DOM_VK_BACK_QUOTE": 1,
+ "DOM_VK_OPEN_BRACKET": 1,
+ "DOM_VK_BACK_SLASH": 1,
+ "DOM_VK_CLOSE_BRACKET": 1,
+ "DOM_VK_QUOTE": 1,
+ "DOM_VK_META": 1,
+
+ "SVG_ZOOMANDPAN_DISABLE": 1,
+ "SVG_ZOOMANDPAN_MAGNIFY": 1,
+ "SVG_ZOOMANDPAN_UNKNOWN": 1
+};
+
+this.cssInfo =
+{
+ "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"],
+ "background-attachment": ["bgAttachment"],
+ "background-color": ["color", "systemColor"],
+ "background-image": ["none"],
+ "background-position": ["bgPosition"],
+ "background-repeat": ["bgRepeat"],
+
+ "border": ["borderStyle", "thickness", "color", "systemColor", "none"],
+ "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
+ "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
+ "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
+ "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
+ "border-collapse": ["borderCollapse"],
+ "border-color": ["color", "systemColor"],
+ "border-top-color": ["color", "systemColor"],
+ "border-right-color": ["color", "systemColor"],
+ "border-bottom-color": ["color", "systemColor"],
+ "border-left-color": ["color", "systemColor"],
+ "border-spacing": [],
+ "border-style": ["borderStyle"],
+ "border-top-style": ["borderStyle"],
+ "border-right-style": ["borderStyle"],
+ "border-bottom-style": ["borderStyle"],
+ "border-left-style": ["borderStyle"],
+ "border-width": ["thickness"],
+ "border-top-width": ["thickness"],
+ "border-right-width": ["thickness"],
+ "border-bottom-width": ["thickness"],
+ "border-left-width": ["thickness"],
+
+ "bottom": ["auto"],
+ "caption-side": ["captionSide"],
+ "clear": ["clear", "none"],
+ "clip": ["auto"],
+ "color": ["color", "systemColor"],
+ "content": ["content"],
+ "counter-increment": ["none"],
+ "counter-reset": ["none"],
+ "cursor": ["cursor", "none"],
+ "direction": ["direction"],
+ "display": ["display", "none"],
+ "empty-cells": [],
+ "float": ["float", "none"],
+ "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"],
+
+ "font-family": ["fontFamily"],
+ "font-size": ["fontSize"],
+ "font-size-adjust": [],
+ "font-stretch": [],
+ "font-style": ["fontStyle"],
+ "font-variant": ["fontVariant"],
+ "font-weight": ["fontWeight"],
+
+ "height": ["auto"],
+ "left": ["auto"],
+ "letter-spacing": [],
+ "line-height": [],
+
+ "list-style": ["listStyleType", "listStylePosition", "none"],
+ "list-style-image": ["none"],
+ "list-style-position": ["listStylePosition"],
+ "list-style-type": ["listStyleType", "none"],
+
+ "margin": [],
+ "margin-top": [],
+ "margin-right": [],
+ "margin-bottom": [],
+ "margin-left": [],
+
+ "marker-offset": ["auto"],
+ "min-height": ["none"],
+ "max-height": ["none"],
+ "min-width": ["none"],
+ "max-width": ["none"],
+
+ "outline": ["borderStyle", "color", "systemColor", "none"],
+ "outline-color": ["color", "systemColor"],
+ "outline-style": ["borderStyle"],
+ "outline-width": [],
+
+ "overflow": ["overflow", "auto"],
+ "overflow-x": ["overflow", "auto"],
+ "overflow-y": ["overflow", "auto"],
+
+ "padding": [],
+ "padding-top": [],
+ "padding-right": [],
+ "padding-bottom": [],
+ "padding-left": [],
+
+ "position": ["position"],
+ "quotes": ["none"],
+ "right": ["auto"],
+ "table-layout": ["tableLayout", "auto"],
+ "text-align": ["textAlign"],
+ "text-decoration": ["textDecoration", "none"],
+ "text-indent": [],
+ "text-shadow": [],
+ "text-transform": ["textTransform", "none"],
+ "top": ["auto"],
+ "unicode-bidi": [],
+ "vertical-align": ["verticalAlign"],
+ "white-space": ["whiteSpace"],
+ "width": ["auto"],
+ "word-spacing": [],
+ "z-index": [],
+
+ "-moz-appearance": ["mozAppearance"],
+ "-moz-border-radius": [],
+ "-moz-border-radius-bottomleft": [],
+ "-moz-border-radius-bottomright": [],
+ "-moz-border-radius-topleft": [],
+ "-moz-border-radius-topright": [],
+ "-moz-border-top-colors": ["color", "systemColor"],
+ "-moz-border-right-colors": ["color", "systemColor"],
+ "-moz-border-bottom-colors": ["color", "systemColor"],
+ "-moz-border-left-colors": ["color", "systemColor"],
+ "-moz-box-align": ["mozBoxAlign"],
+ "-moz-box-direction": ["mozBoxDirection"],
+ "-moz-box-flex": [],
+ "-moz-box-ordinal-group": [],
+ "-moz-box-orient": ["mozBoxOrient"],
+ "-moz-box-pack": ["mozBoxPack"],
+ "-moz-box-sizing": ["mozBoxSizing"],
+ "-moz-opacity": [],
+ "-moz-user-focus": ["userFocus", "none"],
+ "-moz-user-input": ["userInput"],
+ "-moz-user-modify": [],
+ "-moz-user-select": ["userSelect", "none"],
+ "-moz-background-clip": [],
+ "-moz-background-inline-policy": [],
+ "-moz-background-origin": [],
+ "-moz-binding": [],
+ "-moz-column-count": [],
+ "-moz-column-gap": [],
+ "-moz-column-width": [],
+ "-moz-image-region": []
+};
+
+this.inheritedStyleNames =
+{
+ "border-collapse": 1,
+ "border-spacing": 1,
+ "border-style": 1,
+ "caption-side": 1,
+ "color": 1,
+ "cursor": 1,
+ "direction": 1,
+ "empty-cells": 1,
+ "font": 1,
+ "font-family": 1,
+ "font-size-adjust": 1,
+ "font-size": 1,
+ "font-style": 1,
+ "font-variant": 1,
+ "font-weight": 1,
+ "letter-spacing": 1,
+ "line-height": 1,
+ "list-style": 1,
+ "list-style-image": 1,
+ "list-style-position": 1,
+ "list-style-type": 1,
+ "quotes": 1,
+ "text-align": 1,
+ "text-decoration": 1,
+ "text-indent": 1,
+ "text-shadow": 1,
+ "text-transform": 1,
+ "white-space": 1,
+ "word-spacing": 1
+};
+
+this.cssKeywords =
+{
+ "appearance":
+ [
+ "button",
+ "button-small",
+ "checkbox",
+ "checkbox-container",
+ "checkbox-small",
+ "dialog",
+ "listbox",
+ "menuitem",
+ "menulist",
+ "menulist-button",
+ "menulist-textfield",
+ "menupopup",
+ "progressbar",
+ "radio",
+ "radio-container",
+ "radio-small",
+ "resizer",
+ "scrollbar",
+ "scrollbarbutton-down",
+ "scrollbarbutton-left",
+ "scrollbarbutton-right",
+ "scrollbarbutton-up",
+ "scrollbartrack-horizontal",
+ "scrollbartrack-vertical",
+ "separator",
+ "statusbar",
+ "tab",
+ "tab-left-edge",
+ "tabpanels",
+ "textfield",
+ "toolbar",
+ "toolbarbutton",
+ "toolbox",
+ "tooltip",
+ "treeheadercell",
+ "treeheadersortarrow",
+ "treeitem",
+ "treetwisty",
+ "treetwistyopen",
+ "treeview",
+ "window"
+ ],
+
+ "systemColor":
+ [
+ "ActiveBorder",
+ "ActiveCaption",
+ "AppWorkspace",
+ "Background",
+ "ButtonFace",
+ "ButtonHighlight",
+ "ButtonShadow",
+ "ButtonText",
+ "CaptionText",
+ "GrayText",
+ "Highlight",
+ "HighlightText",
+ "InactiveBorder",
+ "InactiveCaption",
+ "InactiveCaptionText",
+ "InfoBackground",
+ "InfoText",
+ "Menu",
+ "MenuText",
+ "Scrollbar",
+ "ThreeDDarkShadow",
+ "ThreeDFace",
+ "ThreeDHighlight",
+ "ThreeDLightShadow",
+ "ThreeDShadow",
+ "Window",
+ "WindowFrame",
+ "WindowText",
+ "-moz-field",
+ "-moz-fieldtext",
+ "-moz-workspace",
+ "-moz-visitedhyperlinktext",
+ "-moz-use-text-color"
+ ],
+
+ "color":
+ [
+ "AliceBlue",
+ "AntiqueWhite",
+ "Aqua",
+ "Aquamarine",
+ "Azure",
+ "Beige",
+ "Bisque",
+ "Black",
+ "BlanchedAlmond",
+ "Blue",
+ "BlueViolet",
+ "Brown",
+ "BurlyWood",
+ "CadetBlue",
+ "Chartreuse",
+ "Chocolate",
+ "Coral",
+ "CornflowerBlue",
+ "Cornsilk",
+ "Crimson",
+ "Cyan",
+ "DarkBlue",
+ "DarkCyan",
+ "DarkGoldenRod",
+ "DarkGray",
+ "DarkGreen",
+ "DarkKhaki",
+ "DarkMagenta",
+ "DarkOliveGreen",
+ "DarkOrange",
+ "DarkOrchid",
+ "DarkRed",
+ "DarkSalmon",
+ "DarkSeaGreen",
+ "DarkSlateBlue",
+ "DarkSlateGray",
+ "DarkTurquoise",
+ "DarkViolet",
+ "DeepPink",
+ "DarkSkyBlue",
+ "DimGray",
+ "DodgerBlue",
+ "Feldspar",
+ "FireBrick",
+ "FloralWhite",
+ "ForestGreen",
+ "Fuchsia",
+ "Gainsboro",
+ "GhostWhite",
+ "Gold",
+ "GoldenRod",
+ "Gray",
+ "Green",
+ "GreenYellow",
+ "HoneyDew",
+ "HotPink",
+ "IndianRed",
+ "Indigo",
+ "Ivory",
+ "Khaki",
+ "Lavender",
+ "LavenderBlush",
+ "LawnGreen",
+ "LemonChiffon",
+ "LightBlue",
+ "LightCoral",
+ "LightCyan",
+ "LightGoldenRodYellow",
+ "LightGrey",
+ "LightGreen",
+ "LightPink",
+ "LightSalmon",
+ "LightSeaGreen",
+ "LightSkyBlue",
+ "LightSlateBlue",
+ "LightSlateGray",
+ "LightSteelBlue",
+ "LightYellow",
+ "Lime",
+ "LimeGreen",
+ "Linen",
+ "Magenta",
+ "Maroon",
+ "MediumAquaMarine",
+ "MediumBlue",
+ "MediumOrchid",
+ "MediumPurple",
+ "MediumSeaGreen",
+ "MediumSlateBlue",
+ "MediumSpringGreen",
+ "MediumTurquoise",
+ "MediumVioletRed",
+ "MidnightBlue",
+ "MintCream",
+ "MistyRose",
+ "Moccasin",
+ "NavajoWhite",
+ "Navy",
+ "OldLace",
+ "Olive",
+ "OliveDrab",
+ "Orange",
+ "OrangeRed",
+ "Orchid",
+ "PaleGoldenRod",
+ "PaleGreen",
+ "PaleTurquoise",
+ "PaleVioletRed",
+ "PapayaWhip",
+ "PeachPuff",
+ "Peru",
+ "Pink",
+ "Plum",
+ "PowderBlue",
+ "Purple",
+ "Red",
+ "RosyBrown",
+ "RoyalBlue",
+ "SaddleBrown",
+ "Salmon",
+ "SandyBrown",
+ "SeaGreen",
+ "SeaShell",
+ "Sienna",
+ "Silver",
+ "SkyBlue",
+ "SlateBlue",
+ "SlateGray",
+ "Snow",
+ "SpringGreen",
+ "SteelBlue",
+ "Tan",
+ "Teal",
+ "Thistle",
+ "Tomato",
+ "Turquoise",
+ "Violet",
+ "VioletRed",
+ "Wheat",
+ "White",
+ "WhiteSmoke",
+ "Yellow",
+ "YellowGreen",
+ "transparent",
+ "invert"
+ ],
+
+ "auto":
+ [
+ "auto"
+ ],
+
+ "none":
+ [
+ "none"
+ ],
+
+ "captionSide":
+ [
+ "top",
+ "bottom",
+ "left",
+ "right"
+ ],
+
+ "clear":
+ [
+ "left",
+ "right",
+ "both"
+ ],
+
+ "cursor":
+ [
+ "auto",
+ "cell",
+ "context-menu",
+ "crosshair",
+ "default",
+ "help",
+ "pointer",
+ "progress",
+ "move",
+ "e-resize",
+ "all-scroll",
+ "ne-resize",
+ "nw-resize",
+ "n-resize",
+ "se-resize",
+ "sw-resize",
+ "s-resize",
+ "w-resize",
+ "ew-resize",
+ "ns-resize",
+ "nesw-resize",
+ "nwse-resize",
+ "col-resize",
+ "row-resize",
+ "text",
+ "vertical-text",
+ "wait",
+ "alias",
+ "copy",
+ "move",
+ "no-drop",
+ "not-allowed",
+ "-moz-alias",
+ "-moz-cell",
+ "-moz-copy",
+ "-moz-grab",
+ "-moz-grabbing",
+ "-moz-contextmenu",
+ "-moz-zoom-in",
+ "-moz-zoom-out",
+ "-moz-spinning"
+ ],
+
+ "direction":
+ [
+ "ltr",
+ "rtl"
+ ],
+
+ "bgAttachment":
+ [
+ "scroll",
+ "fixed"
+ ],
+
+ "bgPosition":
+ [
+ "top",
+ "center",
+ "bottom",
+ "left",
+ "right"
+ ],
+
+ "bgRepeat":
+ [
+ "repeat",
+ "repeat-x",
+ "repeat-y",
+ "no-repeat"
+ ],
+
+ "borderStyle":
+ [
+ "hidden",
+ "dotted",
+ "dashed",
+ "solid",
+ "double",
+ "groove",
+ "ridge",
+ "inset",
+ "outset",
+ "-moz-bg-inset",
+ "-moz-bg-outset",
+ "-moz-bg-solid"
+ ],
+
+ "borderCollapse":
+ [
+ "collapse",
+ "separate"
+ ],
+
+ "overflow":
+ [
+ "visible",
+ "hidden",
+ "scroll",
+ "-moz-scrollbars-horizontal",
+ "-moz-scrollbars-none",
+ "-moz-scrollbars-vertical"
+ ],
+
+ "listStyleType":
+ [
+ "disc",
+ "circle",
+ "square",
+ "decimal",
+ "decimal-leading-zero",
+ "lower-roman",
+ "upper-roman",
+ "lower-greek",
+ "lower-alpha",
+ "lower-latin",
+ "upper-alpha",
+ "upper-latin",
+ "hebrew",
+ "armenian",
+ "georgian",
+ "cjk-ideographic",
+ "hiragana",
+ "katakana",
+ "hiragana-iroha",
+ "katakana-iroha",
+ "inherit"
+ ],
+
+ "listStylePosition":
+ [
+ "inside",
+ "outside"
+ ],
+
+ "content":
+ [
+ "open-quote",
+ "close-quote",
+ "no-open-quote",
+ "no-close-quote",
+ "inherit"
+ ],
+
+ "fontStyle":
+ [
+ "normal",
+ "italic",
+ "oblique",
+ "inherit"
+ ],
+
+ "fontVariant":
+ [
+ "normal",
+ "small-caps",
+ "inherit"
+ ],
+
+ "fontWeight":
+ [
+ "normal",
+ "bold",
+ "bolder",
+ "lighter",
+ "inherit"
+ ],
+
+ "fontSize":
+ [
+ "xx-small",
+ "x-small",
+ "small",
+ "medium",
+ "large",
+ "x-large",
+ "xx-large",
+ "smaller",
+ "larger"
+ ],
+
+ "fontFamily":
+ [
+ "Arial",
+ "Comic Sans MS",
+ "Georgia",
+ "Tahoma",
+ "Verdana",
+ "Times New Roman",
+ "Trebuchet MS",
+ "Lucida Grande",
+ "Helvetica",
+ "serif",
+ "sans-serif",
+ "cursive",
+ "fantasy",
+ "monospace",
+ "caption",
+ "icon",
+ "menu",
+ "message-box",
+ "small-caption",
+ "status-bar",
+ "inherit"
+ ],
+
+ "display":
+ [
+ "block",
+ "inline",
+ "inline-block",
+ "list-item",
+ "marker",
+ "run-in",
+ "compact",
+ "table",
+ "inline-table",
+ "table-row-group",
+ "table-column",
+ "table-column-group",
+ "table-header-group",
+ "table-footer-group",
+ "table-row",
+ "table-cell",
+ "table-caption",
+ "-moz-box",
+ "-moz-compact",
+ "-moz-deck",
+ "-moz-grid",
+ "-moz-grid-group",
+ "-moz-grid-line",
+ "-moz-groupbox",
+ "-moz-inline-block",
+ "-moz-inline-box",
+ "-moz-inline-grid",
+ "-moz-inline-stack",
+ "-moz-inline-table",
+ "-moz-marker",
+ "-moz-popup",
+ "-moz-runin",
+ "-moz-stack"
+ ],
+
+ "position":
+ [
+ "static",
+ "relative",
+ "absolute",
+ "fixed",
+ "inherit"
+ ],
+
+ "float":
+ [
+ "left",
+ "right"
+ ],
+
+ "textAlign":
+ [
+ "left",
+ "right",
+ "center",
+ "justify"
+ ],
+
+ "tableLayout":
+ [
+ "fixed"
+ ],
+
+ "textDecoration":
+ [
+ "underline",
+ "overline",
+ "line-through",
+ "blink"
+ ],
+
+ "textTransform":
+ [
+ "capitalize",
+ "lowercase",
+ "uppercase",
+ "inherit"
+ ],
+
+ "unicodeBidi":
+ [
+ "normal",
+ "embed",
+ "bidi-override"
+ ],
+
+ "whiteSpace":
+ [
+ "normal",
+ "pre",
+ "nowrap"
+ ],
+
+ "verticalAlign":
+ [
+ "baseline",
+ "sub",
+ "super",
+ "top",
+ "text-top",
+ "middle",
+ "bottom",
+ "text-bottom",
+ "inherit"
+ ],
+
+ "thickness":
+ [
+ "thin",
+ "medium",
+ "thick"
+ ],
+
+ "userFocus":
+ [
+ "ignore",
+ "normal"
+ ],
+
+ "userInput":
+ [
+ "disabled",
+ "enabled"
+ ],
+
+ "userSelect":
+ [
+ "normal"
+ ],
+
+ "mozBoxSizing":
+ [
+ "content-box",
+ "padding-box",
+ "border-box"
+ ],
+
+ "mozBoxAlign":
+ [
+ "start",
+ "center",
+ "end",
+ "baseline",
+ "stretch"
+ ],
+
+ "mozBoxDirection":
+ [
+ "normal",
+ "reverse"
+ ],
+
+ "mozBoxOrient":
+ [
+ "horizontal",
+ "vertical"
+ ],
+
+ "mozBoxPack":
+ [
+ "start",
+ "center",
+ "end"
+ ]
+};
+
+this.nonEditableTags =
+{
+ "HTML": 1,
+ "HEAD": 1,
+ "html": 1,
+ "head": 1
+};
+
+this.innerEditableTags =
+{
+ "BODY": 1,
+ "body": 1
+};
+
+this.selfClosingTags =
+{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML
+ "meta": 1,
+ "link": 1,
+ "area": 1,
+ "base": 1,
+ "col": 1,
+ "input": 1,
+ "img": 1,
+ "br": 1,
+ "hr": 1,
+ "param":1,
+ "embed":1
+};
+
+var invisibleTags = this.invisibleTags =
+{
+ "HTML": 1,
+ "HEAD": 1,
+ "TITLE": 1,
+ "META": 1,
+ "LINK": 1,
+ "STYLE": 1,
+ "SCRIPT": 1,
+ "NOSCRIPT": 1,
+ "BR": 1,
+ "PARAM": 1,
+ "COL": 1,
+
+ "html": 1,
+ "head": 1,
+ "title": 1,
+ "meta": 1,
+ "link": 1,
+ "style": 1,
+ "script": 1,
+ "noscript": 1,
+ "br": 1,
+ "param": 1,
+ "col": 1
+ /*
+ "window": 1,
+ "browser": 1,
+ "frame": 1,
+ "tabbrowser": 1,
+ "WINDOW": 1,
+ "BROWSER": 1,
+ "FRAME": 1,
+ "TABBROWSER": 1,
+ */
+};
+
+
+if (typeof KeyEvent == "undefined") {
+ this.KeyEvent = {
+ DOM_VK_CANCEL: 3,
+ DOM_VK_HELP: 6,
+ DOM_VK_BACK_SPACE: 8,
+ DOM_VK_TAB: 9,
+ DOM_VK_CLEAR: 12,
+ DOM_VK_RETURN: 13,
+ DOM_VK_ENTER: 14,
+ DOM_VK_SHIFT: 16,
+ DOM_VK_CONTROL: 17,
+ DOM_VK_ALT: 18,
+ DOM_VK_PAUSE: 19,
+ DOM_VK_CAPS_LOCK: 20,
+ DOM_VK_ESCAPE: 27,
+ DOM_VK_SPACE: 32,
+ DOM_VK_PAGE_UP: 33,
+ DOM_VK_PAGE_DOWN: 34,
+ DOM_VK_END: 35,
+ DOM_VK_HOME: 36,
+ DOM_VK_LEFT: 37,
+ DOM_VK_UP: 38,
+ DOM_VK_RIGHT: 39,
+ DOM_VK_DOWN: 40,
+ DOM_VK_PRINTSCREEN: 44,
+ DOM_VK_INSERT: 45,
+ DOM_VK_DELETE: 46,
+ DOM_VK_0: 48,
+ DOM_VK_1: 49,
+ DOM_VK_2: 50,
+ DOM_VK_3: 51,
+ DOM_VK_4: 52,
+ DOM_VK_5: 53,
+ DOM_VK_6: 54,
+ DOM_VK_7: 55,
+ DOM_VK_8: 56,
+ DOM_VK_9: 57,
+ DOM_VK_SEMICOLON: 59,
+ DOM_VK_EQUALS: 61,
+ DOM_VK_A: 65,
+ DOM_VK_B: 66,
+ DOM_VK_C: 67,
+ DOM_VK_D: 68,
+ DOM_VK_E: 69,
+ DOM_VK_F: 70,
+ DOM_VK_G: 71,
+ DOM_VK_H: 72,
+ DOM_VK_I: 73,
+ DOM_VK_J: 74,
+ DOM_VK_K: 75,
+ DOM_VK_L: 76,
+ DOM_VK_M: 77,
+ DOM_VK_N: 78,
+ DOM_VK_O: 79,
+ DOM_VK_P: 80,
+ DOM_VK_Q: 81,
+ DOM_VK_R: 82,
+ DOM_VK_S: 83,
+ DOM_VK_T: 84,
+ DOM_VK_U: 85,
+ DOM_VK_V: 86,
+ DOM_VK_W: 87,
+ DOM_VK_X: 88,
+ DOM_VK_Y: 89,
+ DOM_VK_Z: 90,
+ DOM_VK_CONTEXT_MENU: 93,
+ DOM_VK_NUMPAD0: 96,
+ DOM_VK_NUMPAD1: 97,
+ DOM_VK_NUMPAD2: 98,
+ DOM_VK_NUMPAD3: 99,
+ DOM_VK_NUMPAD4: 100,
+ DOM_VK_NUMPAD5: 101,
+ DOM_VK_NUMPAD6: 102,
+ DOM_VK_NUMPAD7: 103,
+ DOM_VK_NUMPAD8: 104,
+ DOM_VK_NUMPAD9: 105,
+ DOM_VK_MULTIPLY: 106,
+ DOM_VK_ADD: 107,
+ DOM_VK_SEPARATOR: 108,
+ DOM_VK_SUBTRACT: 109,
+ DOM_VK_DECIMAL: 110,
+ DOM_VK_DIVIDE: 111,
+ DOM_VK_F1: 112,
+ DOM_VK_F2: 113,
+ DOM_VK_F3: 114,
+ DOM_VK_F4: 115,
+ DOM_VK_F5: 116,
+ DOM_VK_F6: 117,
+ DOM_VK_F7: 118,
+ DOM_VK_F8: 119,
+ DOM_VK_F9: 120,
+ DOM_VK_F10: 121,
+ DOM_VK_F11: 122,
+ DOM_VK_F12: 123,
+ DOM_VK_F13: 124,
+ DOM_VK_F14: 125,
+ DOM_VK_F15: 126,
+ DOM_VK_F16: 127,
+ DOM_VK_F17: 128,
+ DOM_VK_F18: 129,
+ DOM_VK_F19: 130,
+ DOM_VK_F20: 131,
+ DOM_VK_F21: 132,
+ DOM_VK_F22: 133,
+ DOM_VK_F23: 134,
+ DOM_VK_F24: 135,
+ DOM_VK_NUM_LOCK: 144,
+ DOM_VK_SCROLL_LOCK: 145,
+ DOM_VK_COMMA: 188,
+ DOM_VK_PERIOD: 190,
+ DOM_VK_SLASH: 191,
+ DOM_VK_BACK_QUOTE: 192,
+ DOM_VK_OPEN_BRACKET: 219,
+ DOM_VK_BACK_SLASH: 220,
+ DOM_VK_CLOSE_BRACKET: 221,
+ DOM_VK_QUOTE: 222,
+ DOM_VK_META: 224
+ };
+}
+
+
+// ************************************************************************************************
+// Ajax
+
+/**
+ * @namespace
+ */
+this.Ajax =
+{
+
+ requests: [],
+ transport: null,
+ states: ["Uninitialized","Loading","Loaded","Interactive","Complete"],
+
+ initialize: function()
+ {
+ this.transport = FBL.getNativeXHRObject();
+ },
+
+ getXHRObject: function()
+ {
+ var xhrObj = false;
+ try
+ {
+ xhrObj = new XMLHttpRequest();
+ }
+ catch(e)
+ {
+ var progid = [
+ "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"
+ ];
+
+ for ( var i=0; i < progid.length; ++i ) {
+ try
+ {
+ xhrObj = new ActiveXObject(progid[i]);
+ }
+ catch(e)
+ {
+ continue;
+ }
+ break;
+ }
+ }
+ finally
+ {
+ return xhrObj;
+ }
+ },
+
+
+ /**
+ * Create a AJAX request.
+ *
+ * @name request
+ * @param {Object} options request options
+ * @param {String} options.url URL to be requested
+ * @param {String} options.type Request type ("get" ou "post"). Default is "get".
+ * @param {Boolean} options.async Asynchronous flag. Default is "true".
+ * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text".
+ * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded".
+ * @param {Function} options.onLoading onLoading callback
+ * @param {Function} options.onLoaded onLoaded callback
+ * @param {Function} options.onInteractive onInteractive callback
+ * @param {Function} options.onComplete onComplete callback
+ * @param {Function} options.onUpdate onUpdate callback
+ * @param {Function} options.onSuccess onSuccess callback
+ * @param {Function} options.onFailure onFailure callback
+ */
+ request: function(options)
+ {
+ // process options
+ var o = FBL.extend(
+ {
+ // default values
+ type: "get",
+ async: true,
+ dataType: "text",
+ contentType: "application/x-www-form-urlencoded"
+ },
+ options || {}
+ );
+
+ this.requests.push(o);
+
+ var s = this.getState();
+ if (s == "Uninitialized" || s == "Complete" || s == "Loaded")
+ this.sendRequest();
+ },
+
+ serialize: function(data)
+ {
+ var r = [""], rl = 0;
+ if (data) {
+ if (typeof data == "string") r[rl++] = data;
+
+ else if (data.innerHTML && data.elements) {
+ for (var i=0,el,l=(el=data.elements).length; i < l; i++)
+ if (el[i].name) {
+ r[rl++] = encodeURIComponent(el[i].name);
+ r[rl++] = "=";
+ r[rl++] = encodeURIComponent(el[i].value);
+ r[rl++] = "&";
+ }
+
+ } else
+ for(var param in data) {
+ r[rl++] = encodeURIComponent(param);
+ r[rl++] = "=";
+ r[rl++] = encodeURIComponent(data[param]);
+ r[rl++] = "&";
+ }
+ }
+ return r.join("").replace(/&$/, "");
+ },
+
+ sendRequest: function()
+ {
+ var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data;
+
+ // open XHR object
+ t.open(r.type, r.url, r.async);
+
+ //setRequestHeaders();
+
+ // indicates that it is a XHR request to the server
+ t.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+ // if data is being sent, sets the appropriate content-type
+ if (data = FBL.Ajax.serialize(r.data))
+ t.setRequestHeader("Content-Type", r.contentType);
+
+ /** @ignore */
+ // onreadystatechange handler
+ t.onreadystatechange = function()
+ {
+ FBL.Ajax.onStateChange(r);
+ };
+
+ // send the request
+ t.send(data);
+ },
+
+ /**
+ * Handles the state change
+ */
+ onStateChange: function(options)
+ {
+ var fn, o = options, t = this.transport;
+ var state = this.getState(t);
+
+ if (fn = o["on" + state]) fn(this.getResponse(o), o);
+
+ if (state == "Complete")
+ {
+ var success = t.status == 200, response = this.getResponse(o);
+
+ if (fn = o["onUpdate"])
+ fn(response, o);
+
+ if (fn = o["on" + (success ? "Success" : "Failure")])
+ fn(response, o);
+
+ t.onreadystatechange = FBL.emptyFn;
+
+ if (this.requests.length > 0)
+ setTimeout(this.sendRequest, 10);
+ }
+ },
+
+ /**
+ * gets the appropriate response value according the type
+ */
+ getResponse: function(options)
+ {
+ var t = this.transport, type = options.dataType;
+
+ if (t.status != 200) return t.statusText;
+ else if (type == "text") return t.responseText;
+ else if (type == "html") return t.responseText;
+ else if (type == "xml") return t.responseXML;
+ else if (type == "json") return eval("(" + t.responseText + ")");
+ },
+
+ /**
+ * returns the current state of the XHR object
+ */
+ getState: function()
+ {
+ return this.states[this.transport.readyState];
+ }
+
+};
+
+
+// ************************************************************************************************
+// Cookie, from http://www.quirksmode.org/js/cookies.html
+
+this.createCookie = function(name,value,days)
+{
+ if ('cookie' in document)
+ {
+ if (days)
+ {
+ var date = new Date();
+ date.setTime(date.getTime()+(days*24*60*60*1000));
+ var expires = "; expires="+date.toGMTString();
+ }
+ else
+ var expires = "";
+
+ document.cookie = name+"="+value+expires+"; path=/";
+ }
+};
+
+this.readCookie = function (name)
+{
+ if ('cookie' in document)
+ {
+ var nameEQ = name + "=";
+ var ca = document.cookie.split(';');
+
+ for(var i=0; i < ca.length; i++)
+ {
+ var c = ca[i];
+ while (c.charAt(0)==' ') c = c.substring(1,c.length);
+ if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
+ }
+ }
+
+ return null;
+};
+
+this.removeCookie = function(name)
+{
+ this.createCookie(name, "", -1);
+};
+
+
+// ************************************************************************************************
+// http://www.mister-pixel.com/#Content__state=is_that_simple
+var fixIE6BackgroundImageCache = function(doc)
+{
+ doc = doc || document;
+ try
+ {
+ doc.execCommand("BackgroundImageCache", false, true);
+ }
+ catch(E)
+ {
+
+ }
+};
+
+// ************************************************************************************************
+// calculatePixelsPerInch
+
+var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
+
+var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body)
+{
+ var inch = FBL.createGlobalElement("div");
+ inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;";
+ body.appendChild(inch);
+
+ FBL.pixelsPerInch = {
+ x: inch.offsetWidth,
+ y: inch.offsetHeight
+ };
+
+ body.removeChild(inch);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.SourceLink = function(url, line, type, object, instance)
+{
+ this.href = url;
+ this.instance = instance;
+ this.line = line;
+ this.type = type;
+ this.object = object;
+};
+
+this.SourceLink.prototype =
+{
+ toString: function()
+ {
+ return this.href;
+ },
+ toJSON: function() // until 3.1...
+ {
+ return "{\"href\":\""+this.href+"\", "+
+ (this.line?("\"line\":"+this.line+","):"")+
+ (this.type?(" \"type\":\""+this.type+"\","):"")+
+ "}";
+ }
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+this.SourceText = function(lines, owner)
+{
+ this.lines = lines;
+ this.owner = owner;
+};
+
+this.SourceText.getLineAsHTML = function(lineNo)
+{
+ return escapeForSourceLine(this.lines[lineNo-1]);
+};
+
+
+// ************************************************************************************************
+}).apply(FBL);
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /** @scope s_i18n */ function() { with (FBL) {
+// ************************************************************************************************
+
+// TODO: xxxpedro localization
+var oSTR =
+{
+ "NoMembersWarning": "There are no properties to show for this object.",
+
+ "EmptyStyleSheet": "There are no rules in this stylesheet.",
+ "EmptyElementCSS": "This element has no style rules.",
+ "AccessRestricted": "Access to restricted URI denied.",
+
+ "net.label.Parameters": "Parameters",
+ "net.label.Source": "Source",
+ "URLParameters": "Params",
+
+ "EditStyle": "Edit Element Style...",
+ "NewRule": "New Rule...",
+
+ "NewProp": "New Property...",
+ "EditProp": 'Edit "%s"',
+ "DeleteProp": 'Delete "%s"',
+ "DisableProp": 'Disable "%s"'
+};
+
+// ************************************************************************************************
+
+FBL.$STR = function(name)
+{
+ return oSTR.hasOwnProperty(name) ? oSTR[name] : name;
+};
+
+FBL.$STRF = function(name, args)
+{
+ if (!oSTR.hasOwnProperty(name)) return name;
+
+ var format = oSTR[name];
+ var objIndex = 0;
+
+ var parts = parseFormat(format);
+ var trialIndex = objIndex;
+ var objects = args;
+
+ for (var i= 0; i < parts.length; i++)
+ {
+ var part = parts[i];
+ if (part && typeof(part) == "object")
+ {
+ if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted.
+ {
+ format = "";
+ objIndex = -1;
+ parts.length = 0;
+ break;
+ }
+ }
+
+ }
+
+ var result = [];
+ for (var i = 0; i < parts.length; ++i)
+ {
+ var part = parts[i];
+ if (part && typeof(part) == "object")
+ {
+ result.push(""+args.shift());
+ }
+ else
+ result.push(part);
+ }
+
+ return result.join("");
+};
+
+// ************************************************************************************************
+
+var parseFormat = function parseFormat(format)
+{
+ var parts = [];
+ if (format.length <= 0)
+ return parts;
+
+ var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/;
+ for (var m = reg.exec(format); m; m = reg.exec(format))
+ {
+ if (m[0].substr(0, 2) == "%%")
+ {
+ parts.push(format.substr(0, m.index));
+ parts.push(m[0].substr(1));
+ }
+ else
+ {
+ var type = m[8] ? m[8] : m[5];
+ var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+ var rep = null;
+ switch (type)
+ {
+ case "s":
+ rep = FirebugReps.Text;
+ break;
+ case "f":
+ case "i":
+ case "d":
+ rep = FirebugReps.Number;
+ break;
+ case "o":
+ rep = null;
+ break;
+ }
+
+ parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+ parts.push({rep: rep, precision: precision, type: ("%" + type)});
+ }
+
+ format = format.substr(m.index+m[0].length);
+ }
+
+ parts.push(format);
+ return parts;
+};
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /** @scope s_firebug */ function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Globals
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Internals
+
+var modules = [];
+var panelTypes = [];
+var panelTypeMap = {};
+var reps = [];
+
+var parentPanelMap = {};
+
+
+// ************************************************************************************************
+// Firebug
+
+/**
+ * @namespace describe Firebug
+ * @exports FBL.Firebug as Firebug
+ */
+FBL.Firebug =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ version: "Firebug Lite 1.4.0",
+ revision: "$Revision$",
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ modules: modules,
+ panelTypes: panelTypes,
+ panelTypeMap: panelTypeMap,
+ reps: reps,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Initialization
+
+ initialize: function()
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application");
+
+ Firebug.browser = new Context(Env.browser);
+ Firebug.context = Firebug.browser;
+
+ Firebug.loadPrefs();
+ Firebug.context.persistedState.isOpen = false;
+
+ // Document must be cached before chrome initialization
+ cacheDocument();
+
+ if (Firebug.Inspector && Firebug.Inspector.create)
+ Firebug.Inspector.create();
+
+ if (FBL.CssAnalyzer && FBL.CssAnalyzer.processAllStyleSheets)
+ FBL.CssAnalyzer.processAllStyleSheets(Firebug.browser.document);
+
+ FirebugChrome.initialize();
+
+ dispatch(modules, "initialize", []);
+
+ if (Firebug.disableResourceFetching)
+ Firebug.Console.logFormatted(["Some Firebug Lite features are not working because " +
+ "resource fetching is disabled. To enabled it set the Firebug Lite option " +
+ "\"disableResourceFetching\" to \"false\". More info at " +
+ "http://getfirebug.com/firebuglite#Options"],
+ Firebug.context, "warn");
+
+ if (Env.onLoad)
+ {
+ var onLoad = Env.onLoad;
+ delete Env.onLoad;
+
+ setTimeout(onLoad, 200);
+ }
+ },
+
+ shutdown: function()
+ {
+ if (Firebug.saveCookies)
+ Firebug.savePrefs();
+
+ if (Firebug.Inspector)
+ Firebug.Inspector.destroy();
+
+ dispatch(modules, "shutdown", []);
+
+ var chromeMap = FirebugChrome.chromeMap;
+
+ for (var name in chromeMap)
+ {
+ if (chromeMap.hasOwnProperty(name))
+ {
+ try
+ {
+ chromeMap[name].destroy();
+ }
+ catch(E)
+ {
+ if (FBTrace.DBG_ERRORS) FBTrace.sysout("chrome.destroy() failed to: " + name);
+ }
+ }
+ }
+
+ Firebug.Lite.Cache.Element.clear();
+ Firebug.Lite.Cache.StyleSheet.clear();
+
+ Firebug.browser = null;
+ Firebug.context = null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Registration
+
+ registerModule: function()
+ {
+ modules.push.apply(modules, arguments);
+
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule");
+ },
+
+ registerPanel: function()
+ {
+ panelTypes.push.apply(panelTypes, arguments);
+
+ for (var i = 0, panelType; panelType = arguments[i]; ++i)
+ {
+ panelTypeMap[panelType.prototype.name] = arguments[i];
+
+ if (panelType.prototype.parentPanel)
+ parentPanelMap[panelType.prototype.parentPanel] = 1;
+ }
+
+ if (FBTrace.DBG_INITIALIZE)
+ for (var i = 0; i < arguments.length; ++i)
+ FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name);
+ },
+
+ registerRep: function()
+ {
+ reps.push.apply(reps, arguments);
+ },
+
+ unregisterRep: function()
+ {
+ for (var i = 0; i < arguments.length; ++i)
+ remove(reps, arguments[i]);
+ },
+
+ setDefaultReps: function(funcRep, rep)
+ {
+ FBL.defaultRep = rep;
+ FBL.defaultFuncRep = funcRep;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Reps
+
+ getRep: function(object)
+ {
+ var type = typeof object;
+ if (isIE && isFunction(object))
+ type = "function";
+
+ for (var i = 0; i < reps.length; ++i)
+ {
+ var rep = reps[i];
+ try
+ {
+ if (rep.supportsObject(object, type))
+ {
+ if (FBTrace.DBG_DOM)
+ FBTrace.sysout("getRep type: "+type+" object: "+object, rep);
+ return rep;
+ }
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc);
+ FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className);
+ // TODO: xxxpedro add trace to FBTrace logs like in Firebug
+ //firebug.trace();
+ }
+ }
+ }
+
+ return (type == 'function') ? defaultFuncRep : defaultRep;
+ },
+
+ getRepObject: function(node)
+ {
+ var target = null;
+ for (var child = node; child; child = child.parentNode)
+ {
+ if (hasClass(child, "repTarget"))
+ target = child;
+
+ if (child.repObject)
+ {
+ if (!target && hasClass(child, "repIgnore"))
+ break;
+ else
+ return child.repObject;
+ }
+ }
+ },
+
+ getRepNode: function(node)
+ {
+ for (var child = node; child; child = child.parentNode)
+ {
+ if (child.repObject)
+ return child;
+ }
+ },
+
+ getElementByRepObject: function(element, object)
+ {
+ for (var child = element.firstChild; child; child = child.nextSibling)
+ {
+ if (child.repObject == object)
+ return child;
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Preferences
+
+ getPref: function(name)
+ {
+ return Firebug[name];
+ },
+
+ setPref: function(name, value)
+ {
+ Firebug[name] = value;
+
+ Firebug.savePrefs();
+ },
+
+ setPrefs: function(prefs)
+ {
+ for (var name in prefs)
+ {
+ if (prefs.hasOwnProperty(name))
+ Firebug[name] = prefs[name];
+ }
+
+ Firebug.savePrefs();
+ },
+
+ restorePrefs: function()
+ {
+ var Options = Env.DefaultOptions;
+
+ for (var name in Options)
+ {
+ Firebug[name] = Options[name];
+ }
+ },
+
+ loadPrefs: function()
+ {
+ this.restorePrefs();
+
+ var prefs = Store.get("FirebugLite") || {};
+ var options = prefs.options;
+ var persistedState = prefs.persistedState || FBL.defaultPersistedState;
+
+ for (var name in options)
+ {
+ if (options.hasOwnProperty(name))
+ Firebug[name] = options[name];
+ }
+
+ if (Firebug.context && persistedState)
+ Firebug.context.persistedState = persistedState;
+ },
+
+ savePrefs: function()
+ {
+ var prefs = {
+ options: {}
+ };
+
+ var EnvOptions = Env.Options;
+ var options = prefs.options;
+ for (var name in EnvOptions)
+ {
+ if (EnvOptions.hasOwnProperty(name))
+ {
+ options[name] = Firebug[name];
+ }
+ }
+
+ var persistedState = Firebug.context.persistedState;
+ if (!persistedState)
+ {
+ persistedState = Firebug.context.persistedState = FBL.defaultPersistedState;
+ }
+
+ prefs.persistedState = persistedState;
+
+ Store.set("FirebugLite", prefs);
+ },
+
+ erasePrefs: function()
+ {
+ Store.remove("FirebugLite");
+ this.restorePrefs();
+ }
+};
+
+Firebug.restorePrefs();
+
+// xxxpedro should we remove this?
+window.Firebug = FBL.Firebug;
+
+if (!Env.Options.enablePersistent ||
+ Env.Options.enablePersistent && Env.isChromeContext ||
+ Env.isDebugMode)
+ Env.browser.window.Firebug = FBL.Firebug;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Other methods
+
+FBL.cacheDocument = function cacheDocument()
+{
+ var ElementCache = Firebug.Lite.Cache.Element;
+ var els = Firebug.browser.document.getElementsByTagName("*");
+ for (var i=0, l=els.length, el; i<l; i++)
+ {
+ el = els[i];
+ ElementCache(el);
+ }
+};
+
+// ************************************************************************************************
+
+/**
+ * @class
+ *
+ * Support for listeners registration. This object also extended by Firebug.Module so,
+ * all modules supports listening automatically. Notice that array of listeners
+ * is created for each intance of a module within initialize method. Thus all derived
+ * module classes must ensure that Firebug.Module.initialize method is called for the
+ * super class.
+ */
+Firebug.Listener = function()
+{
+ // The array is created when the first listeners is added.
+ // It can't be created here since derived objects would share
+ // the same array.
+ this.fbListeners = null;
+};
+
+Firebug.Listener.prototype =
+{
+ addListener: function(listener)
+ {
+ if (!this.fbListeners)
+ this.fbListeners = []; // delay the creation until the objects are created so 'this' causes new array for each module
+
+ this.fbListeners.push(listener);
+ },
+
+ removeListener: function(listener)
+ {
+ remove(this.fbListeners, listener); // if this.fbListeners is null, remove is being called with no add
+ }
+};
+
+// ************************************************************************************************
+
+
+// ************************************************************************************************
+// Module
+
+/**
+ * @module Base class for all modules. Every derived module object must be registered using
+ * <code>Firebug.registerModule</code> method. There is always one instance of a module object
+ * per browser window.
+ * @extends Firebug.Listener
+ */
+Firebug.Module = extend(new Firebug.Listener(),
+/** @extend Firebug.Module */
+{
+ /**
+ * Called when the window is opened.
+ */
+ initialize: function()
+ {
+ },
+
+ /**
+ * Called when the window is closed.
+ */
+ shutdown: function()
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Called when a new context is created but before the page is loaded.
+ */
+ initContext: function(context)
+ {
+ },
+
+ /**
+ * Called after a context is detached to a separate window;
+ */
+ reattachContext: function(browser, context)
+ {
+ },
+
+ /**
+ * Called when a context is destroyed. Module may store info on persistedState for reloaded pages.
+ */
+ destroyContext: function(context, persistedState)
+ {
+ },
+
+ // Called when a FF tab is create or activated (user changes FF tab)
+ // Called after context is created or with context == null (to abort?)
+ showContext: function(browser, context)
+ {
+ },
+
+ /**
+ * Called after a context's page gets DOMContentLoaded
+ */
+ loadedContext: function(context)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ showPanel: function(browser, panel)
+ {
+ },
+
+ showSidePanel: function(browser, panel)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ updateOption: function(name, value)
+ {
+ },
+
+ getObjectByURL: function(context, url)
+ {
+ }
+});
+
+// ************************************************************************************************
+// Panel
+
+/**
+ * @panel Base class for all panels. Every derived panel must define a constructor and
+ * register with "Firebug.registerPanel" method. An instance of the panel
+ * object is created by the framework for each browser tab where Firebug is activated.
+ */
+Firebug.Panel =
+{
+ name: "HelloWorld",
+ title: "Hello World!",
+
+ parentPanel: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ options: {
+ hasCommandLine: false,
+ hasStatusBar: false,
+ hasToolButtons: false,
+
+ // Pre-rendered panels are those included in the skin file (firebug.html)
+ isPreRendered: false,
+ innerHTMLSync: false
+
+ /*
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // To be used by external extensions
+ panelHTML: "",
+ panelCSS: "",
+
+ toolButtonsHTML: ""
+ /**/
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ tabNode: null,
+ panelNode: null,
+ sidePanelNode: null,
+ statusBarNode: null,
+ toolButtonsNode: null,
+
+ panelBarNode: null,
+
+ sidePanelBarBoxNode: null,
+ sidePanelBarNode: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ sidePanelBar: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ searchable: false,
+ editable: true,
+ order: 2147483647,
+ statusSeparator: "<",
+
+ create: function(context, doc)
+ {
+ this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name);
+
+ this.panelBarNode = $("fbPanelBar1");
+ this.sidePanelBarBoxNode = $("fbPanelBar2");
+
+ if (this.hasSidePanel)
+ {
+ this.sidePanelBar = extend({}, PanelBar);
+ this.sidePanelBar.create(this);
+ }
+
+ var options = this.options = extend(Firebug.Panel.options, this.options);
+ var panelId = "fb" + this.name;
+
+ if (options.isPreRendered)
+ {
+ this.panelNode = $(panelId);
+
+ this.tabNode = $(panelId + "Tab");
+ this.tabNode.style.display = "block";
+
+ if (options.hasToolButtons)
+ {
+ this.toolButtonsNode = $(panelId + "Buttons");
+ }
+
+ if (options.hasStatusBar)
+ {
+ this.statusBarBox = $("fbStatusBarBox");
+ this.statusBarNode = $(panelId + "StatusBar");
+ }
+ }
+ else
+ {
+ var containerSufix = this.parentPanel ? "2" : "1";
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Create Panel
+ var panelNode = this.panelNode = createElement("div", {
+ id: panelId,
+ className: "fbPanel"
+ });
+
+ $("fbPanel" + containerSufix).appendChild(panelNode);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Create Panel Tab
+ var tabHTML = '<span class="fbTabL"></span><span class="fbTabText">' +
+ this.title + '</span><span class="fbTabR"></span>';
+
+ var tabNode = this.tabNode = createElement("a", {
+ id: panelId + "Tab",
+ className: "fbTab fbHover",
+ innerHTML: tabHTML
+ });
+
+ if (isIE6)
+ {
+ tabNode.href = "javascript:void(0)";
+ }
+
+ var panelBarNode = this.parentPanel ?
+ Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode :
+ this.panelBarNode;
+
+ panelBarNode.appendChild(tabNode);
+ tabNode.style.display = "block";
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create ToolButtons
+ if (options.hasToolButtons)
+ {
+ this.toolButtonsNode = createElement("span", {
+ id: panelId + "Buttons",
+ className: "fbToolbarButtons"
+ });
+
+ $("fbToolbarButtons").appendChild(this.toolButtonsNode);
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create StatusBar
+ if (options.hasStatusBar)
+ {
+ this.statusBarBox = $("fbStatusBarBox");
+
+ this.statusBarNode = createElement("span", {
+ id: panelId + "StatusBar",
+ className: "fbToolbarButtons fbStatusBar"
+ });
+
+ this.statusBarBox.appendChild(this.statusBarNode);
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create SidePanel
+ }
+
+ this.containerNode = this.panelNode.parentNode;
+
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name);
+
+ // xxxpedro contextMenu
+ this.onContextMenu = bind(this.onContextMenu, this);
+
+ /*
+ this.context = context;
+ this.document = doc;
+
+ this.panelNode = doc.createElement("div");
+ this.panelNode.ownerPanel = this;
+
+ setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid);
+ doc.body.appendChild(this.panelNode);
+
+ if (FBTrace.DBG_INITIALIZE)
+ FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n");
+
+ this.initializeNode(this.panelNode);
+ /**/
+ },
+
+ destroy: function(state) // Panel may store info on state
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name);
+
+ if (this.hasSidePanel)
+ {
+ this.sidePanelBar.destroy();
+ this.sidePanelBar = null;
+ }
+
+ this.options = null;
+ this.name = null;
+ this.parentPanel = null;
+
+ this.tabNode = null;
+ this.panelNode = null;
+ this.containerNode = null;
+
+ this.toolButtonsNode = null;
+ this.statusBarBox = null;
+ this.statusBarNode = null;
+
+ //if (this.panelNode)
+ // delete this.panelNode.ownerPanel;
+
+ //this.destroyNode();
+ },
+
+ initialize: function()
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ if (this.hasSidePanel)
+ {
+ this.sidePanelBar.initialize();
+ }
+
+ var options = this.options = extend(Firebug.Panel.options, this.options);
+ var panelId = "fb" + this.name;
+
+ this.panelNode = $(panelId);
+
+ this.tabNode = $(panelId + "Tab");
+ this.tabNode.style.display = "block";
+
+ if (options.hasStatusBar)
+ {
+ this.statusBarBox = $("fbStatusBarBox");
+ this.statusBarNode = $(panelId + "StatusBar");
+ }
+
+ if (options.hasToolButtons)
+ {
+ this.toolButtonsNode = $(panelId + "Buttons");
+ }
+
+ this.containerNode = this.panelNode.parentNode;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // restore persistent state
+ this.containerNode.scrollTop = this.lastScrollTop;
+
+ // xxxpedro contextMenu
+ addEvent(this.containerNode, "contextmenu", this.onContextMenu);
+
+
+ /// TODO: xxxpedro infoTip Hack
+ Firebug.chrome.currentPanel =
+ Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ?
+ Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel :
+ Firebug.chrome.selectedPanel;
+
+ Firebug.showInfoTips = true;
+ if (Firebug.InfoTip)
+ Firebug.InfoTip.initializeBrowser(Firebug.chrome);
+ },
+
+ shutdown: function()
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name);
+
+ /// TODO: xxxpedro infoTip Hack
+ if (Firebug.InfoTip)
+ Firebug.InfoTip.uninitializeBrowser(Firebug.chrome);
+
+ if (Firebug.chrome.largeCommandLineVisible)
+ Firebug.chrome.hideLargeCommandLine();
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ if (this.hasSidePanel)
+ {
+ // TODO: xxxpedro firebug1.3a6
+ // new PanelBar mechanism will need to call shutdown to hide the panels (so it
+ // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement
+ // a "remember selected panel" feature in the sidePanelBar
+ //this.sidePanelBar.shutdown();
+ }
+
+ // store persistent state
+ this.lastScrollTop = this.containerNode.scrollTop;
+
+ // xxxpedro contextMenu
+ removeEvent(this.containerNode, "contextmenu", this.onContextMenu);
+ },
+
+ detach: function(oldChrome, newChrome)
+ {
+ if (oldChrome && oldChrome.selectedPanel && oldChrome.selectedPanel.name == this.name)
+ this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop;
+ },
+
+ reattach: function(doc)
+ {
+ if (this.options.innerHTMLSync)
+ this.synchronizeUI();
+ },
+
+ synchronizeUI: function()
+ {
+ this.containerNode.scrollTop = this.lastScrollTop || 0;
+ },
+
+ show: function(state)
+ {
+ var options = this.options;
+
+ if (options.hasStatusBar)
+ {
+ this.statusBarBox.style.display = "inline";
+ this.statusBarNode.style.display = "inline";
+ }
+
+ if (options.hasToolButtons)
+ {
+ this.toolButtonsNode.style.display = "inline";
+ }
+
+ this.panelNode.style.display = "block";
+
+ this.visible = true;
+
+ if (!this.parentPanel)
+ Firebug.chrome.layout(this);
+ },
+
+ hide: function(state)
+ {
+ var options = this.options;
+
+ if (options.hasStatusBar)
+ {
+ this.statusBarBox.style.display = "none";
+ this.statusBarNode.style.display = "none";
+ }
+
+ if (options.hasToolButtons)
+ {
+ this.toolButtonsNode.style.display = "none";
+ }
+
+ this.panelNode.style.display = "none";
+
+ this.visible = false;
+ },
+
+ watchWindow: function(win)
+ {
+ },
+
+ unwatchWindow: function(win)
+ {
+ },
+
+ updateOption: function(name, value)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Toolbar helpers
+ */
+ showToolbarButtons: function(buttonsId, show)
+ {
+ try
+ {
+ if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext.
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this);
+
+ return;
+ }
+ var buttons = this.context.browser.chrome.$(buttonsId);
+ if (buttons)
+ collapse(buttons, show ? "false" : "true");
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc);
+ if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser");
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Returns a number indicating the view's ability to inspect the object.
+ *
+ * Zero means not supported, and higher numbers indicate specificity.
+ */
+ supportsObject: function(object)
+ {
+ return 0;
+ },
+
+ hasObject: function(object) // beyond type testing, is this object selectable?
+ {
+ return false;
+ },
+
+ select: function(object, forceUpdate)
+ {
+ if (!object)
+ object = this.getDefaultSelection(this.context);
+
+ if(FBTrace.DBG_PANELS)
+ FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection);
+
+ if (forceUpdate || object != this.selection)
+ {
+ this.selection = object;
+ this.updateSelection(object);
+
+ // TODO: xxxpedro
+ // XXXjoe This is kind of cheating, but, feh.
+ //Firebug.chrome.onPanelSelect(object, this);
+ //if (uiListeners.length > 0)
+ // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener
+ }
+ },
+
+ updateSelection: function(object)
+ {
+ },
+
+ markChange: function(skipSelf)
+ {
+ if (this.dependents)
+ {
+ if (skipSelf)
+ {
+ for (var i = 0; i < this.dependents.length; ++i)
+ {
+ var panelName = this.dependents[i];
+ if (panelName != this.name)
+ this.context.invalidatePanels(panelName);
+ }
+ }
+ else
+ this.context.invalidatePanels.apply(this.context, this.dependents);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ startInspecting: function()
+ {
+ },
+
+ stopInspecting: function(object, cancelled)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ search: function(text, reverse)
+ {
+ },
+
+ /**
+ * Retrieves the search options that this modules supports.
+ * This is used by the search UI to present the proper options.
+ */
+ getSearchOptionsMenuItems: function()
+ {
+ return [
+ Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive")
+ ];
+ },
+
+ /**
+ * Navigates to the next document whose match parameter returns true.
+ */
+ navigateToNextDocument: function(match, reverse)
+ {
+ // This is an approximation of the UI that is displayed by the location
+ // selector. This should be close enough, although it may be better
+ // to simply generate the sorted list within the module, rather than
+ // sorting within the UI.
+ var self = this;
+ function compare(a, b) {
+ var locA = self.getObjectDescription(a);
+ var locB = self.getObjectDescription(b);
+ if(locA.path > locB.path)
+ return 1;
+ if(locA.path < locB.path)
+ return -1;
+ if(locA.name > locB.name)
+ return 1;
+ if(locA.name < locB.name)
+ return -1;
+ return 0;
+ }
+ var allLocs = this.getLocationList().sort(compare);
+ for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++);
+
+ function transformIndex(index) {
+ if (reverse) {
+ // For the reverse case we need to implement wrap around.
+ var intermediate = curPos - index - 1;
+ return (intermediate < 0 ? allLocs.length : 0) + intermediate;
+ } else {
+ return (curPos + index + 1) % allLocs.length;
+ }
+ };
+
+ for (var next = 0; next < allLocs.length - 1; next++)
+ {
+ var object = allLocs[transformIndex(next)];
+
+ if (match(object))
+ {
+ this.navigate(object);
+ return object;
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ // Called when "Options" clicked. Return array of
+ // {label: 'name', nol10n: true, type: "checkbox", checked: <value>, command:function to set <value>}
+ getOptionsMenuItems: function()
+ {
+ return null;
+ },
+
+ /*
+ * Called by chrome.onContextMenu to build the context menu when this panel has focus.
+ * See also FirebugRep for a similar function also called by onContextMenu
+ * Extensions may monkey patch and chain off this call
+ * @param object: the 'realObject', a model value, eg a DOM property
+ * @param target: the HTML element clicked on.
+ * @return an array of menu items.
+ */
+ getContextMenuItems: function(object, target)
+ {
+ return [];
+ },
+
+ getBreakOnMenuItems: function()
+ {
+ return [];
+ },
+
+ getEditor: function(target, value)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getDefaultSelection: function()
+ {
+ return null;
+ },
+
+ browseObject: function(object)
+ {
+ },
+
+ getPopupObject: function(target)
+ {
+ return Firebug.getRepObject(target);
+ },
+
+ getTooltipObject: function(target)
+ {
+ return Firebug.getRepObject(target);
+ },
+
+ showInfoTip: function(infoTip, x, y)
+ {
+
+ },
+
+ getObjectPath: function(object)
+ {
+ return null;
+ },
+
+ // An array of objects that can be passed to getObjectLocation.
+ // The list of things a panel can show, eg sourceFiles.
+ // Only shown if panel.location defined and supportsObject true
+ getLocationList: function()
+ {
+ return null;
+ },
+
+ getDefaultLocation: function()
+ {
+ return null;
+ },
+
+ getObjectLocation: function(object)
+ {
+ return "";
+ },
+
+ // Text for the location list menu eg script panel source file list
+ // return.path: group/category label, return.name: item label
+ getObjectDescription: function(object)
+ {
+ var url = this.getObjectLocation(object);
+ return FBL.splitURLBase(url);
+ },
+
+ /*
+ * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint
+ * @param: show boolean, true turns on.
+ */
+ highlight: function(show)
+ {
+ var tab = this.getTab();
+ if (!tab)
+ return;
+
+ if (show)
+ tab.setAttribute("highlight", "true");
+ else
+ tab.removeAttribute("highlight");
+ },
+
+ getTab: function()
+ {
+ var chrome = Firebug.chrome;
+
+ var tab = chrome.$("fbPanelBar2").getTab(this.name);
+ if (!tab)
+ tab = chrome.$("fbPanelBar1").getTab(this.name);
+ return tab;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Support for Break On Next
+
+ /**
+ * Called by the framework when the user clicks on the Break On Next button.
+ * @param {Boolean} armed Set to true if the Break On Next feature is
+ * to be armed for action and set to false if the Break On Next should be disarmed.
+ * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|.
+ */
+ breakOnNext: function(armed)
+ {
+ },
+
+ /**
+ * Called when a panel is selected/displayed. The method should return true
+ * if the Break On Next feature is currently armed for this panel.
+ */
+ shouldBreakOnNext: function()
+ {
+ return false;
+ },
+
+ /**
+ * Returns labels for Break On Next tooltip (one for enabled and one for disabled state).
+ * @param {Boolean} enabled Set to true if the Break On Next feature is
+ * currently activated for this panel.
+ */
+ getBreakOnNextTooltip: function(enabled)
+ {
+ return null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ // xxxpedro contextMenu
+ onContextMenu: function(event)
+ {
+ if (!this.getContextMenuItems)
+ return;
+
+ cancelEvent(event, true);
+
+ var target = event.target || event.srcElement;
+
+ var menu = this.getContextMenuItems(this.selection, target);
+ if (!menu)
+ return;
+
+ var contextMenu = new Menu(
+ {
+ id: "fbPanelContextMenu",
+
+ items: menu
+ });
+
+ contextMenu.show(event.clientX, event.clientY);
+
+ return true;
+
+ /*
+ // TODO: xxxpedro move code to somewhere. code to get cross-browser
+ // window to screen coordinates
+ var box = Firebug.browser.getElementPosition(Firebug.chrome.node);
+
+ var screenY = 0;
+
+ // Firefox
+ if (typeof window.mozInnerScreenY != "undefined")
+ {
+ screenY = window.mozInnerScreenY;
+ }
+ // Chrome
+ else if (typeof window.innerHeight != "undefined")
+ {
+ screenY = window.outerHeight - window.innerHeight;
+ }
+ // IE
+ else if (typeof window.screenTop != "undefined")
+ {
+ screenY = window.screenTop;
+ }
+
+ contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top);
+ /**/
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/**
+ * MeasureBox
+ * To get pixels size.width and size.height:
+ * <ul><li> this.startMeasuring(view); </li>
+ * <li> var size = this.measureText(lineNoCharsSpacer); </li>
+ * <li> this.stopMeasuring(); </li>
+ * </ul>
+ *
+ * @namespace
+ */
+Firebug.MeasureBox =
+{
+ startMeasuring: function(target)
+ {
+ if (!this.measureBox)
+ {
+ this.measureBox = target.ownerDocument.createElement("span");
+ this.measureBox.className = "measureBox";
+ }
+
+ copyTextStyles(target, this.measureBox);
+ target.ownerDocument.body.appendChild(this.measureBox);
+ },
+
+ getMeasuringElement: function()
+ {
+ return this.measureBox;
+ },
+
+ measureText: function(value)
+ {
+ this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m";
+ return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1};
+ },
+
+ measureInputText: function(value)
+ {
+ value = value ? escapeForTextNode(value) : "m";
+ if (!Firebug.showTextNodesWithWhitespace)
+ value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m');
+ this.measureBox.innerHTML = value;
+ return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1};
+ },
+
+ getBox: function(target)
+ {
+ var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, "");
+ var box = getBoxFromStyles(style, this.measureBox);
+ return box;
+ },
+
+ stopMeasuring: function()
+ {
+ this.measureBox.parentNode.removeChild(this.measureBox);
+ }
+};
+
+
+// ************************************************************************************************
+if (FBL.domplate) Firebug.Rep = domplate(
+{
+ className: "",
+ inspectable: true,
+
+ supportsObject: function(object, type)
+ {
+ return false;
+ },
+
+ inspectObject: function(object, context)
+ {
+ Firebug.chrome.select(object);
+ },
+
+ browseObject: function(object, context)
+ {
+ },
+
+ persistObject: function(object, context)
+ {
+ },
+
+ getRealObject: function(object, context)
+ {
+ return object;
+ },
+
+ getTitle: function(object)
+ {
+ var label = safeToString(object);
+
+ var re = /\[object (.*?)\]/;
+ var m = re.exec(label);
+
+ ///return m ? m[1] : label;
+
+ // if the label is in the "[object TYPE]" format return its type
+ if (m)
+ {
+ return m[1];
+ }
+ // if it is IE we need to handle some special cases
+ else if (
+ // safeToString() fails to recognize some objects in IE
+ isIE &&
+ // safeToString() returns "[object]" for some objects like window.Image
+ (label == "[object]" ||
+ // safeToString() returns undefined for some objects like window.clientInformation
+ typeof object == "object" && typeof label == "undefined")
+ )
+ {
+ return "Object";
+ }
+ else
+ {
+ return label;
+ }
+ },
+
+ getTooltip: function(object)
+ {
+ return null;
+ },
+
+ getContextMenuItems: function(object, target, context)
+ {
+ return [];
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Convenience for domplates
+
+ STR: function(name)
+ {
+ return $STR(name);
+ },
+
+ cropString: function(text)
+ {
+ return cropString(text);
+ },
+
+ cropMultipleLines: function(text, limit)
+ {
+ return cropMultipleLines(text, limit);
+ },
+
+ toLowerCase: function(text)
+ {
+ return text ? text.toLowerCase() : text;
+ },
+
+ plural: function(n)
+ {
+ return n == 1 ? "" : "s";
+ }
+});
+
+// ************************************************************************************************
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /** @scope s_gui */ function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Controller
+
+/**@namespace*/
+FBL.Controller = {
+
+ controllers: null,
+ controllerContext: null,
+
+ initialize: function(context)
+ {
+ this.controllers = [];
+ this.controllerContext = context || Firebug.chrome;
+ },
+
+ shutdown: function()
+ {
+ this.removeControllers();
+
+ //this.controllers = null;
+ //this.controllerContext = null;
+ },
+
+ addController: function()
+ {
+ for (var i=0, arg; arg=arguments[i]; i++)
+ {
+ // If the first argument is a string, make a selector query
+ // within the controller node context
+ if (typeof arg[0] == "string")
+ {
+ arg[0] = $$(arg[0], this.controllerContext);
+ }
+
+ // bind the handler to the proper context
+ var handler = arg[2];
+ arg[2] = bind(handler, this);
+ // save the original handler as an extra-argument, so we can
+ // look for it later, when removing a particular controller
+ arg[3] = handler;
+
+ this.controllers.push(arg);
+ addEvent.apply(this, arg);
+ }
+ },
+
+ removeController: function()
+ {
+ for (var i=0, arg; arg=arguments[i]; i++)
+ {
+ for (var j=0, c; c=this.controllers[j]; j++)
+ {
+ if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3])
+ removeEvent.apply(this, c);
+ }
+ }
+ },
+
+ removeControllers: function()
+ {
+ for (var i=0, c; c=this.controllers[i]; i++)
+ {
+ removeEvent.apply(this, c);
+ }
+ }
+};
+
+
+// ************************************************************************************************
+// PanelBar
+
+/**@namespace*/
+FBL.PanelBar =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ panelMap: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ selectedPanel: null,
+ parentPanelName: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ create: function(ownerPanel)
+ {
+ this.panelMap = {};
+ this.ownerPanel = ownerPanel;
+
+ if (ownerPanel)
+ {
+ ownerPanel.sidePanelBarNode = createElement("span");
+ ownerPanel.sidePanelBarNode.style.display = "none";
+ ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode);
+ }
+
+ var panels = Firebug.panelTypes;
+ for (var i=0, p; p=panels[i]; i++)
+ {
+ if ( // normal Panel of the Chrome's PanelBar
+ !ownerPanel && !p.prototype.parentPanel ||
+ // Child Panel of the current Panel's SidePanelBar
+ ownerPanel && p.prototype.parentPanel &&
+ ownerPanel.name == p.prototype.parentPanel)
+ {
+ this.addPanel(p.prototype.name);
+ }
+ }
+ },
+
+ destroy: function()
+ {
+ PanelBar.shutdown.call(this);
+
+ for (var name in this.panelMap)
+ {
+ this.removePanel(name);
+
+ var panel = this.panelMap[name];
+ panel.destroy();
+
+ this.panelMap[name] = null;
+ delete this.panelMap[name];
+ }
+
+ this.panelMap = null;
+ this.ownerPanel = null;
+ },
+
+ initialize: function()
+ {
+ if (this.ownerPanel)
+ this.ownerPanel.sidePanelBarNode.style.display = "inline";
+
+ for(var name in this.panelMap)
+ {
+ (function(self, name){
+
+ // tab click handler
+ var onTabClick = function onTabClick()
+ {
+ self.selectPanel(name);
+ return false;
+ };
+
+ Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]);
+
+ })(this, name);
+ }
+ },
+
+ shutdown: function()
+ {
+ var selectedPanel = this.selectedPanel;
+
+ if (selectedPanel)
+ {
+ removeClass(selectedPanel.tabNode, "fbSelectedTab");
+ selectedPanel.hide();
+ selectedPanel.shutdown();
+ }
+
+ if (this.ownerPanel)
+ this.ownerPanel.sidePanelBarNode.style.display = "none";
+
+ this.selectedPanel = null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ addPanel: function(panelName, parentPanel)
+ {
+ var PanelType = Firebug.panelTypeMap[panelName];
+ var panel = this.panelMap[panelName] = new PanelType();
+
+ panel.create();
+ },
+
+ removePanel: function(panelName)
+ {
+ var panel = this.panelMap[panelName];
+ if (panel.hasOwnProperty(panelName))
+ panel.destroy();
+ },
+
+ selectPanel: function(panelName)
+ {
+ var selectedPanel = this.selectedPanel;
+ var panel = this.panelMap[panelName];
+
+ if (panel && selectedPanel != panel)
+ {
+ if (selectedPanel)
+ {
+ removeClass(selectedPanel.tabNode, "fbSelectedTab");
+ selectedPanel.shutdown();
+ selectedPanel.hide();
+ }
+
+ if (!panel.parentPanel)
+ Firebug.context.persistedState.selectedPanelName = panelName;
+
+ this.selectedPanel = panel;
+
+ setClass(panel.tabNode, "fbSelectedTab");
+ panel.show();
+ panel.initialize();
+ }
+ },
+
+ getPanel: function(panelName)
+ {
+ var panel = this.panelMap[panelName];
+
+ return panel;
+ }
+
+};
+
+//************************************************************************************************
+// Button
+
+/**
+ * options.element
+ * options.caption
+ * options.title
+ *
+ * options.owner
+ * options.className
+ * options.pressedClassName
+ *
+ * options.onPress
+ * options.onUnpress
+ * options.onClick
+ *
+ * @class
+ * @extends FBL.Controller
+ *
+ */
+
+FBL.Button = function(options)
+{
+ options = options || {};
+
+ append(this, options);
+
+ this.state = "unpressed";
+ this.display = "unpressed";
+
+ if (this.element)
+ {
+ this.container = this.element.parentNode;
+ }
+ else
+ {
+ this.shouldDestroy = true;
+
+ this.container = this.owner.getPanel().toolButtonsNode;
+
+ this.element = createElement("a", {
+ className: this.baseClassName + " " + this.className + " fbHover",
+ innerHTML: this.caption
+ });
+
+ if (this.title)
+ this.element.title = this.title;
+
+ this.container.appendChild(this.element);
+ }
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+Button.prototype = extend(Controller,
+/**@extend FBL.Button.prototype*/
+{
+ type: "normal",
+ caption: "caption",
+ title: null,
+
+ className: "", // custom class
+ baseClassName: "fbButton", // control class
+ pressedClassName: "fbBtnPressed", // control pressed class
+
+ element: null,
+ container: null,
+ owner: null,
+
+ state: null,
+ display: null,
+
+ destroy: function()
+ {
+ this.shutdown();
+
+ // only remove if it is a dynamically generated button (not pre-rendered)
+ if (this.shouldDestroy)
+ this.container.removeChild(this.element);
+
+ this.element = null;
+ this.container = null;
+ this.owner = null;
+ },
+
+ initialize: function()
+ {
+ Controller.initialize.apply(this);
+
+ var element = this.element;
+
+ this.addController([element, "mousedown", this.handlePress]);
+
+ if (this.type == "normal")
+ this.addController(
+ [element, "mouseup", this.handleUnpress],
+ [element, "mouseout", this.handleUnpress],
+ [element, "click", this.handleClick]
+ );
+ },
+
+ shutdown: function()
+ {
+ Controller.shutdown.apply(this);
+ },
+
+ restore: function()
+ {
+ this.changeState("unpressed");
+ },
+
+ changeState: function(state)
+ {
+ this.state = state;
+ this.changeDisplay(state);
+ },
+
+ changeDisplay: function(display)
+ {
+ if (display != this.display)
+ {
+ if (display == "pressed")
+ {
+ setClass(this.element, this.pressedClassName);
+ }
+ else if (display == "unpressed")
+ {
+ removeClass(this.element, this.pressedClassName);
+ }
+ this.display = display;
+ }
+ },
+
+ handlePress: function(event)
+ {
+ cancelEvent(event, true);
+
+ if (this.type == "normal")
+ {
+ this.changeDisplay("pressed");
+ this.beforeClick = true;
+ }
+ else if (this.type == "toggle")
+ {
+ if (this.state == "pressed")
+ {
+ this.changeState("unpressed");
+
+ if (this.onUnpress)
+ this.onUnpress.apply(this.owner, arguments);
+ }
+ else
+ {
+ this.changeState("pressed");
+
+ if (this.onPress)
+ this.onPress.apply(this.owner, arguments);
+ }
+
+ if (this.onClick)
+ this.onClick.apply(this.owner, arguments);
+ }
+
+ return false;
+ },
+
+ handleUnpress: function(event)
+ {
+ cancelEvent(event, true);
+
+ if (this.beforeClick)
+ this.changeDisplay("unpressed");
+
+ return false;
+ },
+
+ handleClick: function(event)
+ {
+ cancelEvent(event, true);
+
+ if (this.type == "normal")
+ {
+ if (this.onClick)
+ this.onClick.apply(this.owner);
+
+ this.changeState("unpressed");
+ }
+
+ this.beforeClick = false;
+
+ return false;
+ }
+});
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/**
+ * @class
+ * @extends FBL.Button
+ */
+FBL.IconButton = function()
+{
+ Button.apply(this, arguments);
+};
+
+IconButton.prototype = extend(Button.prototype,
+/**@extend FBL.IconButton.prototype*/
+{
+ baseClassName: "fbIconButton",
+ pressedClassName: "fbIconPressed"
+});
+
+
+//************************************************************************************************
+// Menu
+
+var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value",
+ _command: "$item.command"};
+
+if (isIE6)
+ menuItemProps.href = "javascript:void(0)";
+
+// Allow GUI to be loaded even when Domplate module is not installed.
+if (FBL.domplate)
+var MenuPlate = domplate(Firebug.Rep,
+{
+ tag:
+ DIV({"class": "fbMenu fbShadow"},
+ DIV({"class": "fbMenuContent fbShadowContent"},
+ FOR("item", "$object.items|memberIterator",
+ TAG("$item.tag", {item: "$item"})
+ )
+ )
+ ),
+
+ itemTag:
+ A(menuItemProps,
+ "$item.label"
+ ),
+
+ checkBoxTag:
+ A(extend(menuItemProps, {checked : "$item.checked"}),
+
+ "$item.label"
+ ),
+
+ radioButtonTag:
+ A(extend(menuItemProps, {selected : "$item.selected"}),
+
+ "$item.label"
+ ),
+
+ groupTag:
+ A(extend(menuItemProps, {child: "$item.child"}),
+ "$item.label"
+ ),
+
+ shortcutTag:
+ A(menuItemProps,
+ "$item.label",
+ SPAN({"class": "fbMenuShortcutKey"},
+ "$item.key"
+ )
+ ),
+
+ separatorTag:
+ SPAN({"class": "fbMenuSeparator"}),
+
+ memberIterator: function(items)
+ {
+ var result = [];
+
+ for (var i=0, length=items.length; i<length; i++)
+ {
+ var item = items[i];
+
+ // separator representation
+ if (typeof item == "string" && item.indexOf("-") == 0)
+ {
+ result.push({tag: this.separatorTag});
+ continue;
+ }
+
+ item = extend(item, {});
+
+ item.type = item.type || "";
+ item.value = item.value || "";
+
+ var type = item.type;
+
+ // default item representation
+ item.tag = this.itemTag;
+
+ var className = item.className || "";
+
+ className += "fbMenuOption fbHover ";
+
+ // specific representations
+ if (type == "checkbox")
+ {
+ className += "fbMenuCheckBox ";
+ item.tag = this.checkBoxTag;
+ }
+ else if (type == "radiobutton")
+ {
+ className += "fbMenuRadioButton ";
+ item.tag = this.radioButtonTag;
+ }
+ else if (type == "group")
+ {
+ className += "fbMenuGroup ";
+ item.tag = this.groupTag;
+ }
+ else if (type == "shortcut")
+ {
+ className += "fbMenuShortcut ";
+ item.tag = this.shortcutTag;
+ }
+
+ if (item.checked)
+ className += "fbMenuChecked ";
+ else if (item.selected)
+ className += "fbMenuRadioSelected ";
+
+ if (item.disabled)
+ className += "fbMenuDisabled ";
+
+ item.className = className;
+
+ item.label = $STR(item.label);
+
+ result.push(item);
+ }
+
+ return result;
+ }
+});
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/**
+ * options
+ * options.element
+ * options.id
+ * options.items
+ *
+ * item.label
+ * item.className
+ * item.type
+ * item.value
+ * item.disabled
+ * item.checked
+ * item.selected
+ * item.command
+ * item.child
+ *
+ *
+ * @class
+ * @extends FBL.Controller
+ *
+ */
+FBL.Menu = function(options)
+{
+ // if element is not pre-rendered, we must render it now
+ if (!options.element)
+ {
+ if (options.getItems)
+ options.items = options.getItems();
+
+ options.element = MenuPlate.tag.append(
+ {object: options},
+ getElementByClass(Firebug.chrome.document, "fbBody"),
+ MenuPlate
+ );
+ }
+
+ // extend itself with the provided options
+ append(this, options);
+
+ if (typeof this.element == "string")
+ {
+ this.id = this.element;
+ this.element = $(this.id);
+ }
+ else if (this.id)
+ {
+ this.element.id = this.id;
+ }
+
+ this.element.firebugIgnore = true;
+ this.elementStyle = this.element.style;
+
+ this.isVisible = false;
+
+ this.handleMouseDown = bind(this.handleMouseDown, this);
+ this.handleMouseOver = bind(this.handleMouseOver, this);
+ this.handleMouseOut = bind(this.handleMouseOut, this);
+
+ this.handleWindowMouseDown = bind(this.handleWindowMouseDown, this);
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var menuMap = {};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+Menu.prototype = extend(Controller,
+/**@extend FBL.Menu.prototype*/
+{
+ destroy: function()
+ {
+ //if (this.element) console.log("destroy", this.element.id);
+
+ this.hide();
+
+ // if it is a childMenu, remove its reference from the parentMenu
+ if (this.parentMenu)
+ this.parentMenu.childMenu = null;
+
+ // remove the element from the document
+ this.element.parentNode.removeChild(this.element);
+
+ // clear references
+ this.element = null;
+ this.elementStyle = null;
+ this.parentMenu = null;
+ this.parentTarget = null;
+ },
+
+ initialize: function()
+ {
+ Controller.initialize.call(this);
+
+ this.addController(
+ [this.element, "mousedown", this.handleMouseDown],
+ [this.element, "mouseover", this.handleMouseOver]
+ );
+ },
+
+ shutdown: function()
+ {
+ Controller.shutdown.call(this);
+ },
+
+ show: function(x, y)
+ {
+ this.initialize();
+
+ if (this.isVisible) return;
+
+ //console.log("show", this.element.id);
+
+ x = x || 0;
+ y = y || 0;
+
+ if (this.parentMenu)
+ {
+ var oldChildMenu = this.parentMenu.childMenu;
+ if (oldChildMenu && oldChildMenu != this)
+ {
+ oldChildMenu.destroy();
+ }
+
+ this.parentMenu.childMenu = this;
+ }
+ else
+ addEvent(Firebug.chrome.document, "mousedown", this.handleWindowMouseDown);
+
+ this.elementStyle.display = "block";
+ this.elementStyle.visibility = "hidden";
+
+ var size = Firebug.chrome.getSize();
+
+ x = Math.min(x, size.width - this.element.clientWidth - 10);
+ x = Math.max(x, 0);
+
+ y = Math.min(y, size.height - this.element.clientHeight - 10);
+ y = Math.max(y, 0);
+
+ this.elementStyle.left = x + "px";
+ this.elementStyle.top = y + "px";
+
+ this.elementStyle.visibility = "visible";
+
+ this.isVisible = true;
+
+ if (isFunction(this.onShow))
+ this.onShow.apply(this, arguments);
+ },
+
+ hide: function()
+ {
+ this.clearHideTimeout();
+ this.clearShowChildTimeout();
+
+ if (!this.isVisible) return;
+
+ //console.log("hide", this.element.id);
+
+ this.elementStyle.display = "none";
+
+ if(this.childMenu)
+ {
+ this.childMenu.destroy();
+ this.childMenu = null;
+ }
+
+ if(this.parentTarget)
+ removeClass(this.parentTarget, "fbMenuGroupSelected");
+
+ this.isVisible = false;
+
+ this.shutdown();
+
+ if (isFunction(this.onHide))
+ this.onHide.apply(this, arguments);
+ },
+
+ showChildMenu: function(target)
+ {
+ var id = target.getAttribute("child");
+
+ var parent = this;
+ var target = target;
+
+ this.showChildTimeout = Firebug.chrome.window.setTimeout(function(){
+
+ //if (!parent.isVisible) return;
+
+ var box = Firebug.chrome.getElementBox(target);
+
+ var childMenuObject = menuMap.hasOwnProperty(id) ?
+ menuMap[id] : {element: $(id)};
+
+ var childMenu = new Menu(extend(childMenuObject,
+ {
+ parentMenu: parent,
+ parentTarget: target
+ }));
+
+ var offsetLeft = isIE6 ? -1 : -6; // IE6 problem with fixed position
+ childMenu.show(box.left + box.width + offsetLeft, box.top -6);
+ setClass(target, "fbMenuGroupSelected");
+
+ },350);
+ },
+
+ clearHideTimeout: function()
+ {
+ if (this.hideTimeout)
+ {
+ Firebug.chrome.window.clearTimeout(this.hideTimeout);
+ delete this.hideTimeout;
+ }
+ },
+
+ clearShowChildTimeout: function()
+ {
+ if(this.showChildTimeout)
+ {
+ Firebug.chrome.window.clearTimeout(this.showChildTimeout);
+ this.showChildTimeout = null;
+ }
+ },
+
+ handleMouseDown: function(event)
+ {
+ cancelEvent(event, true);
+
+ var topParent = this;
+ while (topParent.parentMenu)
+ topParent = topParent.parentMenu;
+
+ var target = event.target || event.srcElement;
+
+ target = getAncestorByClass(target, "fbMenuOption");
+
+ if(!target || hasClass(target, "fbMenuGroup"))
+ return false;
+
+ if (target && !hasClass(target, "fbMenuDisabled"))
+ {
+ var type = target.getAttribute("type");
+
+ if (type == "checkbox")
+ {
+ var checked = target.getAttribute("checked");
+ var value = target.getAttribute("value");
+ var wasChecked = hasClass(target, "fbMenuChecked");
+
+ if (wasChecked)
+ {
+ removeClass(target, "fbMenuChecked");
+ target.setAttribute("checked", "");
+ }
+ else
+ {
+ setClass(target, "fbMenuChecked");
+ target.setAttribute("checked", "true");
+ }
+
+ if (isFunction(this.onCheck))
+ this.onCheck.call(this, target, value, !wasChecked);
+ }
+
+ if (type == "radiobutton")
+ {
+ var selectedRadios = getElementsByClass(target.parentNode, "fbMenuRadioSelected");
+
+ var group = target.getAttribute("group");
+
+ for (var i = 0, length = selectedRadios.length; i < length; i++)
+ {
+ radio = selectedRadios[i];
+
+ if (radio.getAttribute("group") == group)
+ {
+ removeClass(radio, "fbMenuRadioSelected");
+ radio.setAttribute("selected", "");
+ }
+ }
+
+ setClass(target, "fbMenuRadioSelected");
+ target.setAttribute("selected", "true");
+ }
+
+ var handler = null;
+
+ // target.command can be a function or a string.
+ var cmd = target.command;
+
+ // If it is a function it will be used as the handler
+ if (isFunction(cmd))
+ handler = cmd;
+ // If it is a string it the property of the current menu object
+ // will be used as the handler
+ else if (typeof cmd == "string")
+ handler = this[cmd];
+
+ var closeMenu = true;
+
+ if (handler)
+ closeMenu = handler.call(this, target) !== false;
+
+ if (closeMenu)
+ topParent.hide();
+ }
+
+ return false;
+ },
+
+ handleWindowMouseDown: function(event)
+ {
+ //console.log("handleWindowMouseDown");
+
+ var target = event.target || event.srcElement;
+
+ target = getAncestorByClass(target, "fbMenu");
+
+ if (!target)
+ {
+ removeEvent(Firebug.chrome.document, "mousedown", this.handleWindowMouseDown);
+ this.hide();
+ }
+ },
+
+ handleMouseOver: function(event)
+ {
+ //console.log("handleMouseOver", this.element.id);
+
+ this.clearHideTimeout();
+ this.clearShowChildTimeout();
+
+ var target = event.target || event.srcElement;
+
+ target = getAncestorByClass(target, "fbMenuOption");
+
+ if(!target)
+ return;
+
+ var childMenu = this.childMenu;
+ if(childMenu)
+ {
+ removeClass(childMenu.parentTarget, "fbMenuGroupSelected");
+
+ if (childMenu.parentTarget != target && childMenu.isVisible)
+ {
+ childMenu.clearHideTimeout();
+ childMenu.hideTimeout = Firebug.chrome.window.setTimeout(function(){
+ childMenu.destroy();
+ },300);
+ }
+ }
+
+ if(hasClass(target, "fbMenuGroup"))
+ {
+ this.showChildMenu(target);
+ }
+ }
+});
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+append(Menu,
+/**@extend FBL.Menu*/
+{
+ register: function(object)
+ {
+ menuMap[object.id] = object;
+ },
+
+ check: function(element)
+ {
+ setClass(element, "fbMenuChecked");
+ element.setAttribute("checked", "true");
+ },
+
+ uncheck: function(element)
+ {
+ removeClass(element, "fbMenuChecked");
+ element.setAttribute("checked", "");
+ },
+
+ disable: function(element)
+ {
+ setClass(element, "fbMenuDisabled");
+ },
+
+ enable: function(element)
+ {
+ removeClass(element, "fbMenuDisabled");
+ }
+});
+
+
+//************************************************************************************************
+// Status Bar
+
+/**@class*/
+function StatusBar(){};
+
+StatusBar.prototype = extend(Controller, {
+
+});
+
+// ************************************************************************************************
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /**@scope s_context*/ function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Globals
+
+var refreshDelay = 300;
+
+// Opera and some versions of webkit returns the wrong value of document.elementFromPoint()
+// function, without taking into account the scroll position. Safari 4 (webkit/531.21.8)
+// still have this issue. Google Chrome 4 (webkit/532.5) does not. So, we're assuming this
+// issue was fixed in the 532 version
+var shouldFixElementFromPoint = isOpera || isSafari && browserVersion < "532";
+
+var evalError = "___firebug_evaluation_error___";
+var pixelsPerInch;
+
+var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
+var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";
+
+
+// ************************************************************************************************
+// Context
+
+/** @class */
+FBL.Context = function(win)
+{
+ this.window = win.window;
+ this.document = win.document;
+
+ this.browser = Env.browser;
+
+ // Some windows in IE, like iframe, doesn't have the eval() method
+ if (isIE && !this.window.eval)
+ {
+ // But after executing the following line the method magically appears!
+ this.window.execScript("null");
+ // Just to make sure the "magic" really happened
+ if (!this.window.eval)
+ throw new Error("Firebug Error: eval() method not found in this window");
+ }
+
+ // Create a new "black-box" eval() method that runs in the global namespace
+ // of the context window, without exposing the local variables declared
+ // by the function that calls it
+ this.eval = this.window.eval("new Function('" +
+ "try{ return window.eval.apply(window,arguments) }catch(E){ E."+evalError+"=true; return E }" +
+ "')");
+};
+
+FBL.Context.prototype =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // partial-port of Firebug tabContext.js
+
+ browser: null,
+ loaded: true,
+
+ setTimeout: function(fn, delay)
+ {
+ var win = this.window;
+
+ if (win.setTimeout == this.setTimeout)
+ throw new Error("setTimeout recursion");
+
+ var timeout = win.setTimeout.apply ? // IE doesn't have apply method on setTimeout
+ win.setTimeout.apply(win, arguments) :
+ win.setTimeout(fn, delay);
+
+ if (!this.timeouts)
+ this.timeouts = {};
+
+ this.timeouts[timeout] = 1;
+
+ return timeout;
+ },
+
+ clearTimeout: function(timeout)
+ {
+ clearTimeout(timeout);
+
+ if (this.timeouts)
+ delete this.timeouts[timeout];
+ },
+
+ setInterval: function(fn, delay)
+ {
+ var win = this.window;
+
+ var timeout = win.setInterval.apply ? // IE doesn't have apply method on setTimeout
+ win.setInterval.apply(win, arguments) :
+ win.setInterval(fn, delay);
+
+ if (!this.intervals)
+ this.intervals = {};
+
+ this.intervals[timeout] = 1;
+
+ return timeout;
+ },
+
+ clearInterval: function(timeout)
+ {
+ clearInterval(timeout);
+
+ if (this.intervals)
+ delete this.intervals[timeout];
+ },
+
+ invalidatePanels: function()
+ {
+ if (!this.invalidPanels)
+ this.invalidPanels = {};
+
+ for (var i = 0; i < arguments.length; ++i)
+ {
+ var panelName = arguments[i];
+
+ // avoid error. need to create a better getPanel() function as explained below
+ if (!Firebug.chrome || !Firebug.chrome.selectedPanel)
+ return;
+
+ //var panel = this.getPanel(panelName, true);
+ //TODO: xxxpedro context how to get all panels using a single function?
+ // the current workaround to make the invalidation works is invalidating
+ // only sidePanels. There's also a problem with panel name (LowerCase in Firebug Lite)
+ var panel = Firebug.chrome.selectedPanel.sidePanelBar ?
+ Firebug.chrome.selectedPanel.sidePanelBar.getPanel(panelName, true) :
+ null;
+
+ if (panel && !panel.noRefresh)
+ this.invalidPanels[panelName] = 1;
+ }
+
+ if (this.refreshTimeout)
+ {
+ this.clearTimeout(this.refreshTimeout);
+ delete this.refreshTimeout;
+ }
+
+ this.refreshTimeout = this.setTimeout(bindFixed(function()
+ {
+ var invalids = [];
+
+ for (var panelName in this.invalidPanels)
+ {
+ //var panel = this.getPanel(panelName, true);
+ //TODO: xxxpedro context how to get all panels using a single function?
+ // the current workaround to make the invalidation works is invalidating
+ // only sidePanels. There's also a problem with panel name (LowerCase in Firebug Lite)
+ var panel = Firebug.chrome.selectedPanel.sidePanelBar ?
+ Firebug.chrome.selectedPanel.sidePanelBar.getPanel(panelName, true) :
+ null;
+
+ if (panel)
+ {
+ if (panel.visible && !panel.editing)
+ panel.refresh();
+ else
+ panel.needsRefresh = true;
+
+ // If the panel is being edited, we'll keep trying to
+ // refresh it until editing is done
+ if (panel.editing)
+ invalids.push(panelName);
+ }
+ }
+
+ delete this.invalidPanels;
+ delete this.refreshTimeout;
+
+ // Keep looping until every tab is valid
+ if (invalids.length)
+ this.invalidatePanels.apply(this, invalids);
+ }, this), refreshDelay);
+ },
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Evalutation Method
+
+ /**
+ * Evaluates an expression in the current context window.
+ *
+ * @param {String} expr expression to be evaluated
+ *
+ * @param {String} context string indicating the global location
+ * of the object that will be used as the
+ * context. The context is referred in
+ * the expression as the "this" keyword.
+ * If no context is informed, the "window"
+ * context is used.
+ *
+ * @param {String} api string indicating the global location
+ * of the object that will be used as the
+ * api of the evaluation.
+ *
+ * @param {Function} errorHandler(message) error handler to be called
+ * if the evaluation fails.
+ */
+ evaluate: function(expr, context, api, errorHandler)
+ {
+ // the default context is the "window" object. It can be any string that represents
+ // a global accessible element as: "my.namespaced.object"
+ context = context || "window";
+
+ var isObjectLiteral = trim(expr).indexOf("{") == 0,
+ cmd,
+ result;
+
+ // if the context is the "window" object, we don't need a closure
+ if (context == "window")
+ {
+ // If it is an object literal, then wrap the expression with parenthesis so we can
+ // capture the return value
+ if (isObjectLiteral)
+ {
+ cmd = api ?
+ "with("+api+"){ ("+expr+") }" :
+ "(" + expr + ")";
+ }
+ else
+ {
+ cmd = api ?
+ "with("+api+"){ "+expr+" }" :
+ expr;
+ }
+ }
+ else
+ {
+ cmd = api ?
+ // with API and context, no return value
+ "(function(arguments){ with(" + api + "){ " +
+ expr +
+ " } }).call(" + context + ",undefined)"
+ :
+ // with context only, no return value
+ "(function(arguments){ " +
+ expr +
+ " }).call(" + context + ",undefined)";
+ }
+
+ result = this.eval(cmd);
+
+ if (result && result[evalError])
+ {
+ var msg = result.name ? (result.name + ": ") : "";
+ msg += result.message || result;
+
+ if (errorHandler)
+ result = errorHandler(msg);
+ else
+ result = msg;
+ }
+
+ return result;
+ },
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Window Methods
+
+ getWindowSize: function()
+ {
+ var width=0, height=0, el;
+
+ if (typeof this.window.innerWidth == "number")
+ {
+ width = this.window.innerWidth;
+ height = this.window.innerHeight;
+ }
+ else if ((el=this.document.documentElement) && (el.clientHeight || el.clientWidth))
+ {
+ width = el.clientWidth;
+ height = el.clientHeight;
+ }
+ else if ((el=this.document.body) && (el.clientHeight || el.clientWidth))
+ {
+ width = el.clientWidth;
+ height = el.clientHeight;
+ }
+
+ return {width: width, height: height};
+ },
+
+ getWindowScrollSize: function()
+ {
+ var width=0, height=0, el;
+
+ // first try the document.documentElement scroll size
+ if (!isIEQuiksMode && (el=this.document.documentElement) &&
+ (el.scrollHeight || el.scrollWidth))
+ {
+ width = el.scrollWidth;
+ height = el.scrollHeight;
+ }
+
+ // then we need to check if document.body has a bigger scroll size value
+ // because sometimes depending on the browser and the page, the document.body
+ // scroll size returns a smaller (and wrong) measure
+ if ((el=this.document.body) && (el.scrollHeight || el.scrollWidth) &&
+ (el.scrollWidth > width || el.scrollHeight > height))
+ {
+ width = el.scrollWidth;
+ height = el.scrollHeight;
+ }
+
+ return {width: width, height: height};
+ },
+
+ getWindowScrollPosition: function()
+ {
+ var top=0, left=0, el;
+
+ if(typeof this.window.pageYOffset == "number")
+ {
+ top = this.window.pageYOffset;
+ left = this.window.pageXOffset;
+ }
+ else if((el=this.document.body) && (el.scrollTop || el.scrollLeft))
+ {
+ top = el.scrollTop;
+ left = el.scrollLeft;
+ }
+ else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft))
+ {
+ top = el.scrollTop;
+ left = el.scrollLeft;
+ }
+
+ return {top:top, left:left};
+ },
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Element Methods
+
+ getElementFromPoint: function(x, y)
+ {
+ if (shouldFixElementFromPoint)
+ {
+ var scroll = this.getWindowScrollPosition();
+ return this.document.elementFromPoint(x + scroll.left, y + scroll.top);
+ }
+ else
+ return this.document.elementFromPoint(x, y);
+ },
+
+ getElementPosition: function(el)
+ {
+ var left = 0;
+ var top = 0;
+
+ do
+ {
+ left += el.offsetLeft;
+ top += el.offsetTop;
+ }
+ while (el = el.offsetParent);
+
+ return {left:left, top:top};
+ },
+
+ getElementBox: function(el)
+ {
+ var result = {};
+
+ if (el.getBoundingClientRect)
+ {
+ var rect = el.getBoundingClientRect();
+
+ // fix IE problem with offset when not in fullscreen mode
+ var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0;
+
+ var scroll = this.getWindowScrollPosition();
+
+ result.top = Math.round(rect.top - offset + scroll.top);
+ result.left = Math.round(rect.left - offset + scroll.left);
+ result.height = Math.round(rect.bottom - rect.top);
+ result.width = Math.round(rect.right - rect.left);
+ }
+ else
+ {
+ var position = this.getElementPosition(el);
+
+ result.top = position.top;
+ result.left = position.left;
+ result.height = el.offsetHeight;
+ result.width = el.offsetWidth;
+ }
+
+ return result;
+ },
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Measurement Methods
+
+ getMeasurement: function(el, name)
+ {
+ var result = {value: 0, unit: "px"};
+
+ var cssValue = this.getStyle(el, name);
+
+ if (!cssValue) return result;
+ if (cssValue.toLowerCase() == "auto") return result;
+
+ var reMeasure = /(\d+\.?\d*)(.*)/;
+ var m = cssValue.match(reMeasure);
+
+ if (m)
+ {
+ result.value = m[1]-0;
+ result.unit = m[2].toLowerCase();
+ }
+
+ return result;
+ },
+
+ getMeasurementInPixels: function(el, name)
+ {
+ if (!el) return null;
+
+ var m = this.getMeasurement(el, name);
+ var value = m.value;
+ var unit = m.unit;
+
+ if (unit == "px")
+ return value;
+
+ else if (unit == "pt")
+ return this.pointsToPixels(name, value);
+
+ else if (unit == "em")
+ return this.emToPixels(el, value);
+
+ else if (unit == "%")
+ return this.percentToPixels(el, value);
+
+ else if (unit == "ex")
+ return this.exToPixels(el, value);
+
+ // TODO: add other units. Maybe create a better general way
+ // to calculate measurements in different units.
+ },
+
+ getMeasurementBox1: function(el, name)
+ {
+ var sufixes = ["Top", "Left", "Bottom", "Right"];
+ var result = [];
+
+ for(var i=0, sufix; sufix=sufixes[i]; i++)
+ result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix));
+
+ return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
+ },
+
+ getMeasurementBox: function(el, name)
+ {
+ var result = [];
+ var sufixes = name == "border" ?
+ ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] :
+ ["Top", "Left", "Bottom", "Right"];
+
+ if (isIE)
+ {
+ var propName, cssValue;
+ var autoMargin = null;
+
+ for(var i=0, sufix; sufix=sufixes[i]; i++)
+ {
+ propName = name + sufix;
+
+ cssValue = el.currentStyle[propName] || el.style[propName];
+
+ if (cssValue == "auto")
+ {
+ if (!autoMargin)
+ autoMargin = this.getCSSAutoMarginBox(el);
+
+ result[i] = autoMargin[sufix.toLowerCase()];
+ }
+ else
+ result[i] = this.getMeasurementInPixels(el, propName);
+
+ }
+
+ }
+ else
+ {
+ for(var i=0, sufix; sufix=sufixes[i]; i++)
+ result[i] = this.getMeasurementInPixels(el, name + sufix);
+ }
+
+ return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
+ },
+
+ getCSSAutoMarginBox: function(el)
+ {
+ if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1)
+ return {top:0, left:0, bottom:0, right:0};
+ /**/
+
+ if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1)
+ return {top:0, left:0, bottom:0, right:0};
+ /**/
+
+ var offsetTop = 0;
+ if (false && isIEStantandMode)
+ {
+ var scrollSize = Firebug.browser.getWindowScrollSize();
+ offsetTop = scrollSize.height;
+ }
+
+ var box = this.document.createElement("div");
+ //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;";
+ box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;";
+
+ var clone = el.cloneNode(false);
+ var text = this.document.createTextNode("&nbsp;");
+ clone.appendChild(text);
+
+ box.appendChild(clone);
+
+ this.document.body.appendChild(box);
+
+ var marginTop = clone.offsetTop - box.offsetTop - 1;
+ var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop;
+
+ var marginLeft = clone.offsetLeft - box.offsetLeft - 1;
+ var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft;
+
+ this.document.body.removeChild(box);
+
+ return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight};
+ },
+
+ getFontSizeInPixels: function(el)
+ {
+ var size = this.getMeasurement(el, "fontSize");
+
+ if (size.unit == "px") return size.value;
+
+ // get font size, the dirty way
+ var computeDirtyFontSize = function(el, calibration)
+ {
+ var div = this.document.createElement("div");
+ var divStyle = offscreenStyle;
+
+ if (calibration)
+ divStyle += " font-size:"+calibration+"px;";
+
+ div.style.cssText = divStyle;
+ div.innerHTML = "A";
+ el.appendChild(div);
+
+ var value = div.offsetHeight;
+ el.removeChild(div);
+ return value;
+ };
+
+ /*
+ var calibrationBase = 200;
+ var calibrationValue = computeDirtyFontSize(el, calibrationBase);
+ var rate = calibrationBase / calibrationValue;
+ /**/
+
+ // the "dirty technique" fails in some environments, so we're using a static value
+ // based in some tests.
+ var rate = 200 / 225;
+
+ var value = computeDirtyFontSize(el);
+
+ return value * rate;
+ },
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Unit Funtions
+
+ pointsToPixels: function(name, value, returnFloat)
+ {
+ var axis = /Top$|Bottom$/.test(name) ? "y" : "x";
+
+ var result = value * pixelsPerInch[axis] / 72;
+
+ return returnFloat ? result : Math.round(result);
+ },
+
+ emToPixels: function(el, value)
+ {
+ if (!el) return null;
+
+ var fontSize = this.getFontSizeInPixels(el);
+
+ return Math.round(value * fontSize);
+ },
+
+ exToPixels: function(el, value)
+ {
+ if (!el) return null;
+
+ // get ex value, the dirty way
+ var div = this.document.createElement("div");
+ div.style.cssText = offscreenStyle + "width:"+value + "ex;";
+
+ el.appendChild(div);
+ var value = div.offsetWidth;
+ el.removeChild(div);
+
+ return value;
+ },
+
+ percentToPixels: function(el, value)
+ {
+ if (!el) return null;
+
+ // get % value, the dirty way
+ var div = this.document.createElement("div");
+ div.style.cssText = offscreenStyle + "width:"+value + "%;";
+
+ el.appendChild(div);
+ var value = div.offsetWidth;
+ el.removeChild(div);
+
+ return value;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getStyle: isIE ? function(el, name)
+ {
+ return el.currentStyle[name] || el.style[name] || undefined;
+ }
+ : function(el, name)
+ {
+ return this.document.defaultView.getComputedStyle(el,null)[name]
+ || el.style[name] || undefined;
+ }
+
+};
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Globals
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Window Options
+
+var WindowDefaultOptions =
+ {
+ type: "frame",
+ id: "FirebugUI"
+ //height: 350 // obsolete
+ },
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Instantiated objects
+
+ commandLine,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Interface Elements Cache
+
+ fbTop,
+ fbContent,
+ fbContentStyle,
+ fbBottom,
+ fbBtnInspect,
+
+ fbToolbar,
+
+ fbPanelBox1,
+ fbPanelBox1Style,
+ fbPanelBox2,
+ fbPanelBox2Style,
+ fbPanelBar2Box,
+ fbPanelBar2BoxStyle,
+
+ fbHSplitter,
+ fbVSplitter,
+ fbVSplitterStyle,
+
+ fbPanel1,
+ fbPanel1Style,
+ fbPanel2,
+ fbPanel2Style,
+
+ fbConsole,
+ fbConsoleStyle,
+ fbHTML,
+
+ fbCommandLine,
+ fbLargeCommandLine,
+ fbLargeCommandButtons,
+
+//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Cached size values
+
+ topHeight,
+ topPartialHeight,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ lastSelectedPanelName,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ focusCommandLineState = 0,
+ lastFocusedPanelName,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ lastHSplitterMouseMove = 0,
+ onHSplitterMouseMoveBuffer = null,
+ onHSplitterMouseMoveTimer = null,
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ lastVSplitterMouseMove = 0;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+
+// ************************************************************************************************
+// FirebugChrome
+
+FBL.defaultPersistedState =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ isOpen: false,
+ height: 300,
+ sidePanelWidth: 350,
+
+ selectedPanelName: "Console",
+ selectedHTMLElementId: null,
+
+ htmlSelectionStack: []
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+};
+
+/**@namespace*/
+FBL.FirebugChrome =
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ //isOpen: false,
+ //height: 300,
+ //sidePanelWidth: 350,
+
+ //selectedPanelName: "Console",
+ //selectedHTMLElementId: null,
+
+ chromeMap: {},
+
+ htmlSelectionStack: [],
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ create: function()
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window");
+
+ createChromeWindow();
+ },
+
+ initialize: function()
+ {
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window");
+
+ if (Env.chrome.type == "frame" || Env.chrome.type == "div")
+ ChromeMini.create(Env.chrome);
+
+ var chrome = Firebug.chrome = new Chrome(Env.chrome);
+ FirebugChrome.chromeMap[chrome.type] = chrome;
+
+ addGlobalEvent("keydown", onGlobalKeyDown);
+
+ if (Env.Options.enablePersistent && chrome.type == "popup")
+ {
+ // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode
+ var frame = FirebugChrome.chromeMap.frame;
+ if (frame)
+ frame.close();
+
+ //chrome.reattach(frame, chrome);
+ //TODO: xxxpedro persist synchronize?
+ chrome.initialize();
+ }
+ },
+
+ clone: function(FBChrome)
+ {
+ for (var name in FBChrome)
+ {
+ var prop = FBChrome[name];
+ if (FBChrome.hasOwnProperty(name) && !isFunction(prop))
+ {
+ this[name] = prop;
+ }
+ }
+ }
+};
+
+
+
+// ************************************************************************************************
+// Chrome Window Creation
+
+var createChromeWindow = function(options)
+{
+ options = extend(WindowDefaultOptions, options || {});
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Locals
+
+ var browserWin = Env.browser.window;
+ var browserContext = new Context(browserWin);
+ var prefs = Store.get("FirebugLite");
+ var persistedState = prefs && prefs.persistedState || defaultPersistedState;
+
+ var chrome = {},
+
+ context = options.context || Env.browser,
+
+ type = chrome.type = Env.Options.enablePersistent ?
+ "popup" :
+ options.type,
+
+ isChromeFrame = type == "frame",
+
+ useLocalSkin = Env.useLocalSkin,
+
+ url = useLocalSkin ?
+ Env.Location.skin :
+ "about:blank",
+
+ // document.body not available in XML+XSL documents in Firefox
+ body = context.document.getElementsByTagName("body")[0],
+
+ formatNode = function(node)
+ {
+ if (!Env.isDebugMode)
+ {
+ node.firebugIgnore = true;
+ }
+
+ var browserWinSize = browserContext.getWindowSize();
+ var height = persistedState.height || 300;
+
+ height = Math.min(browserWinSize.height, height);
+ height = Math.max(200, height);
+
+ node.style.border = "0";
+ node.style.visibility = "hidden";
+ node.style.zIndex = "2147483647"; // MAX z-index = 2147483647
+ node.style.position = noFixedPosition ? "absolute" : "fixed";
+ node.style.width = "100%"; // "102%"; IE auto margin bug
+ node.style.left = "0";
+ node.style.bottom = noFixedPosition ? "-1px" : "0";
+ node.style.height = height + "px";
+
+ // avoid flickering during chrome rendering
+ //if (isFirefox)
+ // node.style.display = "none";
+ },
+
+ createChromeDiv = function()
+ {
+ //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed.");
+
+ var node = chrome.node = createGlobalElement("div"),
+ style = createGlobalElement("style"),
+
+ css = FirebugChrome.Skin.CSS
+ /*
+ .replace(/;/g, " !important;")
+ .replace(/!important\s!important/g, "!important")
+ .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/,
+
+ // reset some styles to minimize interference from the main page's style
+ rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" +
+ // load the chrome styles
+ css +
+ // adjust some remaining styles
+ ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}";
+ /*
+ if (isIE)
+ {
+ // IE7 CSS bug (FbChrome table bigger than its parent div)
+ rules += ".fbBody table.fbChrome{position: static !important;}";
+ }/**/
+
+ style.type = "text/css";
+
+ if (style.styleSheet)
+ style.styleSheet.cssText = rules;
+ else
+ style.appendChild(context.document.createTextNode(rules));
+
+ document.getElementsByTagName("head")[0].appendChild(style);
+
+ node.className = "fbBody";
+ node.style.overflow = "hidden";
+ node.innerHTML = getChromeDivTemplate();
+
+ if (isIE)
+ {
+ // IE7 CSS bug (FbChrome table bigger than its parent div)
+ setTimeout(function(){
+ node.firstChild.style.height = "1px";
+ node.firstChild.style.position = "static";
+ },0);
+ /**/
+ }
+
+ formatNode(node);
+
+ body.appendChild(node);
+
+ chrome.window = window;
+ chrome.document = document;
+ onChromeLoad(chrome);
+ };
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ try
+ {
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create the Chrome as a "div" (windowless mode)
+ if (type == "div")
+ {
+ createChromeDiv();
+ return;
+ }
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // cretate the Chrome as an "iframe"
+ else if (isChromeFrame)
+ {
+ // Create the Chrome Frame
+ var node = chrome.node = createGlobalElement("iframe");
+ node.setAttribute("src", url);
+ node.setAttribute("frameBorder", "0");
+
+ formatNode(node);
+
+ body.appendChild(node);
+
+ // must set the id after appending to the document, otherwise will cause an
+ // strange error in IE, making the iframe load the page in which the bookmarklet
+ // was created (like getfirebug.com), before loading the injected UI HTML,
+ // generating an "Access Denied" error.
+ node.id = options.id;
+ }
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create the Chrome as a "popup"
+ else
+ {
+ var height = persistedState.popupHeight || 300;
+ var browserWinSize = browserContext.getWindowSize();
+
+ var browserWinLeft = typeof browserWin.screenX == "number" ?
+ browserWin.screenX : browserWin.screenLeft;
+
+ var popupLeft = typeof persistedState.popupLeft == "number" ?
+ persistedState.popupLeft : browserWinLeft;
+
+ var browserWinTop = typeof browserWin.screenY == "number" ?
+ browserWin.screenY : browserWin.screenTop;
+
+ var popupTop = typeof persistedState.popupTop == "number" ?
+ persistedState.popupTop :
+ Math.max(
+ 0,
+ Math.min(
+ browserWinTop + browserWinSize.height - height,
+ // Google Chrome bug
+ screen.availHeight - height - 61
+ )
+ );
+
+ var popupWidth = typeof persistedState.popupWidth == "number" ?
+ persistedState.popupWidth :
+ Math.max(
+ 0,
+ Math.min(
+ browserWinSize.width,
+ // Opera opens popup in a new tab if it's too big!
+ screen.availWidth-10
+ )
+ );
+
+ var popupHeight = typeof persistedState.popupHeight == "number" ?
+ persistedState.popupHeight : 300;
+
+ var options = [
+ "true,top=", popupTop,
+ ",left=", popupLeft,
+ ",height=", popupHeight,
+ ",width=", popupWidth,
+ ",resizable"
+ ].join(""),
+
+ node = chrome.node = context.window.open(
+ url,
+ "popup",
+ options
+ );
+
+ if (node)
+ {
+ try
+ {
+ node.focus();
+ }
+ catch(E)
+ {
+ alert("Firebug Error: Firebug popup was blocked.");
+ return;
+ }
+ }
+ else
+ {
+ alert("Firebug Error: Firebug popup was blocked.");
+ return;
+ }
+ }
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Inject the interface HTML if it is not using the local skin
+
+ if (!useLocalSkin)
+ {
+ var tpl = getChromeTemplate(!isChromeFrame),
+ doc = isChromeFrame ? node.contentWindow.document : node.document;
+
+ doc.write(tpl);
+ doc.close();
+ }
+
+ //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Wait the Window to be loaded
+
+ var win,
+
+ waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100,
+
+ waitForWindow = function()
+ {
+ if ( // Frame loaded... OR
+ isChromeFrame && (win=node.contentWindow) &&
+ node.contentWindow.document.getElementById("fbCommandLine") ||
+
+ // Popup loaded
+ !isChromeFrame && (win=node.window) && node.document &&
+ node.document.getElementById("fbCommandLine") )
+ {
+ chrome.window = win.window;
+ chrome.document = win.document;
+
+ // Prevent getting the wrong chrome height in FF when opening a popup
+ setTimeout(function(){
+ onChromeLoad(chrome);
+ }, useLocalSkin ? 200 : 0);
+ }
+ else
+ setTimeout(waitForWindow, waitDelay);
+ };
+
+ waitForWindow();
+ }
+ catch(e)
+ {
+ var msg = e.message || e;
+
+ if (/access/i.test(msg))
+ {
+ // Firebug Lite could not create a window for its Graphical User Interface due to
+ // a access restriction. This happens in some pages, when loading via bookmarklet.
+ // In such cases, the only way is to load the GUI in a "windowless mode".
+
+ if (isChromeFrame)
+ body.removeChild(node);
+ else if(type == "popup")
+ node.close();
+
+ // Load the GUI in a "windowless mode"
+ createChromeDiv();
+ }
+ else
+ {
+ alert("Firebug Error: Firebug GUI could not be created.");
+ }
+ }
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var onChromeLoad = function onChromeLoad(chrome)
+{
+ Env.chrome = chrome;
+
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded");
+
+ if (Env.Options.enablePersistent)
+ {
+ // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode
+ Env.FirebugChrome = FirebugChrome;
+
+ chrome.window.Firebug = chrome.window.Firebug || {};
+ chrome.window.Firebug.SharedEnv = Env;
+
+ if (Env.isDevelopmentMode)
+ {
+ Env.browser.window.FBDev.loadChromeApplication(chrome);
+ }
+ else
+ {
+ var doc = chrome.document;
+ var script = doc.createElement("script");
+ script.src = Env.Location.app + "#remote,persist";
+ doc.getElementsByTagName("head")[0].appendChild(script);
+ }
+ }
+ else
+ {
+ if (chrome.type == "frame" || chrome.type == "div")
+ {
+ // initialize the chrome application
+ setTimeout(function(){
+ FBL.Firebug.initialize();
+ },0);
+ }
+ else if (chrome.type == "popup")
+ {
+ var oldChrome = FirebugChrome.chromeMap.frame;
+
+ var newChrome = new Chrome(chrome);
+
+ // TODO: xxxpedro sync detach reattach attach
+ dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]);
+
+ newChrome.reattach(oldChrome, newChrome);
+ }
+ }
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var getChromeDivTemplate = function()
+{
+ return FirebugChrome.Skin.HTML;
+};
+
+var getChromeTemplate = function(isPopup)
+{
+ var tpl = FirebugChrome.Skin;
+ var r = [], i = -1;
+
+ r[++i] = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/DTD/strict.dtd">';
+ r[++i] = '<html><head><title>';
+ r[++i] = Firebug.version;
+
+ /*
+ r[++i] = '</title><link href="';
+ r[++i] = Env.Location.skinDir + 'firebug.css';
+ r[++i] = '" rel="stylesheet" type="text/css" />';
+ /**/
+
+ r[++i] = '</title><style>html,body{margin:0;padding:0;overflow:hidden;}';
+ r[++i] = tpl.CSS;
+ r[++i] = '</style>';
+ /**/
+
+ r[++i] = '</head><body class="fbBody' + (isPopup ? ' FirebugPopup' : '') + '">';
+ r[++i] = tpl.HTML;
+ r[++i] = '</body></html>';
+
+ return r.join("");
+};
+
+
+// ************************************************************************************************
+// Chrome Class
+
+/**@class*/
+var Chrome = function Chrome(chrome)
+{
+ var type = chrome.type;
+ var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase;
+
+ append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase)
+ append(this, chrome); // inherit chrome window properties
+ append(this, new Context(chrome.window)); // inherit from Context class
+
+ FirebugChrome.chromeMap[type] = this;
+ Firebug.chrome = this;
+ Env.chrome = chrome.window;
+
+ this.commandLineVisible = false;
+ this.sidePanelVisible = false;
+
+ this.create();
+
+ return this;
+};
+
+// ************************************************************************************************
+// ChromeBase
+
+/**
+ * @namespace
+ * @extends FBL.Controller
+ * @extends FBL.PanelBar
+ **/
+var ChromeBase = {};
+append(ChromeBase, Controller);
+append(ChromeBase, PanelBar);
+append(ChromeBase,
+/**@extend ns-chrome-ChromeBase*/
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // inherited properties
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // inherited from createChrome function
+
+ node: null,
+ type: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // inherited from Context.prototype
+
+ document: null,
+ window: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // value properties
+
+ sidePanelVisible: false,
+ commandLineVisible: false,
+ largeCommandLineVisible: false,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // object properties
+
+ inspectButton: null,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ create: function()
+ {
+ PanelBar.create.call(this);
+
+ if (Firebug.Inspector)
+ this.inspectButton = new Button({
+ type: "toggle",
+ element: $("fbChrome_btInspect"),
+ owner: Firebug.Inspector,
+
+ onPress: Firebug.Inspector.startInspecting,
+ onUnpress: Firebug.Inspector.stopInspecting
+ });
+ },
+
+ destroy: function()
+ {
+ if(Firebug.Inspector)
+ this.inspectButton.destroy();
+
+ PanelBar.destroy.call(this);
+
+ this.shutdown();
+ },
+
+ testMenu: function()
+ {
+ var firebugMenu = new Menu(
+ {
+ id: "fbFirebugMenu",
+
+ items:
+ [
+ {
+ label: "Open Firebug",
+ type: "shortcut",
+ key: isFirefox ? "Shift+F12" : "F12",
+ checked: true,
+ command: "toggleChrome"
+ },
+ {
+ label: "Open Firebug in New Window",
+ type: "shortcut",
+ key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12",
+ command: "openPopup"
+ },
+ {
+ label: "Inspect Element",
+ type: "shortcut",
+ key: "Ctrl+Shift+C",
+ command: "toggleInspect"
+ },
+ {
+ label: "Command Line",
+ type: "shortcut",
+ key: "Ctrl+Shift+L",
+ command: "focusCommandLine"
+ },
+ "-",
+ {
+ label: "Options",
+ type: "group",
+ child: "fbFirebugOptionsMenu"
+ },
+ "-",
+ {
+ label: "Firebug Lite Website...",
+ command: "visitWebsite"
+ },
+ {
+ label: "Discussion Group...",
+ command: "visitDiscussionGroup"
+ },
+ {
+ label: "Issue Tracker...",
+ command: "visitIssueTracker"
+ }
+ ],
+
+ onHide: function()
+ {
+ iconButton.restore();
+ },
+
+ toggleChrome: function()
+ {
+ Firebug.chrome.toggle();
+ },
+
+ openPopup: function()
+ {
+ Firebug.chrome.toggle(true, true);
+ },
+
+ toggleInspect: function()
+ {
+ Firebug.Inspector.toggleInspect();
+ },
+
+ focusCommandLine: function()
+ {
+ Firebug.chrome.focusCommandLine();
+ },
+
+ visitWebsite: function()
+ {
+ this.visit("http://getfirebug.com/lite.html");
+ },
+
+ visitDiscussionGroup: function()
+ {
+ this.visit("http://groups.google.com/group/firebug");
+ },
+
+ visitIssueTracker: function()
+ {
+ this.visit("http://code.google.com/p/fbug/issues/list");
+ },
+
+ visit: function(url)
+ {
+ window.open(url);
+ }
+
+ });
+
+ /**@private*/
+ var firebugOptionsMenu =
+ {
+ id: "fbFirebugOptionsMenu",
+
+ getItems: function()
+ {
+ var cookiesDisabled = !Firebug.saveCookies;
+
+ return [
+ {
+ label: "Start Opened",
+ type: "checkbox",
+ value: "startOpened",
+ checked: Firebug.startOpened,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Start in New Window",
+ type: "checkbox",
+ value: "startInNewWindow",
+ checked: Firebug.startInNewWindow,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Show Icon When Hidden",
+ type: "checkbox",
+ value: "showIconWhenHidden",
+ checked: Firebug.showIconWhenHidden,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Override Console Object",
+ type: "checkbox",
+ value: "overrideConsole",
+ checked: Firebug.overrideConsole,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Ignore Firebug Elements",
+ type: "checkbox",
+ value: "ignoreFirebugElements",
+ checked: Firebug.ignoreFirebugElements,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Disable When Firebug Active",
+ type: "checkbox",
+ value: "disableWhenFirebugActive",
+ checked: Firebug.disableWhenFirebugActive,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Disable XHR Listener",
+ type: "checkbox",
+ value: "disableXHRListener",
+ checked: Firebug.disableXHRListener,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Disable Resource Fetching",
+ type: "checkbox",
+ value: "disableResourceFetching",
+ checked: Firebug.disableResourceFetching,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Enable Trace Mode",
+ type: "checkbox",
+ value: "enableTrace",
+ checked: Firebug.enableTrace,
+ disabled: cookiesDisabled
+ },
+ {
+ label: "Enable Persistent Mode (experimental)",
+ type: "checkbox",
+ value: "enablePersistent",
+ checked: Firebug.enablePersistent,
+ disabled: cookiesDisabled
+ },
+ "-",
+ {
+ label: "Reset All Firebug Options",
+ command: "restorePrefs",
+ disabled: cookiesDisabled
+ }
+ ];
+ },
+
+ onCheck: function(target, value, checked)
+ {
+ Firebug.setPref(value, checked);
+ },
+
+ restorePrefs: function(target)
+ {
+ Firebug.erasePrefs();
+
+ if (target)
+ this.updateMenu(target);
+ },
+
+ updateMenu: function(target)
+ {
+ var options = getElementsByClass(target.parentNode, "fbMenuOption");
+
+ var firstOption = options[0];
+ var enabled = Firebug.saveCookies;
+ if (enabled)
+ Menu.check(firstOption);
+ else
+ Menu.uncheck(firstOption);
+
+ if (enabled)
+ Menu.check(options[0]);
+ else
+ Menu.uncheck(options[0]);
+
+ for (var i = 1, length = options.length; i < length; i++)
+ {
+ var option = options[i];
+
+ var value = option.getAttribute("value");
+ var pref = Firebug[value];
+
+ if (pref)
+ Menu.check(option);
+ else
+ Menu.uncheck(option);
+
+ if (enabled)
+ Menu.enable(option);
+ else
+ Menu.disable(option);
+ }
+ }
+ };
+
+ Menu.register(firebugOptionsMenu);
+
+ var menu = firebugMenu;
+
+ var testMenuClick = function(event)
+ {
+ //console.log("testMenuClick");
+ cancelEvent(event, true);
+
+ var target = event.target || event.srcElement;
+
+ if (menu.isVisible)
+ menu.hide();
+ else
+ {
+ var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position
+
+ chrome = Firebug.chrome,
+
+ box = chrome.getElementBox(target),
+
+ offset = chrome.type == "div" ?
+ chrome.getElementPosition(chrome.node) :
+ {top: 0, left: 0};
+
+ menu.show(
+ box.left + offsetLeft - offset.left,
+ box.top + box.height -5 - offset.top
+ );
+ }
+
+ return false;
+ };
+
+ var iconButton = new IconButton({
+ type: "toggle",
+ element: $("fbFirebugButton"),
+
+ onClick: testMenuClick
+ });
+
+ iconButton.initialize();
+
+ //addEvent($("fbToolbarIcon"), "click", testMenuClick);
+ },
+
+ initialize: function()
+ {
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ if (Env.bookmarkletOutdated)
+ Firebug.Console.logFormatted([
+ "A new bookmarklet version is available. " +
+ "Please visit http://getfirebug.com/firebuglite#Install and update it."
+ ], Firebug.context, "warn");
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ if (Firebug.Console)
+ Firebug.Console.flush();
+
+ if (Firebug.Trace)
+ FBTrace.flush(Firebug.Trace);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application");
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // initialize inherited classes
+ Controller.initialize.call(this);
+ PanelBar.initialize.call(this);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // create the interface elements cache
+
+ fbTop = $("fbTop");
+ fbContent = $("fbContent");
+ fbContentStyle = fbContent.style;
+ fbBottom = $("fbBottom");
+ fbBtnInspect = $("fbBtnInspect");
+
+ fbToolbar = $("fbToolbar");
+
+ fbPanelBox1 = $("fbPanelBox1");
+ fbPanelBox1Style = fbPanelBox1.style;
+ fbPanelBox2 = $("fbPanelBox2");
+ fbPanelBox2Style = fbPanelBox2.style;
+ fbPanelBar2Box = $("fbPanelBar2Box");
+ fbPanelBar2BoxStyle = fbPanelBar2Box.style;
+
+ fbHSplitter = $("fbHSplitter");
+ fbVSplitter = $("fbVSplitter");
+ fbVSplitterStyle = fbVSplitter.style;
+
+ fbPanel1 = $("fbPanel1");
+ fbPanel1Style = fbPanel1.style;
+ fbPanel2 = $("fbPanel2");
+ fbPanel2Style = fbPanel2.style;
+
+ fbConsole = $("fbConsole");
+ fbConsoleStyle = fbConsole.style;
+ fbHTML = $("fbHTML");
+
+ fbCommandLine = $("fbCommandLine");
+ fbLargeCommandLine = $("fbLargeCommandLine");
+ fbLargeCommandButtons = $("fbLargeCommandButtons");
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // static values cache
+ topHeight = fbTop.offsetHeight;
+ topPartialHeight = fbToolbar.offsetHeight;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ disableTextSelection($("fbToolbar"));
+ disableTextSelection($("fbPanelBarBox"));
+ disableTextSelection($("fbPanelBar1"));
+ disableTextSelection($("fbPanelBar2"));
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6
+ if (isIE6 && Firebug.Selector)
+ {
+ // TODO: xxxpedro change to getElementsByClass
+ var as = $$(".fbHover");
+ for (var i=0, a; a=as[i]; i++)
+ {
+ a.setAttribute("href", "javascript:void(0)");
+ }
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // initialize all panels
+ /*
+ var panelMap = Firebug.panelTypes;
+ for (var i=0, p; p=panelMap[i]; i++)
+ {
+ if (!p.parentPanel)
+ {
+ this.addPanel(p.prototype.name);
+ }
+ }
+ /**/
+
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+
+ if(Firebug.Inspector)
+ this.inspectButton.initialize();
+
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+
+ this.addController(
+ [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine]
+ );
+
+ // ************************************************************************************************
+
+ // Select the first registered panel
+ // TODO: BUG IE7
+ var self = this;
+ setTimeout(function(){
+ self.selectPanel(Firebug.context.persistedState.selectedPanelName);
+
+ if (Firebug.context.persistedState.selectedPanelName == "Console" && Firebug.CommandLine)
+ Firebug.chrome.focusCommandLine();
+ },0);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //this.draw();
+
+
+
+
+
+
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ var onPanelMouseDown = function onPanelMouseDown(event)
+ {
+ //console.log("onPanelMouseDown", event.target || event.srcElement, event);
+
+ var target = event.target || event.srcElement;
+
+ if (FBL.isLeftClick(event))
+ {
+ var editable = FBL.getAncestorByClass(target, "editable");
+
+ // if an editable element has been clicked then start editing
+ if (editable)
+ {
+ Firebug.Editor.startEditing(editable);
+ FBL.cancelEvent(event);
+ }
+ // if any other element has been clicked then stop editing
+ else
+ {
+ if (!hasClass(target, "textEditorInner"))
+ Firebug.Editor.stopEditing();
+ }
+ }
+ else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target))
+ {
+ // Prevent auto-scroll when middle-clicking a rep object
+ FBL.cancelEvent(event);
+ }
+ };
+
+ Firebug.getElementPanel = function(element)
+ {
+ var panelNode = getAncestorByClass(element, "fbPanel");
+ var id = panelNode.id.substr(2);
+
+ var panel = Firebug.chrome.panelMap[id];
+
+ if (!panel)
+ {
+ if (Firebug.chrome.selectedPanel.sidePanelBar)
+ panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id];
+ }
+
+ return panel;
+ };
+
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ // TODO: xxxpedro port to Firebug
+
+ // Improved window key code event listener. Only one "keydown" event will be attached
+ // to the window, and the onKeyCodeListen() function will delegate which listeners
+ // should be called according to the event.keyCode fired.
+ var onKeyCodeListenersMap = [];
+ var onKeyCodeListen = function(event)
+ {
+ for (var keyCode in onKeyCodeListenersMap)
+ {
+ var listeners = onKeyCodeListenersMap[keyCode];
+
+ for (var i = 0, listener; listener = listeners[i]; i++)
+ {
+ var filter = listener.filter || FBL.noKeyModifiers;
+
+ if (event.keyCode == keyCode && (!filter || filter(event)))
+ {
+ listener.listener();
+ FBL.cancelEvent(event, true);
+ return false;
+ }
+ }
+ }
+ };
+
+ addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen);
+
+ /**
+ * @name keyCodeListen
+ * @memberOf FBL.FirebugChrome
+ */
+ Firebug.chrome.keyCodeListen = function(key, filter, listener, capture)
+ {
+ var keyCode = KeyEvent["DOM_VK_"+key];
+
+ if (!onKeyCodeListenersMap[keyCode])
+ onKeyCodeListenersMap[keyCode] = [];
+
+ onKeyCodeListenersMap[keyCode].push({
+ filter: filter,
+ listener: listener
+ });
+
+ return keyCode;
+ };
+
+ /**
+ * @name keyIgnore
+ * @memberOf FBL.FirebugChrome
+ */
+ Firebug.chrome.keyIgnore = function(keyCode)
+ {
+ onKeyCodeListenersMap[keyCode] = null;
+ delete onKeyCodeListenersMap[keyCode];
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**/
+ // move to shutdown
+ //removeEvent(Firebug.chrome.document, "keydown", listener[0]);
+
+
+ /*
+ Firebug.chrome.keyCodeListen = function(key, filter, listener, capture)
+ {
+ if (!filter)
+ filter = FBL.noKeyModifiers;
+
+ var keyCode = KeyEvent["DOM_VK_"+key];
+
+ var fn = function fn(event)
+ {
+ if (event.keyCode == keyCode && (!filter || filter(event)))
+ {
+ listener();
+ FBL.cancelEvent(event, true);
+ return false;
+ }
+ }
+
+ addEvent(Firebug.chrome.document, "keydown", fn);
+
+ return [fn, capture];
+ };
+
+ Firebug.chrome.keyIgnore = function(listener)
+ {
+ removeEvent(Firebug.chrome.document, "keydown", listener[0]);
+ };
+ /**/
+
+
+ this.addController(
+ [fbPanel1, "mousedown", onPanelMouseDown],
+ [fbPanel2, "mousedown", onPanelMouseDown]
+ );
+/**/
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+
+ // menus can be used without domplate
+ if (FBL.domplate)
+ this.testMenu();
+ /**/
+
+ //test XHR
+ /*
+ setTimeout(function(){
+
+ FBL.Ajax.request({url: "../content/firebug/boot.js"});
+ FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"});
+
+ },1000);
+ /**/
+ },
+
+ shutdown: function()
+ {
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+
+ if(Firebug.Inspector)
+ this.inspectButton.shutdown();
+
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+ // ************************************************************************************************
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ // remove disableTextSelection event handlers
+ restoreTextSelection($("fbToolbar"));
+ restoreTextSelection($("fbPanelBarBox"));
+ restoreTextSelection($("fbPanelBar1"));
+ restoreTextSelection($("fbPanelBar2"));
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // shutdown inherited classes
+ Controller.shutdown.call(this);
+ PanelBar.shutdown.call(this);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Remove the interface elements cache (this must happen after calling
+ // the shutdown method of all dependent components to avoid errors)
+
+ fbTop = null;
+ fbContent = null;
+ fbContentStyle = null;
+ fbBottom = null;
+ fbBtnInspect = null;
+
+ fbToolbar = null;
+
+ fbPanelBox1 = null;
+ fbPanelBox1Style = null;
+ fbPanelBox2 = null;
+ fbPanelBox2Style = null;
+ fbPanelBar2Box = null;
+ fbPanelBar2BoxStyle = null;
+
+ fbHSplitter = null;
+ fbVSplitter = null;
+ fbVSplitterStyle = null;
+
+ fbPanel1 = null;
+ fbPanel1Style = null;
+ fbPanel2 = null;
+
+ fbConsole = null;
+ fbConsoleStyle = null;
+ fbHTML = null;
+
+ fbCommandLine = null;
+ fbLargeCommandLine = null;
+ fbLargeCommandButtons = null;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // static values cache
+
+ topHeight = null;
+ topPartialHeight = null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ toggle: function(forceOpen, popup)
+ {
+ if(popup)
+ {
+ this.detach();
+ }
+ else
+ {
+ if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed)
+ {
+ var frame = FirebugChrome.chromeMap.frame;
+ frame.reattach();
+
+ FirebugChrome.chromeMap.popup = null;
+
+ frame.open();
+
+ return;
+ }
+
+ // If the context is a popup, ignores the toggle process
+ if (Firebug.chrome.type == "popup") return;
+
+ var shouldOpen = forceOpen || !Firebug.context.persistedState.isOpen;
+
+ if(shouldOpen)
+ this.open();
+ else
+ this.close();
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ detach: function()
+ {
+ if(!FirebugChrome.chromeMap.popup)
+ {
+ this.close();
+ createChromeWindow({type: "popup"});
+ }
+ },
+
+ reattach: function(oldChrome, newChrome)
+ {
+ Firebug.browser.window.Firebug = Firebug;
+
+ // chrome synchronization
+ var newPanelMap = newChrome.panelMap;
+ var oldPanelMap = oldChrome.panelMap;
+
+ var panel;
+ for(var name in newPanelMap)
+ {
+ // TODO: xxxpedro innerHTML
+ panel = newPanelMap[name];
+ if (panel.options.innerHTMLSync)
+ panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML;
+ }
+
+ Firebug.chrome = newChrome;
+
+ // TODO: xxxpedro sync detach reattach attach
+ //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]);
+
+ if (newChrome.type == "popup")
+ {
+ newChrome.initialize();
+ //dispatch(Firebug.modules, "initialize", []);
+ }
+ else
+ {
+ // TODO: xxxpedro only needed in persistent
+ // should use FirebugChrome.clone, but popup FBChrome
+ // isn't acessible
+ Firebug.context.persistedState.selectedPanelName = oldChrome.selectedPanel.name;
+ }
+
+ dispatch(newPanelMap, "reattach", [oldChrome, newChrome]);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ draw: function()
+ {
+ var size = this.getSize();
+
+ // Height related values
+ var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0,
+
+ y = Math.max(size.height /* chrome height */, topHeight),
+
+ heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0),
+
+ height = heightValue + "px",
+
+ // Width related values
+ sideWidthValue = Firebug.chrome.sidePanelVisible ? Firebug.context.persistedState.sidePanelWidth : 0,
+
+ width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px";
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Height related rendering
+ fbPanelBox1Style.height = height;
+ fbPanel1Style.height = height;
+
+ if (isIE || isOpera)
+ {
+ // Fix IE and Opera problems with auto resizing the verticall splitter
+ fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px";
+ }
+ //xxxpedro FF2 only?
+ /*
+ else if (isFirefox)
+ {
+ // Fix Firefox problem with table rows with 100% height (fit height)
+ fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px";
+ }/**/
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Width related rendering
+ fbPanelBox1Style.width = width;
+ fbPanel1Style.width = width;
+
+ // SidePanel rendering
+ if (Firebug.chrome.sidePanelVisible)
+ {
+ sideWidthValue = Math.max(sideWidthValue - 6, 0);
+
+ var sideWidth = sideWidthValue + "px";
+
+ fbPanelBox2Style.width = sideWidth;
+
+ fbVSplitterStyle.right = sideWidth;
+
+ if (Firebug.chrome.largeCommandLineVisible)
+ {
+ fbLargeCommandLine = $("fbLargeCommandLine");
+
+ fbLargeCommandLine.style.height = heightValue - 4 + "px";
+ fbLargeCommandLine.style.width = sideWidthValue - 2 + "px";
+
+ fbLargeCommandButtons = $("fbLargeCommandButtons");
+ fbLargeCommandButtons.style.width = sideWidth;
+ }
+ else
+ {
+ fbPanel2Style.height = height;
+ fbPanel2Style.width = sideWidth;
+
+ fbPanelBar2BoxStyle.width = sideWidth;
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getSize: function()
+ {
+ return this.type == "div" ?
+ {
+ height: this.node.offsetHeight,
+ width: this.node.offsetWidth
+ }
+ :
+ this.getWindowSize();
+ },
+
+ resize: function()
+ {
+ var self = this;
+
+ // avoid partial resize when maximizing window
+ setTimeout(function(){
+ self.draw();
+
+ if (noFixedPosition && (self.type == "frame" || self.type == "div"))
+ self.fixIEPosition();
+ }, 0);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ layout: function(panel)
+ {
+ if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", "");
+
+ var options = panel.options;
+
+ changeCommandLineVisibility(options.hasCommandLine);
+ changeSidePanelVisibility(panel.hasSidePanel);
+
+ Firebug.chrome.draw();
+ },
+
+ showLargeCommandLine: function(hideToggleIcon)
+ {
+ var chrome = Firebug.chrome;
+
+ if (!chrome.largeCommandLineVisible)
+ {
+ chrome.largeCommandLineVisible = true;
+
+ if (chrome.selectedPanel.options.hasCommandLine)
+ {
+ if (Firebug.CommandLine)
+ Firebug.CommandLine.blur();
+
+ changeCommandLineVisibility(false);
+ }
+
+ changeSidePanelVisibility(true);
+
+ fbLargeCommandLine.style.display = "block";
+ fbLargeCommandButtons.style.display = "block";
+
+ fbPanel2Style.display = "none";
+ fbPanelBar2BoxStyle.display = "none";
+
+ chrome.draw();
+
+ fbLargeCommandLine.focus();
+
+ if (Firebug.CommandLine)
+ Firebug.CommandLine.setMultiLine(true);
+ }
+ },
+
+ hideLargeCommandLine: function()
+ {
+ if (Firebug.chrome.largeCommandLineVisible)
+ {
+ Firebug.chrome.largeCommandLineVisible = false;
+
+ if (Firebug.CommandLine)
+ Firebug.CommandLine.setMultiLine(false);
+
+ fbLargeCommandLine.blur();
+
+ fbPanel2Style.display = "block";
+ fbPanelBar2BoxStyle.display = "block";
+
+ fbLargeCommandLine.style.display = "none";
+ fbLargeCommandButtons.style.display = "none";
+
+ changeSidePanelVisibility(false);
+
+ if (Firebug.chrome.selectedPanel.options.hasCommandLine)
+ changeCommandLineVisibility(true);
+
+ Firebug.chrome.draw();
+
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ focusCommandLine: function()
+ {
+ var selectedPanelName = this.selectedPanel.name, panelToSelect;
+
+ if (focusCommandLineState == 0 || selectedPanelName != "Console")
+ {
+ focusCommandLineState = 0;
+ lastFocusedPanelName = selectedPanelName;
+
+ panelToSelect = "Console";
+ }
+ if (focusCommandLineState == 1)
+ {
+ panelToSelect = lastFocusedPanelName;
+ }
+
+ this.selectPanel(panelToSelect);
+
+ try
+ {
+ if (Firebug.CommandLine)
+ {
+ if (panelToSelect == "Console")
+ Firebug.CommandLine.focus();
+ else
+ Firebug.CommandLine.blur();
+ }
+ }
+ catch(e)
+ {
+ //TODO: xxxpedro trace error
+ }
+
+ focusCommandLineState = ++focusCommandLineState % 2;
+ }
+
+});
+
+// ************************************************************************************************
+// ChromeFrameBase
+
+/**
+ * @namespace
+ * @extends ns-chrome-ChromeBase
+ */
+var ChromeFrameBase = extend(ChromeBase,
+/**@extend ns-chrome-ChromeFrameBase*/
+{
+ create: function()
+ {
+ ChromeBase.create.call(this);
+
+ // restore display for the anti-flicker trick
+ if (isFirefox)
+ this.node.style.display = "block";
+
+ if (Env.Options.startInNewWindow)
+ {
+ this.close();
+ this.toggle(true, true);
+ return;
+ }
+
+ if (Env.Options.startOpened)
+ this.open();
+ else
+ this.close();
+ },
+
+ destroy: function()
+ {
+ var size = Firebug.chrome.getWindowSize();
+
+ Firebug.context.persistedState.height = size.height;
+
+ if (Firebug.saveCookies)
+ Firebug.savePrefs();
+
+ removeGlobalEvent("keydown", onGlobalKeyDown);
+
+ ChromeBase.destroy.call(this);
+
+ this.document = null;
+ delete this.document;
+
+ this.window = null;
+ delete this.window;
+
+ this.node.parentNode.removeChild(this.node);
+ this.node = null;
+ delete this.node;
+ },
+
+ initialize: function()
+ {
+ //FBTrace.sysout("Frame", "initialize();")
+ ChromeBase.initialize.call(this);
+
+ this.addController(
+ [Firebug.browser.window, "resize", this.resize],
+ [$("fbWindow_btClose"), "click", this.close],
+ [$("fbWindow_btDetach"), "click", this.detach],
+ [$("fbWindow_btDeactivate"), "click", this.deactivate]
+ );
+
+ if (!Env.Options.enablePersistent)
+ this.addController([Firebug.browser.window, "unload", Firebug.shutdown]);
+
+ if (noFixedPosition)
+ {
+ this.addController(
+ [Firebug.browser.window, "scroll", this.fixIEPosition]
+ );
+ }
+
+ fbVSplitter.onmousedown = onVSplitterMouseDown;
+ fbHSplitter.onmousedown = onHSplitterMouseDown;
+
+ this.isInitialized = true;
+ },
+
+ shutdown: function()
+ {
+ fbVSplitter.onmousedown = null;
+ fbHSplitter.onmousedown = null;
+
+ ChromeBase.shutdown.apply(this);
+
+ this.isInitialized = false;
+ },
+
+ reattach: function()
+ {
+ var frame = FirebugChrome.chromeMap.frame;
+
+ ChromeBase.reattach(FirebugChrome.chromeMap.popup, this);
+ },
+
+ open: function()
+ {
+ if (!Firebug.context.persistedState.isOpen)
+ {
+ Firebug.context.persistedState.isOpen = true;
+
+ if (Env.isChromeExtension)
+ localStorage.setItem("Firebug", "1,1");
+
+ var node = this.node;
+
+ node.style.visibility = "hidden"; // Avoid flickering
+
+ if (Firebug.showIconWhenHidden)
+ {
+ if (ChromeMini.isInitialized)
+ {
+ ChromeMini.shutdown();
+ }
+
+ }
+ else
+ node.style.display = "block";
+
+ var main = $("fbChrome");
+
+ // IE6 throws an error when setting this property! why?
+ //main.style.display = "table";
+ main.style.display = "";
+
+ var self = this;
+ /// TODO: xxxpedro FOUC
+ node.style.visibility = "visible";
+ setTimeout(function(){
+ ///node.style.visibility = "visible";
+
+ //dispatch(Firebug.modules, "initialize", []);
+ self.initialize();
+
+ if (noFixedPosition)
+ self.fixIEPosition();
+
+ self.draw();
+
+ }, 10);
+ }
+ },
+
+ close: function()
+ {
+ if (Firebug.context.persistedState.isOpen)
+ {
+ if (this.isInitialized)
+ {
+ //dispatch(Firebug.modules, "shutdown", []);
+ this.shutdown();
+ }
+
+ Firebug.context.persistedState.isOpen = false;
+
+ if (Env.isChromeExtension)
+ localStorage.setItem("Firebug", "1,0");
+
+ var node = this.node;
+
+ if (Firebug.showIconWhenHidden)
+ {
+ node.style.visibility = "hidden"; // Avoid flickering
+
+ // TODO: xxxpedro - persist IE fixed?
+ var main = $("fbChrome", FirebugChrome.chromeMap.frame.document);
+ main.style.display = "none";
+
+ ChromeMini.initialize();
+
+ node.style.visibility = "visible";
+ }
+ else
+ node.style.display = "none";
+ }
+ },
+
+ deactivate: function()
+ {
+ // if it is running as a Chrome extension, dispatch a message to the extension signaling
+ // that Firebug should be deactivated for the current tab
+ if (Env.isChromeExtension)
+ {
+ localStorage.removeItem("Firebug");
+ Firebug.GoogleChrome.dispatch("FB_deactivate");
+
+ // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole
+ // app, otherwise it won't be able to be reactivated without reloading the page.
+ // but we need to stop listening global keys, otherwise the key activation won't work.
+ Firebug.chrome.close();
+ }
+ else
+ {
+ Firebug.shutdown();
+ }
+ },
+
+ fixIEPosition: function()
+ {
+ // fix IE problem with offset when not in fullscreen mode
+ var doc = this.document;
+ var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0;
+
+ var size = Firebug.browser.getWindowSize();
+ var scroll = Firebug.browser.getWindowScrollPosition();
+ var maxHeight = size.height;
+ var height = this.node.offsetHeight;
+
+ var bodyStyle = doc.body.currentStyle;
+
+ this.node.style.top = maxHeight - height + scroll.top + "px";
+
+ if ((this.type == "frame" || this.type == "div") &&
+ (bodyStyle.marginLeft || bodyStyle.marginRight))
+ {
+ this.node.style.width = size.width + "px";
+ }
+
+ if (fbVSplitterStyle)
+ fbVSplitterStyle.right = Firebug.context.persistedState.sidePanelWidth + "px";
+
+ this.draw();
+ }
+
+});
+
+
+// ************************************************************************************************
+// ChromeMini
+
+/**
+ * @namespace
+ * @extends FBL.Controller
+ */
+var ChromeMini = extend(Controller,
+/**@extend ns-chrome-ChromeMini*/
+{
+ create: function(chrome)
+ {
+ append(this, chrome);
+ this.type = "mini";
+ },
+
+ initialize: function()
+ {
+ Controller.initialize.apply(this);
+
+ var doc = FirebugChrome.chromeMap.frame.document;
+
+ var mini = $("fbMiniChrome", doc);
+ mini.style.display = "block";
+
+ var miniIcon = $("fbMiniIcon", doc);
+ var width = miniIcon.offsetWidth + 10;
+ miniIcon.title = "Open " + Firebug.version;
+
+ var errors = $("fbMiniErrors", doc);
+ if (errors.offsetWidth)
+ width += errors.offsetWidth + 10;
+
+ var node = this.node;
+ node.style.height = "27px";
+ node.style.width = width + "px";
+ node.style.left = "";
+ node.style.right = 0;
+
+ if (this.node.nodeName.toLowerCase() == "iframe")
+ {
+ node.setAttribute("allowTransparency", "true");
+ this.document.body.style.backgroundColor = "transparent";
+ }
+ else
+ node.style.background = "transparent";
+
+ if (noFixedPosition)
+ this.fixIEPosition();
+
+ this.addController(
+ [$("fbMiniIcon", doc), "click", onMiniIconClick]
+ );
+
+ if (noFixedPosition)
+ {
+ this.addController(
+ [Firebug.browser.window, "scroll", this.fixIEPosition]
+ );
+ }
+
+ this.isInitialized = true;
+ },
+
+ shutdown: function()
+ {
+ var node = this.node;
+ node.style.height = Firebug.context.persistedState.height + "px";
+ node.style.width = "100%";
+ node.style.left = 0;
+ node.style.right = "";
+
+ if (this.node.nodeName.toLowerCase() == "iframe")
+ {
+ node.setAttribute("allowTransparency", "false");
+ this.document.body.style.backgroundColor = "#fff";
+ }
+ else
+ node.style.background = "#fff";
+
+ if (noFixedPosition)
+ this.fixIEPosition();
+
+ var doc = FirebugChrome.chromeMap.frame.document;
+
+ var mini = $("fbMiniChrome", doc);
+ mini.style.display = "none";
+
+ Controller.shutdown.apply(this);
+
+ this.isInitialized = false;
+ },
+
+ draw: function()
+ {
+
+ },
+
+ fixIEPosition: ChromeFrameBase.fixIEPosition
+
+});
+
+
+// ************************************************************************************************
+// ChromePopupBase
+
+/**
+ * @namespace
+ * @extends ns-chrome-ChromeBase
+ */
+var ChromePopupBase = extend(ChromeBase,
+/**@extend ns-chrome-ChromePopupBase*/
+{
+
+ initialize: function()
+ {
+ setClass(this.document.body, "FirebugPopup");
+
+ ChromeBase.initialize.call(this);
+
+ this.addController(
+ [Firebug.chrome.window, "resize", this.resize],
+ [Firebug.chrome.window, "unload", this.destroy]
+ //[Firebug.chrome.window, "beforeunload", this.destroy]
+ );
+
+ if (Env.Options.enablePersistent)
+ {
+ this.persist = bind(this.persist, this);
+ addEvent(Firebug.browser.window, "unload", this.persist);
+ }
+ else
+ this.addController(
+ [Firebug.browser.window, "unload", this.close]
+ );
+
+ fbVSplitter.onmousedown = onVSplitterMouseDown;
+ },
+
+ destroy: function()
+ {
+ var chromeWin = Firebug.chrome.window;
+ var left = chromeWin.screenX || chromeWin.screenLeft;
+ var top = chromeWin.screenY || chromeWin.screenTop;
+ var size = Firebug.chrome.getWindowSize();
+
+ Firebug.context.persistedState.popupTop = top;
+ Firebug.context.persistedState.popupLeft = left;
+ Firebug.context.persistedState.popupWidth = size.width;
+ Firebug.context.persistedState.popupHeight = size.height;
+
+ if (Firebug.saveCookies)
+ Firebug.savePrefs();
+
+ // TODO: xxxpedro sync detach reattach attach
+ var frame = FirebugChrome.chromeMap.frame;
+
+ if(frame)
+ {
+ dispatch(frame.panelMap, "detach", [this, frame]);
+
+ frame.reattach(this, frame);
+ }
+
+ if (Env.Options.enablePersistent)
+ {
+ removeEvent(Firebug.browser.window, "unload", this.persist);
+ }
+
+ ChromeBase.destroy.apply(this);
+
+ FirebugChrome.chromeMap.popup = null;
+
+ this.node.close();
+ },
+
+ persist: function()
+ {
+ persistTimeStart = new Date().getTime();
+
+ removeEvent(Firebug.browser.window, "unload", this.persist);
+
+ Firebug.Inspector.destroy();
+ Firebug.browser.window.FirebugOldBrowser = true;
+
+ var persistTimeStart = new Date().getTime();
+
+ var waitMainWindow = function()
+ {
+ var doc, head;
+
+ try
+ {
+ if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* &&
+ doc.documentElement && (head = doc.documentElement.firstChild)*/)
+ {
+
+ try
+ {
+ // exposes the FBL to the global namespace when in debug mode
+ if (Env.isDebugMode)
+ {
+ window.FBL = FBL;
+ }
+
+ window.Firebug = Firebug;
+ window.opener.Firebug = Firebug;
+
+ Env.browser = window.opener;
+ Firebug.browser = Firebug.context = new Context(Env.browser);
+ Firebug.loadPrefs();
+
+ registerConsole();
+
+ // the delay time should be calculated right after registering the
+ // console, once right after the console registration, call log messages
+ // will be properly handled
+ var persistDelay = new Date().getTime() - persistTimeStart;
+
+ var chrome = Firebug.chrome;
+ addEvent(Firebug.browser.window, "unload", chrome.persist);
+
+ FBL.cacheDocument();
+ Firebug.Inspector.create();
+
+ Firebug.Console.logFormatted(
+ ["Firebug could not capture console calls during " +
+ persistDelay + "ms"],
+ Firebug.context,
+ "info"
+ );
+
+ setTimeout(function(){
+ var htmlPanel = chrome.getPanel("HTML");
+ htmlPanel.createUI();
+ },50);
+
+ }
+ catch(pE)
+ {
+ alert("persist error: " + (pE.message || pE));
+ }
+
+ }
+ else
+ {
+ window.setTimeout(waitMainWindow, 0);
+ }
+
+ } catch (E) {
+ window.close();
+ }
+ };
+
+ waitMainWindow();
+ },
+
+ close: function()
+ {
+ this.destroy();
+ }
+
+});
+
+
+//************************************************************************************************
+// UI helpers
+
+var changeCommandLineVisibility = function changeCommandLineVisibility(visibility)
+{
+ var last = Firebug.chrome.commandLineVisible;
+ var visible = Firebug.chrome.commandLineVisible =
+ typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible;
+
+ if (visible != last)
+ {
+ if (visible)
+ {
+ fbBottom.className = "";
+
+ if (Firebug.CommandLine)
+ Firebug.CommandLine.activate();
+ }
+ else
+ {
+ if (Firebug.CommandLine)
+ Firebug.CommandLine.deactivate();
+
+ fbBottom.className = "hide";
+ }
+ }
+};
+
+var changeSidePanelVisibility = function changeSidePanelVisibility(visibility)
+{
+ var last = Firebug.chrome.sidePanelVisible;
+ Firebug.chrome.sidePanelVisible =
+ typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible;
+
+ if (Firebug.chrome.sidePanelVisible != last)
+ {
+ fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide";
+ fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide";
+ }
+};
+
+
+// ************************************************************************************************
+// F12 Handler
+
+var onGlobalKeyDown = function onGlobalKeyDown(event)
+{
+ var keyCode = event.keyCode;
+ var shiftKey = event.shiftKey;
+ var ctrlKey = event.ctrlKey;
+
+ if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox))
+ {
+ Firebug.chrome.toggle(false, ctrlKey);
+ cancelEvent(event, true);
+
+ // TODO: xxxpedro replace with a better solution. we're doing this
+ // to allow reactivating with the F12 key after being deactivated
+ if (Env.isChromeExtension)
+ {
+ Firebug.GoogleChrome.dispatch("FB_enableIcon");
+ }
+ }
+ else if (keyCode == 67 /* C */ && ctrlKey && shiftKey)
+ {
+ Firebug.Inspector.toggleInspect();
+ cancelEvent(event, true);
+ }
+ else if (keyCode == 76 /* L */ && ctrlKey && shiftKey)
+ {
+ Firebug.chrome.focusCommandLine();
+ cancelEvent(event, true);
+ }
+};
+
+var onMiniIconClick = function onMiniIconClick(event)
+{
+ Firebug.chrome.toggle(false, event.ctrlKey);
+ cancelEvent(event, true);
+};
+
+
+// ************************************************************************************************
+// Horizontal Splitter Handling
+
+var onHSplitterMouseDown = function onHSplitterMouseDown(event)
+{
+ addGlobalEvent("mousemove", onHSplitterMouseMove);
+ addGlobalEvent("mouseup", onHSplitterMouseUp);
+
+ if (isIE)
+ addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp);
+
+ fbHSplitter.className = "fbOnMovingHSplitter";
+
+ return false;
+};
+
+var onHSplitterMouseMove = function onHSplitterMouseMove(event)
+{
+ cancelEvent(event, true);
+
+ var clientY = event.clientY;
+ var win = isIE
+ ? event.srcElement.ownerDocument.parentWindow
+ : event.target.defaultView || event.target.ownerDocument && event.target.ownerDocument.defaultView;
+
+ if (!win)
+ return;
+
+ if (win != win.parent)
+ {
+ var frameElement = win.frameElement;
+ if (frameElement)
+ {
+ var framePos = Firebug.browser.getElementPosition(frameElement).top;
+ clientY += framePos;
+
+ if (frameElement.style.position != "fixed")
+ clientY -= Firebug.browser.getWindowScrollPosition().top;
+ }
+ }
+
+ if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI")
+ {
+ clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY;
+ }
+
+ /*
+ console.log(
+ typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome",
+ //win.frameElement.id,
+ event.target,
+ clientY
+ );/**/
+
+ onHSplitterMouseMoveBuffer = clientY; // buffer
+
+ if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping
+ {
+ lastHSplitterMouseMove = new Date().getTime();
+ handleHSplitterMouseMove();
+ }
+ else
+ if (!onHSplitterMouseMoveTimer)
+ onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate);
+
+ // improving the resizing performance by canceling the mouse event.
+ // canceling events will prevent the page to receive such events, which would imply
+ // in more processing being expended.
+ cancelEvent(event, true);
+ return false;
+};
+
+var handleHSplitterMouseMove = function()
+{
+ if (onHSplitterMouseMoveTimer)
+ {
+ clearTimeout(onHSplitterMouseMoveTimer);
+ onHSplitterMouseMoveTimer = null;
+ }
+
+ var clientY = onHSplitterMouseMoveBuffer;
+
+ var windowSize = Firebug.browser.getWindowSize();
+ var scrollSize = Firebug.browser.getWindowScrollSize();
+
+ // compute chrome fixed size (top bar and command line)
+ var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0;
+ var fixedHeight = topHeight + commandLineHeight;
+ var chromeNode = Firebug.chrome.node;
+
+ var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0;
+
+ //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height;
+ var height = windowSize.height;
+
+ // compute the min and max size of the chrome
+ var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight);
+ chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize);
+
+ Firebug.context.persistedState.height = chromeHeight;
+ chromeNode.style.height = chromeHeight + "px";
+
+ if (noFixedPosition)
+ Firebug.chrome.fixIEPosition();
+
+ Firebug.chrome.draw();
+};
+
+var onHSplitterMouseUp = function onHSplitterMouseUp(event)
+{
+ removeGlobalEvent("mousemove", onHSplitterMouseMove);
+ removeGlobalEvent("mouseup", onHSplitterMouseUp);
+
+ if (isIE)
+ removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp);
+
+ fbHSplitter.className = "";
+
+ Firebug.chrome.draw();
+
+ // avoid text selection in IE when returning to the document
+ // after the mouse leaves the document during the resizing
+ return false;
+};
+
+
+// ************************************************************************************************
+// Vertical Splitter Handling
+
+var onVSplitterMouseDown = function onVSplitterMouseDown(event)
+{
+ addGlobalEvent("mousemove", onVSplitterMouseMove);
+ addGlobalEvent("mouseup", onVSplitterMouseUp);
+
+ return false;
+};
+
+var onVSplitterMouseMove = function onVSplitterMouseMove(event)
+{
+ if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping
+ {
+ var target = event.target || event.srcElement;
+ if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome
+ {
+ var clientX = event.clientX;
+ var win = document.all
+ ? event.srcElement.ownerDocument.parentWindow
+ : event.target.ownerDocument.defaultView;
+
+ if (win != win.parent)
+ clientX += win.frameElement ? win.frameElement.offsetLeft : 0;
+
+ var size = Firebug.chrome.getSize();
+ var x = Math.max(size.width - clientX + 3, 6);
+
+ Firebug.context.persistedState.sidePanelWidth = x;
+ Firebug.chrome.draw();
+ }
+
+ lastVSplitterMouseMove = new Date().getTime();
+ }
+
+ cancelEvent(event, true);
+ return false;
+};
+
+var onVSplitterMouseUp = function onVSplitterMouseUp(event)
+{
+ removeGlobalEvent("mousemove", onVSplitterMouseMove);
+ removeGlobalEvent("mouseup", onVSplitterMouseUp);
+
+ Firebug.chrome.draw();
+};
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+Firebug.Lite =
+{
+};
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+Firebug.Lite.Cache =
+{
+ ID: "firebug-" + new Date().getTime()
+};
+
+// ************************************************************************************************
+
+/**
+ * TODO: if a cached element is cloned, the expando property will be cloned too in IE
+ * which will result in a bug. Firebug Lite will think the new cloned node is the old
+ * one.
+ *
+ * TODO: Investigate a possibility of cache validation, to be customized by each
+ * kind of cache. For ElementCache it should validate if the element still is
+ * inserted at the DOM.
+ */
+var cacheUID = 0;
+var createCache = function()
+{
+ var map = {};
+ var data = {};
+
+ var CID = Firebug.Lite.Cache.ID;
+
+ // better detection
+ var supportsDeleteExpando = !document.all;
+
+ var cacheFunction = function(element)
+ {
+ return cacheAPI.set(element);
+ };
+
+ var cacheAPI =
+ {
+ get: function(key)
+ {
+ return map.hasOwnProperty(key) ?
+ map[key] :
+ null;
+ },
+
+ set: function(element)
+ {
+ var id = getValidatedKey(element);
+
+ if (!id)
+ {
+ id = ++cacheUID;
+ element[CID] = id;
+ }
+
+ if (!map.hasOwnProperty(id))
+ {
+ map[id] = element;
+ data[id] = {};
+ }
+
+ return id;
+ },
+
+ unset: function(element)
+ {
+ var id = getValidatedKey(element);
+
+ if (!id) return;
+
+ if (supportsDeleteExpando)
+ {
+ delete element[CID];
+ }
+ else if (element.removeAttribute)
+ {
+ element.removeAttribute(CID);
+ }
+
+ delete map[id];
+ delete data[id];
+
+ },
+
+ key: function(element)
+ {
+ return getValidatedKey(element);
+ },
+
+ has: function(element)
+ {
+ var id = getValidatedKey(element);
+ return id && map.hasOwnProperty(id);
+ },
+
+ each: function(callback)
+ {
+ for (var key in map)
+ {
+ if (map.hasOwnProperty(key))
+ {
+ callback(key, map[key]);
+ }
+ }
+ },
+
+ data: function(element, name, value)
+ {
+ // set data
+ if (value)
+ {
+ if (!name) return null;
+
+ var id = cacheAPI.set(element);
+
+ return data[id][name] = value;
+ }
+ // get data
+ else
+ {
+ var id = cacheAPI.key(element);
+
+ return data.hasOwnProperty(id) && data[id].hasOwnProperty(name) ?
+ data[id][name] :
+ null;
+ }
+ },
+
+ clear: function()
+ {
+ for (var id in map)
+ {
+ var element = map[id];
+ cacheAPI.unset(element);
+ }
+ }
+ };
+
+ var getValidatedKey = function(element)
+ {
+ var id = element[CID];
+
+ // If a cached element is cloned in IE, the expando property CID will be also
+ // cloned (differently than other browsers) resulting in a bug: Firebug Lite
+ // will think the new cloned node is the old one. To prevent this problem we're
+ // checking if the cached element matches the given element.
+ if (
+ !supportsDeleteExpando && // the problem happens when supportsDeleteExpando is false
+ id && // the element has the expando property
+ map.hasOwnProperty(id) && // there is a cached element with the same id
+ map[id] != element // but it is a different element than the current one
+ )
+ {
+ // remove the problematic property
+ element.removeAttribute(CID);
+
+ id = null;
+ }
+
+ return id;
+ };
+
+ FBL.append(cacheFunction, cacheAPI);
+
+ return cacheFunction;
+};
+
+// ************************************************************************************************
+
+// TODO: xxxpedro : check if we need really this on FBL scope
+Firebug.Lite.Cache.StyleSheet = createCache();
+Firebug.Lite.Cache.Element = createCache();
+
+// TODO: xxxpedro
+Firebug.Lite.Cache.Event = createCache();
+
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+var sourceMap = {};
+
+// ************************************************************************************************
+Firebug.Lite.Proxy =
+{
+ // jsonp callbacks
+ _callbacks: {},
+
+ /**
+ * Load a resource, either locally (directly) or externally (via proxy) using
+ * synchronous XHR calls. Loading external resources requires the proxy plugin to
+ * be installed and configured (see /plugin/proxy/proxy.php).
+ */
+ load: function(url)
+ {
+ var resourceDomain = getDomain(url);
+ var isLocalResource =
+ // empty domain means local URL
+ !resourceDomain ||
+ // same domain means local too
+ resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context
+
+ return isLocalResource ? fetchResource(url) : fetchProxyResource(url);
+ },
+
+ /**
+ * Load a resource using JSONP technique.
+ */
+ loadJSONP: function(url, callback)
+ {
+ var script = createGlobalElement("script"),
+ doc = Firebug.context.document,
+
+ uid = "" + new Date().getTime(),
+ callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid,
+
+ jsonpURL = url.indexOf("?") != -1 ?
+ url + "&" + callbackName :
+ url + "?" + callbackName;
+
+ Firebug.Lite.Proxy._callbacks[uid] = function(data)
+ {
+ if (callback)
+ callback(data);
+
+ script.parentNode.removeChild(script);
+ delete Firebug.Lite.Proxy._callbacks[uid];
+ };
+
+ script.src = jsonpURL;
+
+ if (doc.documentElement)
+ doc.documentElement.appendChild(script);
+ },
+
+ /**
+ * Load a resource using YQL (not reliable).
+ */
+ YQL: function(url, callback)
+ {
+ var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" +
+ encodeURIComponent(url) + "%22&format=xml";
+
+ this.loadJSONP(yql, function(data)
+ {
+ var source = data.results[0];
+
+ // clean up YQL bogus elements
+ var match = /<body>\s+<p>([\s\S]+)<\/p>\s+<\/body>$/.exec(source);
+ if (match)
+ source = match[1];
+
+ console.log(source);
+ });
+ }
+};
+
+// ************************************************************************************************
+
+Firebug.Lite.Proxy.fetchResourceDisabledMessage =
+ "/* Firebug Lite resource fetching is disabled.\n" +
+ "To enabled it set the Firebug Lite option \"disableResourceFetching\" to \"false\".\n" +
+ "More info at http://getfirebug.com/firebuglite#Options */";
+
+var fetchResource = function(url)
+{
+ if (Firebug.disableResourceFetching)
+ {
+ var source = sourceMap[url] = Firebug.Lite.Proxy.fetchResourceDisabledMessage;
+ return source;
+ }
+
+ if (sourceMap.hasOwnProperty(url))
+ return sourceMap[url];
+
+ // Getting the native XHR object so our calls won't be logged in the Console Panel
+ var xhr = FBL.getNativeXHRObject();
+ xhr.open("get", url, false);
+ xhr.send();
+
+ var source = sourceMap[url] = xhr.responseText;
+ return source;
+};
+
+var fetchProxyResource = function(url)
+{
+ if (sourceMap.hasOwnProperty(url))
+ return sourceMap[url];
+
+ var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url);
+ var response = fetchResource(proxyURL);
+
+ try
+ {
+ var data = eval("(" + response + ")");
+ }
+ catch(E)
+ {
+ return "ERROR: Firebug Lite Proxy plugin returned an invalid response.";
+ }
+
+ var source = data ? data.contents : "";
+ return source;
+};
+
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+Firebug.Lite.Style =
+{
+};
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+Firebug.Lite.Script = function(window)
+{
+ this.fileName = null;
+ this.isValid = null;
+ this.baseLineNumber = null;
+ this.lineExtent = null;
+ this.tag = null;
+
+ this.functionName = null;
+ this.functionSource = null;
+};
+
+Firebug.Lite.Script.prototype =
+{
+ isLineExecutable: function(){},
+ pcToLine: function(){},
+ lineToPc: function(){},
+
+ toString: function()
+ {
+ return "Firebug.Lite.Script";
+ }
+};
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+
+Firebug.Lite.Browser = function(window)
+{
+ this.contentWindow = window;
+ this.contentDocument = window.document;
+ this.currentURI =
+ {
+ spec: window.location.href
+ };
+};
+
+Firebug.Lite.Browser.prototype =
+{
+ toString: function()
+ {
+ return "Firebug.Lite.Browser";
+ }
+};
+
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+/*
+ http://www.JSON.org/json2.js
+ 2010-03-20
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+/*jslint evil: true, strict: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+// ************************************************************************************************
+
+var JSON = window.JSON || {};
+
+// ************************************************************************************************
+
+(function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+
+// ************************************************************************************************
+// registration
+
+FBL.JSON = JSON;
+
+// ************************************************************************************************
+}());
+
+/* See license.txt for terms of usage */
+
+(function(){
+// ************************************************************************************************
+
+/* Copyright (c) 2010-2011 Marcus Westin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+var store = (function(){
+ var api = {},
+ win = window,
+ doc = win.document,
+ localStorageName = 'localStorage',
+ globalStorageName = 'globalStorage',
+ namespace = '__firebug__storejs__',
+ storage
+
+ api.disabled = false
+ api.set = function(key, value) {}
+ api.get = function(key) {}
+ api.remove = function(key) {}
+ api.clear = function() {}
+ api.transact = function(key, transactionFn) {
+ var val = api.get(key)
+ if (typeof val == 'undefined') { val = {} }
+ transactionFn(val)
+ api.set(key, val)
+ }
+
+ api.serialize = function(value) {
+ return JSON.stringify(value)
+ }
+ api.deserialize = function(value) {
+ if (typeof value != 'string') { return undefined }
+ return JSON.parse(value)
+ }
+
+ // Functions to encapsulate questionable FireFox 3.6.13 behavior
+ // when about.config::dom.storage.enabled === false
+ // See https://github.com/marcuswestin/store.js/issues#issue/13
+ function isLocalStorageNameSupported() {
+ try { return (localStorageName in win && win[localStorageName]) }
+ catch(err) { return false }
+ }
+
+ function isGlobalStorageNameSupported() {
+ try { return (globalStorageName in win && win[globalStorageName] && win[globalStorageName][win.location.hostname]) }
+ catch(err) { return false }
+ }
+
+ if (isLocalStorageNameSupported()) {
+ storage = win[localStorageName]
+ api.set = function(key, val) { storage.setItem(key, api.serialize(val)) }
+ api.get = function(key) { return api.deserialize(storage.getItem(key)) }
+ api.remove = function(key) { storage.removeItem(key) }
+ api.clear = function() { storage.clear() }
+
+ } else if (isGlobalStorageNameSupported()) {
+ storage = win[globalStorageName][win.location.hostname]
+ api.set = function(key, val) { storage[key] = api.serialize(val) }
+ api.get = function(key) { return api.deserialize(storage[key] && storage[key].value) }
+ api.remove = function(key) { delete storage[key] }
+ api.clear = function() { for (var key in storage ) { delete storage[key] } }
+
+ } else if (doc.documentElement.addBehavior) {
+ var storage = doc.createElement('div')
+ function withIEStorage(storeFunction) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments, 0)
+ args.unshift(storage)
+ // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
+ // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
+ // TODO: xxxpedro doc.body is not always available so we must use doc.documentElement.
+ // We need to make sure this change won't affect the behavior of this library.
+ doc.documentElement.appendChild(storage)
+ storage.addBehavior('#default#userData')
+ storage.load(localStorageName)
+ var result = storeFunction.apply(api, args)
+ doc.documentElement.removeChild(storage)
+ return result
+ }
+ }
+ api.set = withIEStorage(function(storage, key, val) {
+ storage.setAttribute(key, api.serialize(val))
+ storage.save(localStorageName)
+ })
+ api.get = withIEStorage(function(storage, key) {
+ return api.deserialize(storage.getAttribute(key))
+ })
+ api.remove = withIEStorage(function(storage, key) {
+ storage.removeAttribute(key)
+ storage.save(localStorageName)
+ })
+ api.clear = withIEStorage(function(storage) {
+ var attributes = storage.XMLDocument.documentElement.attributes
+ storage.load(localStorageName)
+ for (var i=0, attr; attr = attributes[i]; i++) {
+ storage.removeAttribute(attr.name)
+ }
+ storage.save(localStorageName)
+ })
+ }
+
+ try {
+ api.set(namespace, namespace)
+ if (api.get(namespace) != namespace) { api.disabled = true }
+ api.remove(namespace)
+ } catch(e) {
+ api.disabled = true
+ }
+
+ return api
+})();
+
+if (typeof module != 'undefined') { module.exports = store }
+
+
+// ************************************************************************************************
+// registration
+
+FBL.Store = store;
+
+// ************************************************************************************************
+})();
+
+/* See license.txt for terms of usage */
+
+FBL.ns( /**@scope s_selector*/ function() { with (FBL) {
+// ************************************************************************************************
+
+/*
+ * Sizzle CSS Selector Engine - v1.0
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function(){
+ baseHasDuplicate = false;
+ return 0;
+});
+
+/**
+ * @name Firebug.Selector
+ * @namespace
+ */
+
+/**
+ * @exports Sizzle as Firebug.Selector
+ */
+var Sizzle = function(selector, context, results, seed) {
+ results = results || [];
+ var origContext = context = context || document;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] )
+ selector += parts.shift();
+
+ set = posProcess( selector, set );
+ }
+ }
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+ var ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
+ }
+
+ if ( context ) {
+ var ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+ set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray(set);
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ var cur = parts.pop(), pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ throw "Syntax error, unrecognized expression: " + (cur || selector);
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+ } else if ( context && context.nodeType === 1 ) {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+ } else {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function(results){
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort(sortOrder);
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[i-1] ) {
+ results.splice(i--, 1);
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function(expr, set){
+ return Sizzle(expr, null, null, set);
+};
+
+Sizzle.find = function(expr, context, isXML){
+ var set, match;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var type = Expr.order[i], match;
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ var left = match[1];
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace(/\\/g, "");
+ set = Expr.find[ type ]( match, context, isXML );
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = context.getElementsByTagName("*");
+ }
+
+ return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+ var old = expr, result = [], curLoop = set, match, anyFound,
+ isXMLFilter = set && set[0] && isXML(set[0]);
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+ var filter = Expr.filter[ type ], found, item;
+ anyFound = false;
+
+ if ( curLoop == result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+ } else {
+ curLoop[i] = false;
+ }
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr == old ) {
+ if ( anyFound == null ) {
+ throw "Syntax error, unrecognized expression: " + expr;
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+/**#@+ @ignore */
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+ },
+ leftMatch: {},
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+ attrHandle: {
+ href: function(elem){
+ return elem.getAttribute("href");
+ }
+ },
+ relative: {
+ "+": function(checkSet, part, isXML){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !/\W/.test(part),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag && !isXML ) {
+ part = part.toUpperCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+ ">": function(checkSet, part, isXML){
+ var isPartStr = typeof part === "string";
+
+ if ( isPartStr && !/\W/.test(part) ) {
+ part = isXML ? part : part.toUpperCase();
+
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName === part ? parent : false;
+ }
+ }
+ } else {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+ "": function(checkSet, part, isXML){
+ var doneName = done++, checkFn = dirCheck;
+
+ if ( !/\W/.test(part) ) {
+ var nodeCheck = part = isXML ? part : part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+ },
+ "~": function(checkSet, part, isXML){
+ var doneName = done++, checkFn = dirCheck;
+
+ if ( typeof part === "string" && !/\W/.test(part) ) {
+ var nodeCheck = part = isXML ? part : part.toUpperCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+ }
+ },
+ find: {
+ ID: function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? [m] : [];
+ }
+ },
+ NAME: function(match, context, isXML){
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [], results = context.getElementsByName(match[1]);
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+ TAG: function(match, context){
+ return context.getElementsByTagName(match[1]);
+ }
+ },
+ preFilter: {
+ CLASS: function(match, curLoop, inplace, result, not, isXML){
+ match = " " + match[1].replace(/\\/g, "") + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
+ if ( !inplace )
+ result.push( elem );
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+ ID: function(match){
+ return match[1].replace(/\\/g, "");
+ },
+ TAG: function(match, curLoop){
+ for ( var i = 0; curLoop[i] === false; i++ ){}
+ return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
+ },
+ CHILD: function(match){
+ if ( match[1] == "nth" ) {
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+ ATTR: function(match, curLoop, inplace, result, not, isXML){
+ var name = match[1].replace(/\\/g, "");
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+ PSEUDO: function(match, curLoop, inplace, result, not){
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+ return false;
+ }
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+ POS: function(match){
+ match.unshift( true );
+ return match;
+ }
+ },
+ filters: {
+ enabled: function(elem){
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+ disabled: function(elem){
+ return elem.disabled === true;
+ },
+ checked: function(elem){
+ return elem.checked === true;
+ },
+ selected: function(elem){
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ elem.parentNode.selectedIndex;
+ return elem.selected === true;
+ },
+ parent: function(elem){
+ return !!elem.firstChild;
+ },
+ empty: function(elem){
+ return !elem.firstChild;
+ },
+ has: function(elem, i, match){
+ return !!Sizzle( match[3], elem ).length;
+ },
+ header: function(elem){
+ return /h\d/i.test( elem.nodeName );
+ },
+ text: function(elem){
+ return "text" === elem.type;
+ },
+ radio: function(elem){
+ return "radio" === elem.type;
+ },
+ checkbox: function(elem){
+ return "checkbox" === elem.type;
+ },
+ file: function(elem){
+ return "file" === elem.type;
+ },
+ password: function(elem){
+ return "password" === elem.type;
+ },
+ submit: function(elem){
+ return "submit" === elem.type;
+ },
+ image: function(elem){
+ return "image" === elem.type;
+ },
+ reset: function(elem){
+ return "reset" === elem.type;
+ },
+ button: function(elem){
+ return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
+ },
+ input: function(elem){
+ return /input|select|textarea|button/i.test(elem.nodeName);
+ }
+ },
+ setFilters: {
+ first: function(elem, i){
+ return i === 0;
+ },
+ last: function(elem, i, match, array){
+ return i === array.length - 1;
+ },
+ even: function(elem, i){
+ return i % 2 === 0;
+ },
+ odd: function(elem, i){
+ return i % 2 === 1;
+ },
+ lt: function(elem, i, match){
+ return i < match[3] - 0;
+ },
+ gt: function(elem, i, match){
+ return i > match[3] - 0;
+ },
+ nth: function(elem, i, match){
+ return match[3] - 0 == i;
+ },
+ eq: function(elem, i, match){
+ return match[3] - 0 == i;
+ }
+ },
+ filter: {
+ PSEUDO: function(elem, match, i, array){
+ var name = match[1], filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var i = 0, l = not.length; i < l; i++ ) {
+ if ( not[i] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ },
+ CHILD: function(elem, match){
+ var type = match[1], node = elem;
+ switch (type) {
+ case 'only':
+ case 'first':
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) return false;
+ }
+ if ( type == 'first') return true;
+ node = elem;
+ case 'last':
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) return false;
+ }
+ return true;
+ case 'nth':
+ var first = match[2], last = match[3];
+
+ if ( first == 1 && last == 0 ) {
+ return true;
+ }
+
+ var doneName = match[0],
+ parent = elem.parentNode;
+
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+ var count = 0;
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+ parent.sizcache = doneName;
+ }
+
+ var diff = elem.nodeIndex - last;
+ if ( first == 0 ) {
+ return diff == 0;
+ } else {
+ return ( diff % first == 0 && diff / first >= 0 );
+ }
+ }
+ },
+ ID: function(elem, match){
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+ TAG: function(elem, match){
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
+ },
+ CLASS: function(elem, match){
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+ ATTR: function(elem, match){
+ var name = match[1],
+ result = Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value != check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+ POS: function(elem, match, i, array){
+ var name = match[2], filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS;
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
+}
+
+var makeArray = function(array, results) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 );
+
+// Provide a fallback method if it does not work
+} catch(e){
+ makeArray = function(array, results) {
+ var ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var i = 0, l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+ } else {
+ for ( var i = 0; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( "sourceIndex" in document.documentElement ) {
+ sortOrder = function( a, b ) {
+ if ( !a.sourceIndex || !b.sourceIndex ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var ret = a.sourceIndex - b.sourceIndex;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( document.createRange ) {
+ sortOrder = function( a, b ) {
+ if ( !a.ownerDocument || !b.ownerDocument ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ }
+
+ var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+ aRange.setStart(a, 0);
+ aRange.setEnd(a, 0);
+ bRange.setStart(b, 0);
+ bRange.setEnd(b, 0);
+ var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date).getTime();
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ var root = document.documentElement;
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( !!document.getElementById( id ) ) {
+ Expr.find.ID = function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+ }
+ };
+
+ Expr.filter.ID = function(elem, match){
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+ root = form = null; // release memory in IE
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function(match, context){
+ var results = context.getElementsByTagName(match[1]);
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+ Expr.attrHandle.href = function(elem){
+ return elem.getAttribute("href", 2);
+ };
+ }
+
+ div = null; // release memory in IE
+})();
+
+if ( document.querySelectorAll ) (function(){
+ var oldSizzle = Sizzle, div = document.createElement("div");
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function(query, context, extra, seed){
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(e){}
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ div = null; // release memory in IE
+})();
+
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
+ var div = document.createElement("div");
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ if ( div.getElementsByClassName("e").length === 0 )
+ return;
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 )
+ return;
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function(match, context, isXML) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ div = null; // release memory in IE
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ var sibDir = dir == "previousSibling" && !isXML;
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ if ( sibDir && elem.nodeType === 1 ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ var sibDir = dir == "previousSibling" && !isXML;
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ if ( sibDir && elem.nodeType === 1 ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+var contains = document.compareDocumentPosition ? function(a, b){
+ return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+ return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+ !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
+};
+
+var posProcess = function(selector, context){
+ var tmpSet = [], later = "", match,
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+
+Firebug.Selector = Sizzle;
+
+/**#@-*/
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Inspector Module
+
+var ElementCache = Firebug.Lite.Cache.Element;
+
+var inspectorTS, inspectorTimer, isInspecting;
+
+Firebug.Inspector =
+{
+ create: function()
+ {
+ offlineFragment = Env.browser.document.createDocumentFragment();
+
+ createBoxModelInspector();
+ createOutlineInspector();
+ },
+
+ destroy: function()
+ {
+ destroyBoxModelInspector();
+ destroyOutlineInspector();
+
+ offlineFragment = null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Inspect functions
+
+ toggleInspect: function()
+ {
+ if (isInspecting)
+ {
+ this.stopInspecting();
+ }
+ else
+ {
+ Firebug.chrome.inspectButton.changeState("pressed");
+ this.startInspecting();
+ }
+ },
+
+ startInspecting: function()
+ {
+ isInspecting = true;
+
+ Firebug.chrome.selectPanel("HTML");
+
+ createInspectorFrame();
+
+ var size = Firebug.browser.getWindowScrollSize();
+
+ fbInspectFrame.style.width = size.width + "px";
+ fbInspectFrame.style.height = size.height + "px";
+
+ //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody);
+
+ addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting);
+ addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick);
+ },
+
+ stopInspecting: function()
+ {
+ isInspecting = false;
+
+ if (outlineVisible) this.hideOutline();
+ removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting);
+ removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick);
+
+ destroyInspectorFrame();
+
+ Firebug.chrome.inspectButton.restore();
+
+ if (Firebug.chrome.type == "popup")
+ Firebug.chrome.node.focus();
+ },
+
+ onInspectingClick: function(e)
+ {
+ fbInspectFrame.style.display = "none";
+ var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY);
+ fbInspectFrame.style.display = "block";
+
+ // Avoid inspecting the outline, and the FirebugUI
+ var id = targ.id;
+ if (id && /^fbOutline\w$/.test(id)) return;
+ if (id == "FirebugUI") return;
+
+ // Avoid looking at text nodes in Opera
+ while (targ.nodeType != 1) targ = targ.parentNode;
+
+ //Firebug.Console.log(targ);
+ Firebug.Inspector.stopInspecting();
+ },
+
+ onInspecting: function(e)
+ {
+ if (new Date().getTime() - lastInspecting > 30)
+ {
+ fbInspectFrame.style.display = "none";
+ var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY);
+ fbInspectFrame.style.display = "block";
+
+ // Avoid inspecting the outline, and the FirebugUI
+ var id = targ.id;
+ if (id && /^fbOutline\w$/.test(id)) return;
+ if (id == "FirebugUI") return;
+
+ // Avoid looking at text nodes in Opera
+ while (targ.nodeType != 1) targ = targ.parentNode;
+
+ if (targ.nodeName.toLowerCase() == "body") return;
+
+ //Firebug.Console.log(e.clientX, e.clientY, targ);
+ Firebug.Inspector.drawOutline(targ);
+
+ if (ElementCache(targ))
+ {
+ var target = ""+ElementCache.key(targ);
+ var lazySelect = function()
+ {
+ inspectorTS = new Date().getTime();
+
+ if (Firebug.HTML)
+ Firebug.HTML.selectTreeNode(""+ElementCache.key(targ));
+ };
+
+ if (inspectorTimer)
+ {
+ clearTimeout(inspectorTimer);
+ inspectorTimer = null;
+ }
+
+ if (new Date().getTime() - inspectorTS > 200)
+ setTimeout(lazySelect, 0);
+ else
+ inspectorTimer = setTimeout(lazySelect, 300);
+ }
+
+ lastInspecting = new Date().getTime();
+ }
+ },
+
+ // TODO: xxxpedro remove this?
+ onInspectingBody: function(e)
+ {
+ if (new Date().getTime() - lastInspecting > 30)
+ {
+ var targ = e.target;
+
+ // Avoid inspecting the outline, and the FirebugUI
+ var id = targ.id;
+ if (id && /^fbOutline\w$/.test(id)) return;
+ if (id == "FirebugUI") return;
+
+ // Avoid looking at text nodes in Opera
+ while (targ.nodeType != 1) targ = targ.parentNode;
+
+ if (targ.nodeName.toLowerCase() == "body") return;
+
+ //Firebug.Console.log(e.clientX, e.clientY, targ);
+ Firebug.Inspector.drawOutline(targ);
+
+ if (ElementCache.has(targ))
+ FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ));
+
+ lastInspecting = new Date().getTime();
+ }
+ },
+
+ /**
+ *
+ * llttttttrr
+ * llttttttrr
+ * ll rr
+ * ll rr
+ * llbbbbbbrr
+ * llbbbbbbrr
+ */
+ drawOutline: function(el)
+ {
+ var border = 2;
+ var scrollbarSize = 17;
+
+ var windowSize = Firebug.browser.getWindowSize();
+ var scrollSize = Firebug.browser.getWindowScrollSize();
+ var scrollPosition = Firebug.browser.getWindowScrollPosition();
+
+ var box = Firebug.browser.getElementBox(el);
+
+ var top = box.top;
+ var left = box.left;
+ var height = box.height;
+ var width = box.width;
+
+ var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width -
+ (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible
+ scrollbarSize : 0);
+
+ var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height -
+ (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible
+ scrollbarSize : 0);
+
+ var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1;
+
+ var o = outlineElements;
+ var style;
+
+ style = o.fbOutlineT.style;
+ style.top = top-border + "px";
+ style.left = left + "px";
+ style.height = border + "px"; // TODO: on initialize()
+ style.width = width + "px";
+
+ style = o.fbOutlineL.style;
+ style.top = top-border + "px";
+ style.left = left-border + "px";
+ style.height = height+ numVerticalBorders*border + "px";
+ style.width = border + "px"; // TODO: on initialize()
+
+ style = o.fbOutlineB.style;
+ if (freeVerticalSpace > 0)
+ {
+ style.top = top+height + "px";
+ style.left = left + "px";
+ style.width = width + "px";
+ //style.height = border + "px"; // TODO: on initialize() or worst case?
+ }
+ else
+ {
+ style.top = -2*border + "px";
+ style.left = -2*border + "px";
+ style.width = border + "px";
+ //style.height = border + "px";
+ }
+
+ style = o.fbOutlineR.style;
+ if (freeHorizontalSpace > 0)
+ {
+ style.top = top-border + "px";
+ style.left = left+width + "px";
+ style.height = height + numVerticalBorders*border + "px";
+ style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px";
+ }
+ else
+ {
+ style.top = -2*border + "px";
+ style.left = -2*border + "px";
+ style.height = border + "px";
+ style.width = border + "px";
+ }
+
+ if (!outlineVisible) this.showOutline();
+ },
+
+ hideOutline: function()
+ {
+ if (!outlineVisible) return;
+
+ for (var name in outline)
+ offlineFragment.appendChild(outlineElements[name]);
+
+ outlineVisible = false;
+ },
+
+ showOutline: function()
+ {
+ if (outlineVisible) return;
+
+ if (boxModelVisible) this.hideBoxModel();
+
+ for (var name in outline)
+ Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]);
+
+ outlineVisible = true;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Box Model
+
+ drawBoxModel: function(el)
+ {
+ // avoid error when the element is not attached a document
+ if (!el || !el.parentNode)
+ return;
+
+ var box = Firebug.browser.getElementBox(el);
+
+ var windowSize = Firebug.browser.getWindowSize();
+ var scrollPosition = Firebug.browser.getWindowScrollPosition();
+
+ // element may be occluded by the chrome, when in frame mode
+ var offsetHeight = Firebug.chrome.type == "frame" ? Firebug.context.persistedState.height : 0;
+
+ // if element box is not inside the viewport, don't draw the box model
+ if (box.top > scrollPosition.top + windowSize.height - offsetHeight ||
+ box.left > scrollPosition.left + windowSize.width ||
+ scrollPosition.top > box.top + box.height ||
+ scrollPosition.left > box.left + box.width )
+ return;
+
+ var top = box.top;
+ var left = box.left;
+ var height = box.height;
+ var width = box.width;
+
+ var margin = Firebug.browser.getMeasurementBox(el, "margin");
+ var padding = Firebug.browser.getMeasurementBox(el, "padding");
+ var border = Firebug.browser.getMeasurementBox(el, "border");
+
+ boxModelStyle.top = top - margin.top + "px";
+ boxModelStyle.left = left - margin.left + "px";
+ boxModelStyle.height = height + margin.top + margin.bottom + "px";
+ boxModelStyle.width = width + margin.left + margin.right + "px";
+
+ boxBorderStyle.top = margin.top + "px";
+ boxBorderStyle.left = margin.left + "px";
+ boxBorderStyle.height = height + "px";
+ boxBorderStyle.width = width + "px";
+
+ boxPaddingStyle.top = margin.top + border.top + "px";
+ boxPaddingStyle.left = margin.left + border.left + "px";
+ boxPaddingStyle.height = height - border.top - border.bottom + "px";
+ boxPaddingStyle.width = width - border.left - border.right + "px";
+
+ boxContentStyle.top = margin.top + border.top + padding.top + "px";
+ boxContentStyle.left = margin.left + border.left + padding.left + "px";
+ boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px";
+ boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px";
+
+ if (!boxModelVisible) this.showBoxModel();
+ },
+
+ hideBoxModel: function()
+ {
+ if (!boxModelVisible) return;
+
+ offlineFragment.appendChild(boxModel);
+ boxModelVisible = false;
+ },
+
+ showBoxModel: function()
+ {
+ if (boxModelVisible) return;
+
+ if (outlineVisible) this.hideOutline();
+
+ Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel);
+ boxModelVisible = true;
+ }
+
+};
+
+// ************************************************************************************************
+// Inspector Internals
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Shared variables
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Internal variables
+
+var offlineFragment = null;
+
+var boxModelVisible = false;
+
+var boxModel, boxModelStyle,
+ boxMargin, boxMarginStyle,
+ boxBorder, boxBorderStyle,
+ boxPadding, boxPaddingStyle,
+ boxContent, boxContentStyle;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
+var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";
+
+var inspectStyle = resetStyle + "z-index: 2147483500;";
+var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" +
+ Env.Location.skinDir + "pixel_transparent.gif);";
+
+//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);";
+
+var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;";
+var inspectModelStyle = inspectStyle + inspectModelOpacity;
+var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;";
+var inspectBorderStyle = inspectStyle + "background: #666;";
+var inspectPaddingStyle = inspectStyle + "background: SlateBlue;";
+var inspectContentStyle = inspectStyle + "background: SkyBlue;";
+
+
+var outlineStyle = {
+ fbHorizontalLine: "background: #3875D7;height: 2px;",
+ fbVerticalLine: "background: #3875D7;width: 2px;"
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var lastInspecting = 0;
+var fbInspectFrame = null;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var outlineVisible = false;
+var outlineElements = {};
+var outline = {
+ "fbOutlineT": "fbHorizontalLine",
+ "fbOutlineL": "fbVerticalLine",
+ "fbOutlineB": "fbHorizontalLine",
+ "fbOutlineR": "fbVerticalLine"
+};
+
+
+var getInspectingTarget = function()
+{
+
+};
+
+// ************************************************************************************************
+// Section
+
+var createInspectorFrame = function createInspectorFrame()
+{
+ fbInspectFrame = createGlobalElement("div");
+ fbInspectFrame.id = "fbInspectFrame";
+ fbInspectFrame.firebugIgnore = true;
+ fbInspectFrame.style.cssText = inspectFrameStyle;
+ Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame);
+};
+
+var destroyInspectorFrame = function destroyInspectorFrame()
+{
+ if (fbInspectFrame)
+ {
+ Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame);
+ fbInspectFrame = null;
+ }
+};
+
+var createOutlineInspector = function createOutlineInspector()
+{
+ for (var name in outline)
+ {
+ var el = outlineElements[name] = createGlobalElement("div");
+ el.id = name;
+ el.firebugIgnore = true;
+ el.style.cssText = inspectStyle + outlineStyle[outline[name]];
+ offlineFragment.appendChild(el);
+ }
+};
+
+var destroyOutlineInspector = function destroyOutlineInspector()
+{
+ for (var name in outline)
+ {
+ var el = outlineElements[name];
+ el.parentNode.removeChild(el);
+ }
+};
+
+var createBoxModelInspector = function createBoxModelInspector()
+{
+ boxModel = createGlobalElement("div");
+ boxModel.id = "fbBoxModel";
+ boxModel.firebugIgnore = true;
+ boxModelStyle = boxModel.style;
+ boxModelStyle.cssText = inspectModelStyle;
+
+ boxMargin = createGlobalElement("div");
+ boxMargin.id = "fbBoxMargin";
+ boxMarginStyle = boxMargin.style;
+ boxMarginStyle.cssText = inspectMarginStyle;
+ boxModel.appendChild(boxMargin);
+
+ boxBorder = createGlobalElement("div");
+ boxBorder.id = "fbBoxBorder";
+ boxBorderStyle = boxBorder.style;
+ boxBorderStyle.cssText = inspectBorderStyle;
+ boxModel.appendChild(boxBorder);
+
+ boxPadding = createGlobalElement("div");
+ boxPadding.id = "fbBoxPadding";
+ boxPaddingStyle = boxPadding.style;
+ boxPaddingStyle.cssText = inspectPaddingStyle;
+ boxModel.appendChild(boxPadding);
+
+ boxContent = createGlobalElement("div");
+ boxContent.id = "fbBoxContent";
+ boxContentStyle = boxContent.style;
+ boxContentStyle.cssText = inspectContentStyle;
+ boxModel.appendChild(boxContent);
+
+ offlineFragment.appendChild(boxModel);
+};
+
+var destroyBoxModelInspector = function destroyBoxModelInspector()
+{
+ boxModel.parentNode.removeChild(boxModel);
+};
+
+// ************************************************************************************************
+// Section
+
+
+
+
+// ************************************************************************************************
+}});
+
+// Problems in IE
+// FIXED - eval return
+// FIXED - addEventListener problem in IE
+// FIXED doc.createRange?
+//
+// class reserved word
+// test all honza examples in IE6 and IE7
+
+
+/* See license.txt for terms of usage */
+
+( /** @scope s_domplate */ function() {
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/** @class */
+FBL.DomplateTag = function DomplateTag(tagName)
+{
+ this.tagName = tagName;
+};
+
+/**
+ * @class
+ * @extends FBL.DomplateTag
+ */
+FBL.DomplateEmbed = function DomplateEmbed()
+{
+};
+
+/**
+ * @class
+ * @extends FBL.DomplateTag
+ */
+FBL.DomplateLoop = function DomplateLoop()
+{
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var DomplateTag = FBL.DomplateTag;
+var DomplateEmbed = FBL.DomplateEmbed;
+var DomplateLoop = FBL.DomplateLoop;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var womb = null;
+
+FBL.domplate = function()
+{
+ var lastSubject;
+ for (var i = 0; i < arguments.length; ++i)
+ lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i];
+
+ for (var name in lastSubject)
+ {
+ var val = lastSubject[name];
+ if (isTag(val))
+ val.tag.subject = lastSubject;
+ }
+
+ return lastSubject;
+};
+
+var domplate = FBL.domplate;
+
+FBL.domplate.context = function(context, fn)
+{
+ var lastContext = domplate.lastContext;
+ domplate.topContext = context;
+ fn.apply(context);
+ domplate.topContext = lastContext;
+};
+
+FBL.TAG = function()
+{
+ var embed = new DomplateEmbed();
+ return embed.merge(arguments);
+};
+
+FBL.FOR = function()
+{
+ var loop = new DomplateLoop();
+ return loop.merge(arguments);
+};
+
+FBL.DomplateTag.prototype =
+{
+ merge: function(args, oldTag)
+ {
+ if (oldTag)
+ this.tagName = oldTag.tagName;
+
+ this.context = oldTag ? oldTag.context : null;
+ this.subject = oldTag ? oldTag.subject : null;
+ this.attrs = oldTag ? copyObject(oldTag.attrs) : {};
+ this.classes = oldTag ? copyObject(oldTag.classes) : {};
+ this.props = oldTag ? copyObject(oldTag.props) : null;
+ this.listeners = oldTag ? copyArray(oldTag.listeners) : null;
+ this.children = oldTag ? copyArray(oldTag.children) : [];
+ this.vars = oldTag ? copyArray(oldTag.vars) : [];
+
+ var attrs = args.length ? args[0] : null;
+ var hasAttrs = typeof(attrs) == "object" && !isTag(attrs);
+
+ this.children = [];
+
+ if (domplate.topContext)
+ this.context = domplate.topContext;
+
+ if (args.length)
+ parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children);
+
+ if (hasAttrs)
+ this.parseAttrs(attrs);
+
+ return creator(this, DomplateTag);
+ },
+
+ parseAttrs: function(args)
+ {
+ for (var name in args)
+ {
+ var val = parseValue(args[name]);
+ readPartNames(val, this.vars);
+
+ if (name.indexOf("on") == 0)
+ {
+ var eventName = name.substr(2);
+ if (!this.listeners)
+ this.listeners = [];
+ this.listeners.push(eventName, val);
+ }
+ else if (name.indexOf("_") == 0)
+ {
+ var propName = name.substr(1);
+ if (!this.props)
+ this.props = {};
+ this.props[propName] = val;
+ }
+ else if (name.indexOf("$") == 0)
+ {
+ var className = name.substr(1);
+ if (!this.classes)
+ this.classes = {};
+ this.classes[className] = val;
+ }
+ else
+ {
+ if (name == "class" && this.attrs.hasOwnProperty(name) )
+ this.attrs[name] += " " + val;
+ else
+ this.attrs[name] = val;
+ }
+ }
+ },
+
+ compile: function()
+ {
+ if (this.renderMarkup)
+ return;
+
+ this.compileMarkup();
+ this.compileDOM();
+
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup);
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM);
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs);
+ },
+
+ compileMarkup: function()
+ {
+ this.markupArgs = [];
+ var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0};
+
+ this.generateMarkup(topBlock, topOuts, blocks, info);
+ this.addCode(topBlock, topOuts, blocks);
+
+ var fnBlock = ['r=(function (__code__, __context__, __in__, __out__'];
+ for (var i = 0; i < info.argIndex; ++i)
+ fnBlock.push(', s', i);
+ fnBlock.push(') {');
+
+ if (this.subject)
+ fnBlock.push('with (this) {');
+ if (this.context)
+ fnBlock.push('with (__context__) {');
+ fnBlock.push('with (__in__) {');
+
+ fnBlock.push.apply(fnBlock, blocks);
+
+ if (this.subject)
+ fnBlock.push('}');
+ if (this.context)
+ fnBlock.push('}');
+
+ fnBlock.push('}})');
+
+ function __link__(tag, code, outputs, args)
+ {
+ if (!tag || !tag.tag)
+ return;
+
+ tag.tag.compile();
+
+ var tagOutputs = [];
+ var markupArgs = [code, tag.tag.context, args, tagOutputs];
+ markupArgs.push.apply(markupArgs, tag.tag.markupArgs);
+ tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs);
+
+ outputs.push(tag);
+ outputs.push(tagOutputs);
+ }
+
+ function __escape__(value)
+ {
+ function replaceChars(ch)
+ {
+ switch (ch)
+ {
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ case "'":
+ return "&#39;";
+ case '"':
+ return "&quot;";
+ }
+ return "?";
+ };
+ return String(value).replace(/[<>&"']/g, replaceChars);
+ }
+
+ function __loop__(iter, outputs, fn)
+ {
+ var iterOuts = [];
+ outputs.push(iterOuts);
+
+ if (iter instanceof Array)
+ iter = new ArrayIterator(iter);
+
+ try
+ {
+ while (1)
+ {
+ var value = iter.next();
+ var itemOuts = [0,0];
+ iterOuts.push(itemOuts);
+ fn.apply(this, [value, itemOuts]);
+ }
+ }
+ catch (exc)
+ {
+ if (exc != StopIteration)
+ throw exc;
+ }
+ }
+
+ var js = fnBlock.join("");
+ var r = null;
+ eval(js);
+ this.renderMarkup = r;
+ },
+
+ getVarNames: function(args)
+ {
+ if (this.vars)
+ args.push.apply(args, this.vars);
+
+ for (var i = 0; i < this.children.length; ++i)
+ {
+ var child = this.children[i];
+ if (isTag(child))
+ child.tag.getVarNames(args);
+ else if (child instanceof Parts)
+ {
+ for (var i = 0; i < child.parts.length; ++i)
+ {
+ if (child.parts[i] instanceof Variable)
+ {
+ var name = child.parts[i].name;
+ var names = name.split(".");
+ args.push(names[0]);
+ }
+ }
+ }
+ }
+ },
+
+ generateMarkup: function(topBlock, topOuts, blocks, info)
+ {
+ topBlock.push(',"<', this.tagName, '"');
+
+ for (var name in this.attrs)
+ {
+ if (name != "class")
+ {
+ var val = this.attrs[name];
+ topBlock.push(', " ', name, '=\\""');
+ addParts(val, ',', topBlock, info, true);
+ topBlock.push(', "\\""');
+ }
+ }
+
+ if (this.listeners)
+ {
+ for (var i = 0; i < this.listeners.length; i += 2)
+ readPartNames(this.listeners[i+1], topOuts);
+ }
+
+ if (this.props)
+ {
+ for (var name in this.props)
+ readPartNames(this.props[name], topOuts);
+ }
+
+ if ( this.attrs.hasOwnProperty("class") || this.classes)
+ {
+ topBlock.push(', " class=\\""');
+ if (this.attrs.hasOwnProperty("class"))
+ addParts(this.attrs["class"], ',', topBlock, info, true);
+ topBlock.push(', " "');
+ for (var name in this.classes)
+ {
+ topBlock.push(', (');
+ addParts(this.classes[name], '', topBlock, info);
+ topBlock.push(' ? "', name, '" + " " : "")');
+ }
+ topBlock.push(', "\\""');
+ }
+ topBlock.push(',">"');
+
+ this.generateChildMarkup(topBlock, topOuts, blocks, info);
+ topBlock.push(',"</', this.tagName, '>"');
+ },
+
+ generateChildMarkup: function(topBlock, topOuts, blocks, info)
+ {
+ for (var i = 0; i < this.children.length; ++i)
+ {
+ var child = this.children[i];
+ if (isTag(child))
+ child.tag.generateMarkup(topBlock, topOuts, blocks, info);
+ else
+ addParts(child, ',', topBlock, info, true);
+ }
+ },
+
+ addCode: function(topBlock, topOuts, blocks)
+ {
+ if (topBlock.length)
+ blocks.push('__code__.push(""', topBlock.join(""), ');');
+ if (topOuts.length)
+ blocks.push('__out__.push(', topOuts.join(","), ');');
+ topBlock.splice(0, topBlock.length);
+ topOuts.splice(0, topOuts.length);
+ },
+
+ addLocals: function(blocks)
+ {
+ var varNames = [];
+ this.getVarNames(varNames);
+
+ var map = {};
+ for (var i = 0; i < varNames.length; ++i)
+ {
+ var name = varNames[i];
+ if ( map.hasOwnProperty(name) )
+ continue;
+
+ map[name] = 1;
+ var names = name.split(".");
+ blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';');
+ }
+ },
+
+ compileDOM: function()
+ {
+ var path = [];
+ var blocks = [];
+ this.domArgs = [];
+ path.embedIndex = 0;
+ path.loopIndex = 0;
+ path.staticIndex = 0;
+ path.renderIndex = 0;
+ var nodeCount = this.generateDOM(path, blocks, this.domArgs);
+
+ var fnBlock = ['r=(function (root, context, o'];
+
+ for (var i = 0; i < path.staticIndex; ++i)
+ fnBlock.push(', ', 's'+i);
+
+ for (var i = 0; i < path.renderIndex; ++i)
+ fnBlock.push(', ', 'd'+i);
+
+ fnBlock.push(') {');
+ for (var i = 0; i < path.loopIndex; ++i)
+ fnBlock.push('var l', i, ' = 0;');
+ for (var i = 0; i < path.embedIndex; ++i)
+ fnBlock.push('var e', i, ' = 0;');
+
+ if (this.subject)
+ fnBlock.push('with (this) {');
+ if (this.context)
+ fnBlock.push('with (context) {');
+
+ fnBlock.push(blocks.join(""));
+
+ if (this.subject)
+ fnBlock.push('}');
+ if (this.context)
+ fnBlock.push('}');
+
+ fnBlock.push('return ', nodeCount, ';');
+ fnBlock.push('})');
+
+ function __bind__(object, fn)
+ {
+ return function(event) { return fn.apply(object, [event]); };
+ }
+
+ function __link__(node, tag, args)
+ {
+ if (!tag || !tag.tag)
+ return;
+
+ tag.tag.compile();
+
+ var domArgs = [node, tag.tag.context, 0];
+ domArgs.push.apply(domArgs, tag.tag.domArgs);
+ domArgs.push.apply(domArgs, args);
+ //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs);
+ return tag.tag.renderDOM.apply(tag.tag.subject, domArgs);
+ }
+
+ var self = this;
+ function __loop__(iter, fn)
+ {
+ var nodeCount = 0;
+ for (var i = 0; i < iter.length; ++i)
+ {
+ iter[i][0] = i;
+ iter[i][1] = nodeCount;
+ nodeCount += fn.apply(this, iter[i]);
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount);
+ }
+ return nodeCount;
+ }
+
+ function __path__(parent, offset)
+ {
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n");
+ var root = parent;
+
+ for (var i = 2; i < arguments.length; ++i)
+ {
+ var index = arguments[i];
+ if (i == 3)
+ index += offset;
+
+ if (index == -1)
+ parent = parent.parentNode;
+ else
+ parent = parent.childNodes[index];
+ }
+
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n");
+ return parent;
+ }
+
+ var js = fnBlock.join("");
+ //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n"));
+ var r = null;
+ eval(js);
+ this.renderDOM = r;
+ },
+
+ generateDOM: function(path, blocks, args)
+ {
+ if (this.listeners || this.props)
+ this.generateNodePath(path, blocks);
+
+ if (this.listeners)
+ {
+ for (var i = 0; i < this.listeners.length; i += 2)
+ {
+ var val = this.listeners[i+1];
+ var arg = generateArg(val, path, args);
+ //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);');
+ blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);');
+ }
+ }
+
+ if (this.props)
+ {
+ for (var name in this.props)
+ {
+ var val = this.props[name];
+ var arg = generateArg(val, path, args);
+ blocks.push('node.', name, ' = ', arg, ';');
+ }
+ }
+
+ this.generateChildDOM(path, blocks, args);
+ return 1;
+ },
+
+ generateNodePath: function(path, blocks)
+ {
+ blocks.push("var node = __path__(root, o");
+ for (var i = 0; i < path.length; ++i)
+ blocks.push(",", path[i]);
+ blocks.push(");");
+ },
+
+ generateChildDOM: function(path, blocks, args)
+ {
+ path.push(0);
+ for (var i = 0; i < this.children.length; ++i)
+ {
+ var child = this.children[i];
+ if (isTag(child))
+ path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args);
+ else
+ path[path.length-1] += '+1';
+ }
+ path.pop();
+ }
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+FBL.DomplateEmbed.prototype = copyObject(FBL.DomplateTag.prototype,
+/** @lends FBL.DomplateEmbed.prototype */
+{
+ merge: function(args, oldTag)
+ {
+ this.value = oldTag ? oldTag.value : parseValue(args[0]);
+ this.attrs = oldTag ? oldTag.attrs : {};
+ this.vars = oldTag ? copyArray(oldTag.vars) : [];
+
+ var attrs = args[1];
+ for (var name in attrs)
+ {
+ var val = parseValue(attrs[name]);
+ this.attrs[name] = val;
+ readPartNames(val, this.vars);
+ }
+
+ return creator(this, DomplateEmbed);
+ },
+
+ getVarNames: function(names)
+ {
+ if (this.value instanceof Parts)
+ names.push(this.value.parts[0].name);
+
+ if (this.vars)
+ names.push.apply(names, this.vars);
+ },
+
+ generateMarkup: function(topBlock, topOuts, blocks, info)
+ {
+ this.addCode(topBlock, topOuts, blocks);
+
+ blocks.push('__link__(');
+ addParts(this.value, '', blocks, info);
+ blocks.push(', __code__, __out__, {');
+
+ var lastName = null;
+ for (var name in this.attrs)
+ {
+ if (lastName)
+ blocks.push(',');
+ lastName = name;
+
+ var val = this.attrs[name];
+ blocks.push('"', name, '":');
+ addParts(val, '', blocks, info);
+ }
+
+ blocks.push('});');
+ //this.generateChildMarkup(topBlock, topOuts, blocks, info);
+ },
+
+ generateDOM: function(path, blocks, args)
+ {
+ var embedName = 'e'+path.embedIndex++;
+
+ this.generateNodePath(path, blocks);
+
+ var valueName = 'd' + path.renderIndex++;
+ var argsName = 'd' + path.renderIndex++;
+ blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');');
+
+ return embedName;
+ }
+});
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+FBL.DomplateLoop.prototype = copyObject(FBL.DomplateTag.prototype,
+/** @lends FBL.DomplateLoop.prototype */
+{
+ merge: function(args, oldTag)
+ {
+ this.varName = oldTag ? oldTag.varName : args[0];
+ this.iter = oldTag ? oldTag.iter : parseValue(args[1]);
+ this.vars = [];
+
+ this.children = oldTag ? copyArray(oldTag.children) : [];
+
+ var offset = Math.min(args.length, 2);
+ parseChildren(args, offset, this.vars, this.children);
+
+ return creator(this, DomplateLoop);
+ },
+
+ getVarNames: function(names)
+ {
+ if (this.iter instanceof Parts)
+ names.push(this.iter.parts[0].name);
+
+ DomplateTag.prototype.getVarNames.apply(this, [names]);
+ },
+
+ generateMarkup: function(topBlock, topOuts, blocks, info)
+ {
+ this.addCode(topBlock, topOuts, blocks);
+
+ var iterName;
+ if (this.iter instanceof Parts)
+ {
+ var part = this.iter.parts[0];
+ iterName = part.name;
+
+ if (part.format)
+ {
+ for (var i = 0; i < part.format.length; ++i)
+ iterName = part.format[i] + "(" + iterName + ")";
+ }
+ }
+ else
+ iterName = this.iter;
+
+ blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {');
+ this.generateChildMarkup(topBlock, topOuts, blocks, info);
+ this.addCode(topBlock, topOuts, blocks);
+ blocks.push('}]);');
+ },
+
+ generateDOM: function(path, blocks, args)
+ {
+ var iterName = 'd'+path.renderIndex++;
+ var counterName = 'i'+path.loopIndex;
+ var loopName = 'l'+path.loopIndex++;
+
+ if (!path.length)
+ path.push(-1, 0);
+
+ var preIndex = path.renderIndex;
+ path.renderIndex = 0;
+
+ var nodeCount = 0;
+
+ var subBlocks = [];
+ var basePath = path[path.length-1];
+ for (var i = 0; i < this.children.length; ++i)
+ {
+ path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount;
+
+ var child = this.children[i];
+ if (isTag(child))
+ nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args);
+ else
+ nodeCount += '+1';
+ }
+
+ path[path.length-1] = basePath+'+'+loopName;
+
+ blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName);
+ for (var i = 0; i < path.renderIndex; ++i)
+ blocks.push(',d'+i);
+ blocks.push(') {');
+ blocks.push(subBlocks.join(""));
+ blocks.push('return ', nodeCount, ';');
+ blocks.push('}]);');
+
+ path.renderIndex = preIndex;
+
+ return loopName;
+ }
+});
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/** @class */
+function Variable(name, format)
+{
+ this.name = name;
+ this.format = format;
+}
+
+/** @class */
+function Parts(parts)
+{
+ this.parts = parts;
+}
+
+// ************************************************************************************************
+
+function parseParts(str)
+{
+ var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g;
+ var index = 0;
+ var parts = [];
+
+ var m;
+ while (m = re.exec(str))
+ {
+ var pre = str.substr(index, (re.lastIndex-m[0].length)-index);
+ if (pre)
+ parts.push(pre);
+
+ var expr = m[1].split("|");
+ parts.push(new Variable(expr[0], expr.slice(1)));
+ index = re.lastIndex;
+ }
+
+ if (!index)
+ return str;
+
+ var post = str.substr(index);
+ if (post)
+ parts.push(post);
+
+ return new Parts(parts);
+}
+
+function parseValue(val)
+{
+ return typeof(val) == 'string' ? parseParts(val) : val;
+}
+
+function parseChildren(args, offset, vars, children)
+{
+ for (var i = offset; i < args.length; ++i)
+ {
+ var val = parseValue(args[i]);
+ children.push(val);
+ readPartNames(val, vars);
+ }
+}
+
+function readPartNames(val, vars)
+{
+ if (val instanceof Parts)
+ {
+ for (var i = 0; i < val.parts.length; ++i)
+ {
+ var part = val.parts[i];
+ if (part instanceof Variable)
+ vars.push(part.name);
+ }
+ }
+}
+
+function generateArg(val, path, args)
+{
+ if (val instanceof Parts)
+ {
+ var vals = [];
+ for (var i = 0; i < val.parts.length; ++i)
+ {
+ var part = val.parts[i];
+ if (part instanceof Variable)
+ {
+ var varName = 'd'+path.renderIndex++;
+ if (part.format)
+ {
+ for (var j = 0; j < part.format.length; ++j)
+ varName = part.format[j] + '(' + varName + ')';
+ }
+
+ vals.push(varName);
+ }
+ else
+ vals.push('"'+part.replace(/"/g, '\\"')+'"');
+ }
+
+ return vals.join('+');
+ }
+ else
+ {
+ args.push(val);
+ return 's' + path.staticIndex++;
+ }
+}
+
+function addParts(val, delim, block, info, escapeIt)
+{
+ var vals = [];
+ if (val instanceof Parts)
+ {
+ for (var i = 0; i < val.parts.length; ++i)
+ {
+ var part = val.parts[i];
+ if (part instanceof Variable)
+ {
+ var partName = part.name;
+ if (part.format)
+ {
+ for (var j = 0; j < part.format.length; ++j)
+ partName = part.format[j] + "(" + partName + ")";
+ }
+
+ if (escapeIt)
+ vals.push("__escape__(" + partName + ")");
+ else
+ vals.push(partName);
+ }
+ else
+ vals.push('"'+ part + '"');
+ }
+ }
+ else if (isTag(val))
+ {
+ info.args.push(val);
+ vals.push('s'+info.argIndex++);
+ }
+ else
+ vals.push('"'+ val + '"');
+
+ var parts = vals.join(delim);
+ if (parts)
+ block.push(delim, parts);
+}
+
+function isTag(obj)
+{
+ return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag;
+}
+
+function creator(tag, cons)
+{
+ var fn = new Function(
+ "var tag = arguments.callee.tag;" +
+ "var cons = arguments.callee.cons;" +
+ "var newTag = new cons();" +
+ "return newTag.merge(arguments, tag);");
+
+ fn.tag = tag;
+ fn.cons = cons;
+ extend(fn, Renderer);
+
+ return fn;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+function copyArray(oldArray)
+{
+ var ary = [];
+ if (oldArray)
+ for (var i = 0; i < oldArray.length; ++i)
+ ary.push(oldArray[i]);
+ return ary;
+}
+
+function copyObject(l, r)
+{
+ var m = {};
+ extend(m, l);
+ extend(m, r);
+ return m;
+}
+
+function extend(l, r)
+{
+ for (var n in r)
+ l[n] = r[n];
+}
+
+function addEvent(object, name, handler)
+{
+ if (document.all)
+ object.attachEvent("on"+name, handler);
+ else
+ object.addEventListener(name, handler, false);
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+/** @class */
+function ArrayIterator(array)
+{
+ var index = -1;
+
+ this.next = function()
+ {
+ if (++index >= array.length)
+ throw StopIteration;
+
+ return array[index];
+ };
+}
+
+/** @class */
+function StopIteration() {}
+
+FBL.$break = function()
+{
+ throw StopIteration;
+};
+
+// ************************************************************************************************
+
+/** @namespace */
+var Renderer =
+{
+ renderHTML: function(args, outputs, self)
+ {
+ var code = [];
+ var markupArgs = [code, this.tag.context, args, outputs];
+ markupArgs.push.apply(markupArgs, this.tag.markupArgs);
+ this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs);
+ return code.join("");
+ },
+
+ insertRows: function(args, before, self)
+ {
+ this.tag.compile();
+
+ var outputs = [];
+ var html = this.renderHTML(args, outputs, self);
+
+ var doc = before.ownerDocument;
+ var div = doc.createElement("div");
+ div.innerHTML = "<table><tbody>"+html+"</tbody></table>";
+
+ var tbody = div.firstChild.firstChild;
+ var parent = before.tagName == "TR" ? before.parentNode : before;
+ var after = before.tagName == "TR" ? before.nextSibling : null;
+
+ var firstRow = tbody.firstChild, lastRow;
+ while (tbody.firstChild)
+ {
+ lastRow = tbody.firstChild;
+ if (after)
+ parent.insertBefore(lastRow, after);
+ else
+ parent.appendChild(lastRow);
+ }
+
+ var offset = 0;
+ if (before.tagName == "TR")
+ {
+ var node = firstRow.parentNode.firstChild;
+ for (; node && node != firstRow; node = node.nextSibling)
+ ++offset;
+ }
+
+ var domArgs = [firstRow, this.tag.context, offset];
+ domArgs.push.apply(domArgs, this.tag.domArgs);
+ domArgs.push.apply(domArgs, outputs);
+
+ this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
+ return [firstRow, lastRow];
+ },
+
+ insertBefore: function(args, before, self)
+ {
+ return this.insertNode(args, before.ownerDocument, before, false, self);
+ },
+
+ insertAfter: function(args, after, self)
+ {
+ return this.insertNode(args, after.ownerDocument, after, true, self);
+ },
+
+ insertNode: function(args, doc, element, isAfter, self)
+ {
+ if (!args)
+ args = {};
+
+ this.tag.compile();
+
+ var outputs = [];
+ var html = this.renderHTML(args, outputs, self);
+
+ //if (FBTrace.DBG_DOM)
+ // FBTrace.sysout("domplate.insertNode html: "+html+"\n");
+
+ var doc = element.ownerDocument;
+ if (!womb || womb.ownerDocument != doc)
+ womb = doc.createElement("div");
+
+ womb.innerHTML = html;
+
+ var root = womb.firstChild;
+ if (isAfter)
+ {
+ while (womb.firstChild)
+ if (element.nextSibling)
+ element.parentNode.insertBefore(womb.firstChild, element.nextSibling);
+ else
+ element.parentNode.appendChild(womb.firstChild);
+ }
+ else
+ {
+ while (womb.lastChild)
+ element.parentNode.insertBefore(womb.lastChild, element);
+ }
+
+ var domArgs = [root, this.tag.context, 0];
+ domArgs.push.apply(domArgs, this.tag.domArgs);
+ domArgs.push.apply(domArgs, outputs);
+
+ //if (FBTrace.DBG_DOM)
+ // FBTrace.sysout("domplate.insertNode domArgs:", domArgs);
+ this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
+
+ return root;
+ },
+ /**/
+
+ /*
+ insertAfter: function(args, before, self)
+ {
+ this.tag.compile();
+
+ var outputs = [];
+ var html = this.renderHTML(args, outputs, self);
+
+ var doc = before.ownerDocument;
+ if (!womb || womb.ownerDocument != doc)
+ womb = doc.createElement("div");
+
+ womb.innerHTML = html;
+
+ var root = womb.firstChild;
+ while (womb.firstChild)
+ if (before.nextSibling)
+ before.parentNode.insertBefore(womb.firstChild, before.nextSibling);
+ else
+ before.parentNode.appendChild(womb.firstChild);
+
+ var domArgs = [root, this.tag.context, 0];
+ domArgs.push.apply(domArgs, this.tag.domArgs);
+ domArgs.push.apply(domArgs, outputs);
+
+ this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null),
+ domArgs);
+
+ return root;
+ },
+ /**/
+
+ replace: function(args, parent, self)
+ {
+ this.tag.compile();
+
+ var outputs = [];
+ var html = this.renderHTML(args, outputs, self);
+
+ var root;
+ if (parent.nodeType == 1)
+ {
+ parent.innerHTML = html;
+ root = parent.firstChild;
+ }
+ else
+ {
+ if (!parent || parent.nodeType != 9)
+ parent = document;
+
+ if (!womb || womb.ownerDocument != parent)
+ womb = parent.createElement("div");
+ womb.innerHTML = html;
+
+ root = womb.firstChild;
+ //womb.removeChild(root);
+ }
+
+ var domArgs = [root, this.tag.context, 0];
+ domArgs.push.apply(domArgs, this.tag.domArgs);
+ domArgs.push.apply(domArgs, outputs);
+ this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
+
+ return root;
+ },
+
+ append: function(args, parent, self)
+ {
+ this.tag.compile();
+
+ var outputs = [];
+ var html = this.renderHTML(args, outputs, self);
+ //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n");
+
+ if (!womb || womb.ownerDocument != parent.ownerDocument)
+ womb = parent.ownerDocument.createElement("div");
+ womb.innerHTML = html;
+
+ // TODO: xxxpedro domplate port to Firebug
+ var root = womb.firstChild;
+ while (womb.firstChild)
+ parent.appendChild(womb.firstChild);
+
+ // clearing element reference to avoid reference error in IE8 when switching contexts
+ womb = null;
+
+ var domArgs = [root, this.tag.context, 0];
+ domArgs.push.apply(domArgs, this.tag.domArgs);
+ domArgs.push.apply(domArgs, outputs);
+
+ //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs);
+ this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
+
+ return root;
+ }
+};
+
+// ************************************************************************************************
+
+function defineTags()
+{
+ for (var i = 0; i < arguments.length; ++i)
+ {
+ var tagName = arguments[i];
+ var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);");
+ fn.DomplateTag = DomplateTag;
+
+ var fnName = tagName.toUpperCase();
+ FBL[fnName] = fn;
+ }
+}
+
+defineTags(
+ "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr",
+ "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select",
+ "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe"
+);
+
+})();
+
+
+/* See license.txt for terms of usage */
+
+var FirebugReps = FBL.ns(function() { with (FBL) {
+
+
+// ************************************************************************************************
+// Common Tags
+
+var OBJECTBOX = this.OBJECTBOX =
+ SPAN({"class": "objectBox objectBox-$className"});
+
+var OBJECTBLOCK = this.OBJECTBLOCK =
+ DIV({"class": "objectBox objectBox-$className"});
+
+var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation
+ A({
+ "class": "objectLink objectLink-$className a11yFocus",
+ href: "javascript:void(0)",
+ // workaround to show XPath (a better approach would use the tooltip on mouseover,
+ // so the XPath information would be calculated dynamically, but we need to create
+ // a tooltip class/wrapper around Menu or InfoTip)
+ title: "$object|FBL.getElementXPath",
+ _repObject: "$object"
+ })
+ : // Other browsers
+ A({
+ "class": "objectLink objectLink-$className a11yFocus",
+ // workaround to show XPath (a better approach would use the tooltip on mouseover,
+ // so the XPath information would be calculated dynamically, but we need to create
+ // a tooltip class/wrapper around Menu or InfoTip)
+ title: "$object|FBL.getElementXPath",
+ _repObject: "$object"
+ });
+
+
+// ************************************************************************************************
+
+this.Undefined = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX("undefined"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "undefined",
+
+ supportsObject: function(object, type)
+ {
+ return type == "undefined";
+ }
+});
+
+// ************************************************************************************************
+
+this.Null = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX("null"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "null",
+
+ supportsObject: function(object, type)
+ {
+ return object == null;
+ }
+});
+
+// ************************************************************************************************
+
+this.Nada = domplate(Firebug.Rep,
+{
+ tag: SPAN(""),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "nada"
+});
+
+// ************************************************************************************************
+
+this.Number = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX("$object"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "number",
+
+ supportsObject: function(object, type)
+ {
+ return type == "boolean" || type == "number";
+ }
+});
+
+// ************************************************************************************************
+
+this.String = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX("&quot;$object&quot;"),
+
+ shortTag: OBJECTBOX("&quot;$object|cropString&quot;"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "string",
+
+ supportsObject: function(object, type)
+ {
+ return type == "string";
+ }
+});
+
+// ************************************************************************************************
+
+this.Text = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX("$object"),
+
+ shortTag: OBJECTBOX("$object|cropString"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "text"
+});
+
+// ************************************************************************************************
+
+this.Caption = domplate(Firebug.Rep,
+{
+ tag: SPAN({"class": "caption"}, "$object")
+});
+
+// ************************************************************************************************
+
+this.Warning = domplate(Firebug.Rep,
+{
+ tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR")
+});
+
+// ************************************************************************************************
+
+this.Func = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK("$object|summarizeFunction"),
+
+ summarizeFunction: function(fn)
+ {
+ var fnRegex = /function ([^(]+\([^)]*\)) \{/;
+ var fnText = safeToString(fn);
+
+ var m = fnRegex.exec(fnText);
+ return m ? m[1] : "function()";
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ copySource: function(fn)
+ {
+ copyToClipboard(safeToString(fn));
+ },
+
+ monitor: function(fn, script, monitored)
+ {
+ if (monitored)
+ Firebug.Debugger.unmonitorScript(fn, script, "monitor");
+ else
+ Firebug.Debugger.monitorScript(fn, script, "monitor");
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "function",
+
+ supportsObject: function(object, type)
+ {
+ return isFunction(object);
+ },
+
+ inspectObject: function(fn, context)
+ {
+ var sourceLink = findSourceForFunction(fn, context);
+ if (sourceLink)
+ Firebug.chrome.select(sourceLink);
+ if (FBTrace.DBG_FUNCTION_NAME)
+ FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink);
+ },
+
+ getTooltip: function(fn, context)
+ {
+ var script = findScriptForFunctionInContext(context, fn);
+ if (script)
+ return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]);
+ else
+ if (fn.toString)
+ return fn.toString();
+ },
+
+ getTitle: function(fn, context)
+ {
+ var name = fn.name ? fn.name : "function";
+ return name + "()";
+ },
+
+ getContextMenuItems: function(fn, target, context, script)
+ {
+ if (!script)
+ script = findScriptForFunctionInContext(context, fn);
+ if (!script)
+ return;
+
+ var scriptInfo = getSourceFileAndLineByScript(context, script);
+ var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
+
+ var name = script ? getFunctionName(script, context) : fn.name;
+ return [
+ {label: "CopySource", command: bindFixed(this.copySource, this, fn) },
+ "-",
+ {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
+ type: "checkbox", checked: monitored,
+ command: bindFixed(this.monitor, this, fn, script, monitored) }
+ ];
+ }
+});
+
+// ************************************************************************************************
+/*
+this.jsdScript = domplate(Firebug.Rep,
+{
+ copySource: function(script)
+ {
+ var fn = script.functionObject.getWrappedValue();
+ return FirebugReps.Func.copySource(fn);
+ },
+
+ monitor: function(fn, script, monitored)
+ {
+ fn = script.functionObject.getWrappedValue();
+ return FirebugReps.Func.monitor(fn, script, monitored);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "jsdScript",
+ inspectable: false,
+
+ supportsObject: function(object, type)
+ {
+ return object instanceof jsdIScript;
+ },
+
+ inspectObject: function(script, context)
+ {
+ var sourceLink = getSourceLinkForScript(script, context);
+ if (sourceLink)
+ Firebug.chrome.select(sourceLink);
+ },
+
+ getRealObject: function(script, context)
+ {
+ return script;
+ },
+
+ getTooltip: function(script)
+ {
+ return $STRF("jsdIScript", [script.tag]);
+ },
+
+ getTitle: function(script, context)
+ {
+ var fn = script.functionObject.getWrappedValue();
+ return FirebugReps.Func.getTitle(fn, context);
+ },
+
+ getContextMenuItems: function(script, target, context)
+ {
+ var fn = script.functionObject.getWrappedValue();
+
+ var scriptInfo = getSourceFileAndLineByScript(context, script);
+ var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
+
+ var name = getFunctionName(script, context);
+
+ return [
+ {label: "CopySource", command: bindFixed(this.copySource, this, script) },
+ "-",
+ {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
+ type: "checkbox", checked: monitored,
+ command: bindFixed(this.monitor, this, fn, script, monitored) }
+ ];
+ }
+});
+/**/
+//************************************************************************************************
+
+this.Obj = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK(
+ SPAN({"class": "objectTitle"}, "$object|getTitle "),
+
+ SPAN({"class": "objectProps"},
+ SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
+ FOR("prop", "$object|propIterator",
+ SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"),
+ SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
+ TAG("$prop.tag", {object: "$prop.object"}),
+ SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
+ ),
+ SPAN({"class": "objectRightBrace"}, "}")
+ )
+ ),
+
+ propNumberTag:
+ SPAN({"class": "objectProp-number"}, "$object"),
+
+ propStringTag:
+ SPAN({"class": "objectProp-string"}, "&quot;$object&quot;"),
+
+ propObjectTag:
+ SPAN({"class": "objectProp-object"}, "$object"),
+
+ propIterator: function (object)
+ {
+ ///Firebug.ObjectShortIteratorMax;
+ var maxLength = 55; // default max length for long representation
+
+ if (!object)
+ return [];
+
+ var props = [];
+ var length = 0;
+
+ var numProperties = 0;
+ var numPropertiesShown = 0;
+ var maxLengthReached = false;
+
+ var lib = this;
+
+ var propRepsMap =
+ {
+ "boolean": this.propNumberTag,
+ "number": this.propNumberTag,
+ "string": this.propStringTag,
+ "object": this.propObjectTag
+ };
+
+ try
+ {
+ var title = Firebug.Rep.getTitle(object);
+ length += title.length;
+
+ for (var name in object)
+ {
+ var value;
+ try
+ {
+ value = object[name];
+ }
+ catch (exc)
+ {
+ continue;
+ }
+
+ var type = typeof(value);
+ if (type == "boolean" ||
+ type == "number" ||
+ (type == "string" && value) ||
+ (type == "object" && value && value.toString))
+ {
+ var tag = propRepsMap[type];
+
+ var value = (type == "object") ?
+ Firebug.getRep(value).getTitle(value) :
+ value + "";
+
+ length += name.length + value.length + 4;
+
+ if (length <= maxLength)
+ {
+ props.push({
+ tag: tag,
+ name: name,
+ object: value,
+ equal: "=",
+ delim: ", "
+ });
+
+ numPropertiesShown++;
+ }
+ else
+ maxLengthReached = true;
+
+ }
+
+ numProperties++;
+
+ if (maxLengthReached && numProperties > numPropertiesShown)
+ break;
+ }
+
+ if (numProperties > numPropertiesShown)
+ {
+ props.push({
+ object: "...", //xxxHonza localization
+ tag: FirebugReps.Caption.tag,
+ name: "",
+ equal:"",
+ delim:""
+ });
+ }
+ else if (props.length > 0)
+ {
+ props[props.length-1].delim = '';
+ }
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions when trying to read from certain objects, like
+ // StorageList, but don't let that gum up the works
+ // XXXjjb also History.previous fails because object is a web-page object which does not have
+ // permission to read the history
+ }
+ return props;
+ },
+
+ fb_1_6_propIterator: function (object, max)
+ {
+ max = max || 3;
+ if (!object)
+ return [];
+
+ var props = [];
+ var len = 0, count = 0;
+
+ try
+ {
+ for (var name in object)
+ {
+ var value;
+ try
+ {
+ value = object[name];
+ }
+ catch (exc)
+ {
+ continue;
+ }
+
+ var t = typeof(value);
+ if (t == "boolean" || t == "number" || (t == "string" && value)
+ || (t == "object" && value && value.toString))
+ {
+ var rep = Firebug.getRep(value);
+ var tag = rep.shortTag || rep.tag;
+ if (t == "object")
+ {
+ value = rep.getTitle(value);
+ tag = rep.titleTag;
+ }
+ count++;
+ if (count <= max)
+ props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "});
+ else
+ break;
+ }
+ }
+ if (count > max)
+ {
+ props[Math.max(1,max-1)] = {
+ object: "more...", //xxxHonza localization
+ tag: FirebugReps.Caption.tag,
+ name: "",
+ equal:"",
+ delim:""
+ };
+ }
+ else if (props.length > 0)
+ {
+ props[props.length-1].delim = '';
+ }
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions when trying to read from certain objects, like
+ // StorageList, but don't let that gum up the works
+ // XXXjjb also History.previous fails because object is a web-page object which does not have
+ // permission to read the history
+ }
+ return props;
+ },
+
+ /*
+ propIterator: function (object)
+ {
+ if (!object)
+ return [];
+
+ var props = [];
+ var len = 0;
+
+ try
+ {
+ for (var name in object)
+ {
+ var val;
+ try
+ {
+ val = object[name];
+ }
+ catch (exc)
+ {
+ continue;
+ }
+
+ var t = typeof val;
+ if (t == "boolean" || t == "number" || (t == "string" && val)
+ || (t == "object" && !isFunction(val) && val && val.toString))
+ {
+ var title = (t == "object")
+ ? Firebug.getRep(val).getTitle(val)
+ : val+"";
+
+ len += name.length + title.length + 1;
+ if (len < 50)
+ props.push({name: name, value: title});
+ else
+ break;
+ }
+ }
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions when trying to read from certain objects, like
+ // StorageList, but don't let that gum up the works
+ // XXXjjb also History.previous fails because object is a web-page object which does not have
+ // permission to read the history
+ }
+
+ return props;
+ },
+ /**/
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "object",
+
+ supportsObject: function(object, type)
+ {
+ return true;
+ }
+});
+
+
+// ************************************************************************************************
+
+this.Arr = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTBOX({_repObject: "$object"},
+ SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["),
+ FOR("item", "$object|arrayIterator",
+ TAG("$item.tag", {object: "$item.object"}),
+ SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim")
+ ),
+ SPAN({"class": "arrayRightBracket", role : "presentation"}, "]")
+ ),
+
+ shortTag:
+ OBJECTBOX({_repObject: "$object"},
+ SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["),
+ FOR("item", "$object|shortArrayIterator",
+ TAG("$item.tag", {object: "$item.object"}),
+ SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim")
+ ),
+ // TODO: xxxpedro - confirm this on Firebug
+ //FOR("prop", "$object|shortPropIterator",
+ // " $prop.name=",
+ // SPAN({"class": "objectPropValue"}, "$prop.value|cropString")
+ //),
+ SPAN({"class": "arrayRightBracket"}, "]")
+ ),
+
+ arrayIterator: function(array)
+ {
+ var items = [];
+ for (var i = 0; i < array.length; ++i)
+ {
+ var value = array[i];
+ var rep = Firebug.getRep(value);
+ var tag = rep.shortTag ? rep.shortTag : rep.tag;
+ var delim = (i == array.length-1 ? "" : ", ");
+
+ items.push({object: value, tag: tag, delim: delim});
+ }
+
+ return items;
+ },
+
+ shortArrayIterator: function(array)
+ {
+ var items = [];
+ for (var i = 0; i < array.length && i < 3; ++i)
+ {
+ var value = array[i];
+ var rep = Firebug.getRep(value);
+ var tag = rep.shortTag ? rep.shortTag : rep.tag;
+ var delim = (i == array.length-1 ? "" : ", ");
+
+ items.push({object: value, tag: tag, delim: delim});
+ }
+
+ if (array.length > 3)
+ items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""});
+
+ return items;
+ },
+
+ shortPropIterator: this.Obj.propIterator,
+
+ getItemIndex: function(child)
+ {
+ var arrayIndex = 0;
+ for (child = child.previousSibling; child; child = child.previousSibling)
+ {
+ if (child.repObject)
+ ++arrayIndex;
+ }
+ return arrayIndex;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "array",
+
+ supportsObject: function(object)
+ {
+ return this.isArray(object);
+ },
+
+ // http://code.google.com/p/fbug/issues/detail?id=874
+ // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007
+ isArray: function(obj) {
+ try {
+ if (!obj)
+ return false;
+ else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8)
+ return true;
+ else if (isFinite(obj.length) && isFunction(obj.splice))
+ return true;
+ else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments
+ return true;
+ else if (instanceOf(obj, "HTMLCollection"))
+ return true;
+ else if (instanceOf(obj, "NodeList"))
+ return true;
+ else
+ return false;
+ }
+ catch(exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ {
+ FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */
+ FBTrace.sysout("isArray Fails on obj", obj);
+ }
+ }
+
+ return false;
+ },
+ // END Yahoo BSD SOURCE See license below.
+
+ getTitle: function(object, context)
+ {
+ return "[" + object.length + "]";
+ }
+});
+
+// ************************************************************************************************
+
+this.Property = domplate(Firebug.Rep,
+{
+ supportsObject: function(object)
+ {
+ return object instanceof Property;
+ },
+
+ getRealObject: function(prop, context)
+ {
+ return prop.object[prop.name];
+ },
+
+ getTitle: function(prop, context)
+ {
+ return prop.name;
+ }
+});
+
+// ************************************************************************************************
+
+this.NetFile = domplate(this.Obj,
+{
+ supportsObject: function(object)
+ {
+ return object instanceof Firebug.NetFile;
+ },
+
+ browseObject: function(file, context)
+ {
+ openNewTab(file.href);
+ return true;
+ },
+
+ getRealObject: function(file, context)
+ {
+ return null;
+ }
+});
+
+// ************************************************************************************************
+
+this.Except = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTBOX({_repObject: "$object"}, "$object.message"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "exception",
+
+ supportsObject: function(object)
+ {
+ return object instanceof ErrorCopy;
+ }
+});
+
+
+// ************************************************************************************************
+
+this.Element = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK(
+ "&lt;",
+ SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"),
+ FOR("attr", "$object|attrIterator",
+ "&nbsp;$attr.nodeName=&quot;", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), "&quot;"
+ ),
+ "&gt;"
+ ),
+
+ shortTag:
+ OBJECTLINK(
+ SPAN({"class": "$object|getVisible"},
+ SPAN({"class": "selectorTag"}, "$object|getSelectorTag"),
+ SPAN({"class": "selectorId"}, "$object|getSelectorId"),
+ SPAN({"class": "selectorClass"}, "$object|getSelectorClass"),
+ SPAN({"class": "selectorValue"}, "$object|getValue")
+ )
+ ),
+
+ getVisible: function(elt)
+ {
+ return isVisible(elt) ? "" : "selectorHidden";
+ },
+
+ getSelectorTag: function(elt)
+ {
+ return elt.nodeName.toLowerCase();
+ },
+
+ getSelectorId: function(elt)
+ {
+ return elt.id ? "#" + elt.id : "";
+ },
+
+ getSelectorClass: function(elt)
+ {
+ return elt.className ? "." + elt.className.split(" ")[0] : "";
+ },
+
+ getValue: function(elt)
+ {
+ // TODO: xxxpedro
+ return "";
+ var value;
+ if (elt instanceof HTMLImageElement)
+ value = getFileName(elt.src);
+ else if (elt instanceof HTMLAnchorElement)
+ value = getFileName(elt.href);
+ else if (elt instanceof HTMLInputElement)
+ value = elt.value;
+ else if (elt instanceof HTMLFormElement)
+ value = getFileName(elt.action);
+ else if (elt instanceof HTMLScriptElement)
+ value = getFileName(elt.src);
+
+ return value ? " " + cropString(value, 20) : "";
+ },
+
+ attrIterator: function(elt)
+ {
+ var attrs = [];
+ var idAttr, classAttr;
+ if (elt.attributes)
+ {
+ for (var i = 0; i < elt.attributes.length; ++i)
+ {
+ var attr = elt.attributes[i];
+
+ // we must check if the attribute is specified otherwise IE will show them
+ if (!attr.specified || attr.nodeName && attr.nodeName.indexOf("firebug-") != -1)
+ continue;
+ else if (attr.nodeName == "id")
+ idAttr = attr;
+ else if (attr.nodeName == "class")
+ classAttr = attr;
+ else if (attr.nodeName == "style")
+ attrs.push({
+ nodeName: attr.nodeName,
+ nodeValue: attr.nodeValue ||
+ // IE won't recognize the attr.nodeValue of <style> nodes ...
+ // and will return CSS property names in upper case, so we need to convert them
+ elt.style.cssText.replace(/([^\s]+)\s*:/g,
+ function(m,g){return g.toLowerCase()+":"})
+ });
+ else
+ attrs.push(attr);
+ }
+ }
+ if (classAttr)
+ attrs.splice(0, 0, classAttr);
+ if (idAttr)
+ attrs.splice(0, 0, idAttr);
+
+ return attrs;
+ },
+
+ shortAttrIterator: function(elt)
+ {
+ var attrs = [];
+ if (elt.attributes)
+ {
+ for (var i = 0; i < elt.attributes.length; ++i)
+ {
+ var attr = elt.attributes[i];
+ if (attr.nodeName == "id" || attr.nodeName == "class")
+ attrs.push(attr);
+ }
+ }
+
+ return attrs;
+ },
+
+ getHidden: function(elt)
+ {
+ return isVisible(elt) ? "" : "nodeHidden";
+ },
+
+ getXPath: function(elt)
+ {
+ return getElementTreeXPath(elt);
+ },
+
+ // TODO: xxxpedro remove this?
+ getNodeText: function(element)
+ {
+ var text = element.textContent;
+ if (Firebug.showFullTextNodes)
+ return text;
+ else
+ return cropString(text, 50);
+ },
+ /**/
+
+ getNodeTextGroups: function(element)
+ {
+ var text = element.textContent;
+ if (!Firebug.showFullTextNodes)
+ {
+ text=cropString(text,50);
+ }
+
+ var escapeGroups=[];
+
+ if (Firebug.showTextNodesWithWhitespace)
+ escapeGroups.push({
+ 'group': 'whitespace',
+ 'class': 'nodeWhiteSpace',
+ 'extra': {
+ '\t': '_Tab',
+ '\n': '_Para',
+ ' ' : '_Space'
+ }
+ });
+ if (Firebug.showTextNodesWithEntities)
+ escapeGroups.push({
+ 'group':'text',
+ 'class':'nodeTextEntity',
+ 'extra':{}
+ });
+
+ if (escapeGroups.length)
+ return escapeGroupsForEntities(text, escapeGroups);
+ else
+ return [{str:text,'class':'',extra:''}];
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ copyHTML: function(elt)
+ {
+ var html = getElementXML(elt);
+ copyToClipboard(html);
+ },
+
+ copyInnerHTML: function(elt)
+ {
+ copyToClipboard(elt.innerHTML);
+ },
+
+ copyXPath: function(elt)
+ {
+ var xpath = getElementXPath(elt);
+ copyToClipboard(xpath);
+ },
+
+ persistor: function(context, xpath)
+ {
+ var elts = xpath
+ ? getElementsByXPath(context.window.document, xpath)
+ : null;
+
+ return elts && elts.length ? elts[0] : null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "element",
+
+ supportsObject: function(object)
+ {
+ //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string";
+ return instanceOf(object, "Element");
+ },
+
+ browseObject: function(elt, context)
+ {
+ var tag = elt.nodeName.toLowerCase();
+ if (tag == "script")
+ openNewTab(elt.src);
+ else if (tag == "link")
+ openNewTab(elt.href);
+ else if (tag == "a")
+ openNewTab(elt.href);
+ else if (tag == "img")
+ openNewTab(elt.src);
+
+ return true;
+ },
+
+ persistObject: function(elt, context)
+ {
+ var xpath = getElementXPath(elt);
+
+ return bind(this.persistor, top, xpath);
+ },
+
+ getTitle: function(element, context)
+ {
+ return getElementCSSSelector(element);
+ },
+
+ getTooltip: function(elt)
+ {
+ return this.getXPath(elt);
+ },
+
+ getContextMenuItems: function(elt, target, context)
+ {
+ var monitored = areEventsMonitored(elt, null, context);
+
+ return [
+ {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) },
+ {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) },
+ {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) },
+ "-",
+ {label: "ShowEventsInConsole", type: "checkbox", checked: monitored,
+ command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) },
+ "-",
+ {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) }
+ ];
+ }
+});
+
+// ************************************************************************************************
+
+this.TextNode = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK(
+ "&lt;",
+ SPAN({"class": "nodeTag"}, "TextNode"),
+ "&nbsp;textContent=&quot;", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), "&quot;",
+ "&gt;"
+ ),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "textNode",
+
+ supportsObject: function(object)
+ {
+ return object instanceof Text;
+ }
+});
+
+// ************************************************************************************************
+
+this.Document = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
+
+ getLocation: function(doc)
+ {
+ return doc.location ? getFileName(doc.location.href) : "";
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "object",
+
+ supportsObject: function(object)
+ {
+ //return object instanceof Document || object instanceof XMLDocument;
+ return instanceOf(object, "Document");
+ },
+
+ browseObject: function(doc, context)
+ {
+ openNewTab(doc.location.href);
+ return true;
+ },
+
+ persistObject: function(doc, context)
+ {
+ return this.persistor;
+ },
+
+ persistor: function(context)
+ {
+ return context.window.document;
+ },
+
+ getTitle: function(win, context)
+ {
+ return "document";
+ },
+
+ getTooltip: function(doc)
+ {
+ return doc.location.href;
+ }
+});
+
+// ************************************************************************************************
+
+this.StyleSheet = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
+
+ getLocation: function(styleSheet)
+ {
+ return getFileName(styleSheet.href);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ copyURL: function(styleSheet)
+ {
+ copyToClipboard(styleSheet.href);
+ },
+
+ openInTab: function(styleSheet)
+ {
+ openNewTab(styleSheet.href);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "object",
+
+ supportsObject: function(object)
+ {
+ //return object instanceof CSSStyleSheet;
+ return instanceOf(object, "CSSStyleSheet");
+ },
+
+ browseObject: function(styleSheet, context)
+ {
+ openNewTab(styleSheet.href);
+ return true;
+ },
+
+ persistObject: function(styleSheet, context)
+ {
+ return bind(this.persistor, top, styleSheet.href);
+ },
+
+ getTooltip: function(styleSheet)
+ {
+ return styleSheet.href;
+ },
+
+ getContextMenuItems: function(styleSheet, target, context)
+ {
+ return [
+ {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) },
+ "-",
+ {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) }
+ ];
+ },
+
+ persistor: function(context, href)
+ {
+ return getStyleSheetByHref(href, context);
+ }
+});
+
+// ************************************************************************************************
+
+this.Window = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
+
+ getLocation: function(win)
+ {
+ try
+ {
+ return (win && win.location && !win.closed) ? getFileName(win.location.href) : "";
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("reps.Window window closed?");
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "object",
+
+ supportsObject: function(object)
+ {
+ return instanceOf(object, "Window");
+ },
+
+ browseObject: function(win, context)
+ {
+ openNewTab(win.location.href);
+ return true;
+ },
+
+ persistObject: function(win, context)
+ {
+ return this.persistor;
+ },
+
+ persistor: function(context)
+ {
+ return context.window;
+ },
+
+ getTitle: function(win, context)
+ {
+ return "window";
+ },
+
+ getTooltip: function(win)
+ {
+ if (win && !win.closed)
+ return win.location.href;
+ }
+});
+
+// ************************************************************************************************
+
+this.Event = domplate(Firebug.Rep,
+{
+ tag: TAG("$copyEventTag", {object: "$object|copyEvent"}),
+
+ copyEventTag:
+ OBJECTLINK("$object|summarizeEvent"),
+
+ summarizeEvent: function(event)
+ {
+ var info = [event.type, ' '];
+
+ var eventFamily = getEventFamily(event.type);
+ if (eventFamily == "mouse")
+ info.push("clientX=", event.clientX, ", clientY=", event.clientY);
+ else if (eventFamily == "key")
+ info.push("charCode=", event.charCode, ", keyCode=", event.keyCode);
+
+ return info.join("");
+ },
+
+ copyEvent: function(event)
+ {
+ return new EventCopy(event);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "object",
+
+ supportsObject: function(object)
+ {
+ //return object instanceof Event || object instanceof EventCopy;
+ return instanceOf(object, "Event") || instanceOf(object, "EventCopy");
+ },
+
+ getTitle: function(event, context)
+ {
+ return "Event " + event.type;
+ }
+});
+
+// ************************************************************************************************
+
+this.SourceLink = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
+
+ hideSourceLink: function(sourceLink)
+ {
+ return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true;
+ },
+
+ getSourceLinkTitle: function(sourceLink)
+ {
+ if (!sourceLink)
+ return "";
+
+ try
+ {
+ var fileName = getFileName(sourceLink.href);
+ fileName = decodeURIComponent(fileName);
+ fileName = cropString(fileName, 17);
+ }
+ catch(exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc);
+ }
+
+ return typeof sourceLink.line == "number" ?
+ fileName + " (line " + sourceLink.line + ")" :
+ fileName;
+
+ // TODO: xxxpedro
+ //return $STRF("Line", [fileName, sourceLink.line]);
+ },
+
+ copyLink: function(sourceLink)
+ {
+ copyToClipboard(sourceLink.href);
+ },
+
+ openInTab: function(sourceLink)
+ {
+ openNewTab(sourceLink.href);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "sourceLink",
+
+ supportsObject: function(object)
+ {
+ return object instanceof SourceLink;
+ },
+
+ getTooltip: function(sourceLink)
+ {
+ return decodeURI(sourceLink.href);
+ },
+
+ inspectObject: function(sourceLink, context)
+ {
+ if (sourceLink.type == "js")
+ {
+ var scriptFile = getSourceFileByHref(sourceLink.href, context);
+ if (scriptFile)
+ return Firebug.chrome.select(sourceLink);
+ }
+ else if (sourceLink.type == "css")
+ {
+ // If an object is defined, treat it as the highest priority for
+ // inspect actions
+ if (sourceLink.object) {
+ Firebug.chrome.select(sourceLink.object);
+ return;
+ }
+
+ var stylesheet = getStyleSheetByHref(sourceLink.href, context);
+ if (stylesheet)
+ {
+ var ownerNode = stylesheet.ownerNode;
+ if (ownerNode)
+ {
+ Firebug.chrome.select(sourceLink, "html");
+ return;
+ }
+
+ var panel = context.getPanel("stylesheet");
+ if (panel && panel.getRuleByLine(stylesheet, sourceLink.line))
+ return Firebug.chrome.select(sourceLink);
+ }
+ }
+
+ // Fallback is to just open the view-source window on the file
+ viewSource(sourceLink.href, sourceLink.line);
+ },
+
+ browseObject: function(sourceLink, context)
+ {
+ openNewTab(sourceLink.href);
+ return true;
+ },
+
+ getContextMenuItems: function(sourceLink, target, context)
+ {
+ return [
+ {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) },
+ "-",
+ {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) }
+ ];
+ }
+});
+
+// ************************************************************************************************
+
+this.SourceFile = domplate(this.SourceLink,
+{
+ tag:
+ OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
+
+ persistor: function(context, href)
+ {
+ return getSourceFileByHref(href, context);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "sourceFile",
+
+ supportsObject: function(object)
+ {
+ return object instanceof SourceFile;
+ },
+
+ persistObject: function(sourceFile)
+ {
+ return bind(this.persistor, top, sourceFile.href);
+ },
+
+ browseObject: function(sourceLink, context)
+ {
+ },
+
+ getTooltip: function(sourceFile)
+ {
+ return sourceFile.href;
+ }
+});
+
+// ************************************************************************************************
+
+this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers
+{
+ tag:
+ OBJECTBLOCK(
+ A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"),
+ " ( ",
+ FOR("arg", "$object|argIterator",
+ TAG("$arg.tag", {object: "$arg.value"}),
+ SPAN({"class": "arrayComma"}, "$arg.delim")
+ ),
+ " )",
+ SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle")
+ ),
+
+ getCallName: function(frame)
+ {
+ //TODO: xxxpedro reps StackFrame
+ return frame.name || "anonymous";
+
+ //return getFunctionName(frame.script, frame.context);
+ },
+
+ getSourceLinkTitle: function(frame)
+ {
+ //TODO: xxxpedro reps StackFrame
+ var fileName = cropString(getFileName(frame.href), 20);
+ return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : "");
+
+ var fileName = cropString(getFileName(frame.href), 17);
+ return $STRF("Line", [fileName, frame.lineNo]);
+ },
+
+ argIterator: function(frame)
+ {
+ if (!frame.args)
+ return [];
+
+ var items = [];
+
+ for (var i = 0; i < frame.args.length; ++i)
+ {
+ var arg = frame.args[i];
+
+ if (!arg)
+ break;
+
+ var rep = Firebug.getRep(arg.value);
+ var tag = rep.shortTag ? rep.shortTag : rep.tag;
+
+ var delim = (i == frame.args.length-1 ? "" : ", ");
+
+ items.push({name: arg.name, value: arg.value, tag: tag, delim: delim});
+ }
+
+ return items;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "stackFrame",
+
+ supportsObject: function(object)
+ {
+ return object instanceof StackFrame;
+ },
+
+ inspectObject: function(stackFrame, context)
+ {
+ var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js");
+ Firebug.chrome.select(sourceLink);
+ },
+
+ getTooltip: function(stackFrame, context)
+ {
+ return $STRF("Line", [stackFrame.href, stackFrame.lineNo]);
+ }
+
+});
+
+// ************************************************************************************************
+
+this.StackTrace = domplate(Firebug.Rep,
+{
+ tag:
+ FOR("frame", "$object.frames focusRow",
+ TAG(this.StackFrame.tag, {object: "$frame"})
+ ),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "stackTrace",
+
+ supportsObject: function(object)
+ {
+ return object instanceof StackTrace;
+ }
+});
+
+// ************************************************************************************************
+
+this.jsdStackFrame = domplate(Firebug.Rep,
+{
+ inspectable: false,
+
+ supportsObject: function(object)
+ {
+ return (object instanceof jsdIStackFrame) && (object.isValid);
+ },
+
+ getTitle: function(frame, context)
+ {
+ if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null
+ return getFunctionName(frame.script, context);
+ },
+
+ getTooltip: function(frame, context)
+ {
+ if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null
+ var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame);
+ if (sourceInfo)
+ return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]);
+ else
+ return $STRF("Line", [frame.script.fileName, frame.line]);
+ },
+
+ getContextMenuItems: function(frame, target, context)
+ {
+ var fn = frame.script.functionObject.getWrappedValue();
+ return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script);
+ }
+});
+
+// ************************************************************************************************
+
+this.ErrorMessage = domplate(Firebug.Rep,
+{
+ tag:
+ OBJECTBOX({
+ $hasTwisty: "$object|hasStackTrace",
+ $hasBreakSwitch: "$object|hasBreakSwitch",
+ $breakForError: "$object|hasErrorBreak",
+ _repObject: "$object",
+ _stackTrace: "$object|getLastErrorStackTrace",
+ onclick: "$onToggleError"},
+
+ DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'},
+ "$object.message|getMessage"
+ ),
+ DIV({"class": "errorTrace"}),
+ DIV({"class": "errorSourceBox errorSource-$object|getSourceType"},
+ IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}),
+ A({"class": "errorSource a11yFocus"}, "$object|getLine")
+ ),
+ TAG(this.SourceLink.tag, {object: "$object|getSourceLink"})
+ ),
+
+ getLastErrorStackTrace: function(error)
+ {
+ return error.trace;
+ },
+
+ hasStackTrace: function(error)
+ {
+ var url = error.href.toString();
+ var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1);
+ return !fromCommandLine && error.trace;
+ },
+
+ hasBreakSwitch: function(error)
+ {
+ return error.href && error.lineNo > 0;
+ },
+
+ hasErrorBreak: function(error)
+ {
+ return fbs.hasErrorBreakpoint(error.href, error.lineNo);
+ },
+
+ getMessage: function(message)
+ {
+ var re = /\[Exception... "(.*?)" nsresult:/;
+ var m = re.exec(message);
+ return m ? m[1] : message;
+ },
+
+ getLine: function(error)
+ {
+ if (error.category == "js")
+ {
+ if (error.source)
+ return cropString(error.source, 80);
+ else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1)
+ return cropString(error.getSourceLine(), 80);
+ }
+ },
+
+ getSourceLink: function(error)
+ {
+ var ext = error.category == "css" ? "css" : "js";
+ return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null;
+ },
+
+ getSourceType: function(error)
+ {
+ // Errors occurring inside of HTML event handlers look like "foo.html (line 1)"
+ // so let's try to skip those
+ if (error.source)
+ return "syntax";
+ else if (error.lineNo == 1 && getFileExtension(error.href) != "js")
+ return "none";
+ else if (error.category == "css")
+ return "none";
+ else if (!error.href || !error.lineNo)
+ return "none";
+ else
+ return "exec";
+ },
+
+ onToggleError: function(event)
+ {
+ var target = event.currentTarget;
+ if (hasClass(event.target, "errorBreak"))
+ {
+ this.breakOnThisError(target.repObject);
+ }
+ else if (hasClass(event.target, "errorSource"))
+ {
+ var panel = Firebug.getElementPanel(event.target);
+ this.inspectObject(target.repObject, panel.context);
+ }
+ else if (hasClass(event.target, "errorTitle"))
+ {
+ var traceBox = target.childNodes[1];
+ toggleClass(target, "opened");
+ event.target.setAttribute('aria-checked', hasClass(target, "opened"));
+ if (hasClass(target, "opened"))
+ {
+ if (target.stackTrace)
+ var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox);
+ if (Firebug.A11yModel.enabled)
+ {
+ var panel = Firebug.getElementPanel(event.target);
+ dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]);
+ }
+ }
+ else
+ clearNode(traceBox);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ copyError: function(error)
+ {
+ var message = [
+ this.getMessage(error.message),
+ error.href,
+ "Line " + error.lineNo
+ ];
+ copyToClipboard(message.join("\n"));
+ },
+
+ breakOnThisError: function(error)
+ {
+ if (this.hasErrorBreak(error))
+ Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo);
+ else
+ Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "errorMessage",
+ inspectable: false,
+
+ supportsObject: function(object)
+ {
+ return object instanceof ErrorMessage;
+ },
+
+ inspectObject: function(error, context)
+ {
+ var sourceLink = this.getSourceLink(error);
+ FirebugReps.SourceLink.inspectObject(sourceLink, context);
+ },
+
+ getContextMenuItems: function(error, target, context)
+ {
+ var breakOnThisError = this.hasErrorBreak(error);
+
+ var items = [
+ {label: "CopyError", command: bindFixed(this.copyError, this, error) }
+ ];
+
+ if (error.category == "css")
+ {
+ items.push(
+ "-",
+ {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
+ command: bindFixed(this.breakOnThisError, this, error) },
+
+ optionMenu("BreakOnAllErrors", "breakOnErrors")
+ );
+ }
+
+ return items;
+ }
+});
+
+// ************************************************************************************************
+
+this.Assert = domplate(Firebug.Rep,
+{
+ tag:
+ DIV(
+ DIV({"class": "errorTitle"}),
+ DIV({"class": "assertDescription"})
+ ),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "assert",
+
+ inspectObject: function(error, context)
+ {
+ var sourceLink = this.getSourceLink(error);
+ Firebug.chrome.select(sourceLink);
+ },
+
+ getContextMenuItems: function(error, target, context)
+ {
+ var breakOnThisError = this.hasErrorBreak(error);
+
+ return [
+ {label: "CopyError", command: bindFixed(this.copyError, this, error) },
+ "-",
+ {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
+ command: bindFixed(this.breakOnThisError, this, error) },
+ {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors,
+ command: bindFixed(this.breakOnAllErrors, this, error) }
+ ];
+ }
+});
+
+// ************************************************************************************************
+
+this.SourceText = domplate(Firebug.Rep,
+{
+ tag:
+ DIV(
+ FOR("line", "$object|lineIterator",
+ DIV({"class": "sourceRow", role : "presentation"},
+ SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"),
+ SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text")
+ )
+ )
+ ),
+
+ lineIterator: function(sourceText)
+ {
+ var maxLineNoChars = (sourceText.lines.length + "").length;
+ var list = [];
+
+ for (var i = 0; i < sourceText.lines.length; ++i)
+ {
+ // Make sure all line numbers are the same width (with a fixed-width font)
+ var lineNo = (i+1) + "";
+ while (lineNo.length < maxLineNoChars)
+ lineNo = " " + lineNo;
+
+ list.push({lineNo: lineNo, text: sourceText.lines[i]});
+ }
+
+ return list;
+ },
+
+ getHTML: function(sourceText)
+ {
+ return getSourceLineRange(sourceText, 1, sourceText.lines.length);
+ }
+});
+
+//************************************************************************************************
+this.nsIDOMHistory = domplate(Firebug.Rep,
+{
+ tag:OBJECTBOX({onclick: "$showHistory"},
+ OBJECTLINK("$object|summarizeHistory")
+ ),
+
+ className: "nsIDOMHistory",
+
+ summarizeHistory: function(history)
+ {
+ try
+ {
+ var items = history.length;
+ return items + " history entries";
+ }
+ catch(exc)
+ {
+ return "object does not support history (nsIDOMHistory)";
+ }
+ },
+
+ showHistory: function(history)
+ {
+ try
+ {
+ var items = history.length; // if this throws, then unsupported
+ Firebug.chrome.select(history);
+ }
+ catch (exc)
+ {
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ supportsObject: function(object, type)
+ {
+ return (object instanceof Ci.nsIDOMHistory);
+ }
+});
+
+// ************************************************************************************************
+this.ApplicationCache = domplate(Firebug.Rep,
+{
+ tag:OBJECTBOX({onclick: "$showApplicationCache"},
+ OBJECTLINK("$object|summarizeCache")
+ ),
+
+ summarizeCache: function(applicationCache)
+ {
+ try
+ {
+ return applicationCache.length + " items in offline cache";
+ }
+ catch(exc)
+ {
+ return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264";
+ }
+ },
+
+ showApplicationCache: function(event)
+ {
+ openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264");
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "applicationCache",
+
+ supportsObject: function(object, type)
+ {
+ if (Ci.nsIDOMOfflineResourceList)
+ return (object instanceof Ci.nsIDOMOfflineResourceList);
+ }
+
+});
+
+this.Storage = domplate(Firebug.Rep,
+{
+ tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")),
+
+ summarize: function(storage)
+ {
+ return storage.length +" items in Storage";
+ },
+ show: function(storage)
+ {
+ openNewTab("http://dev.w3.org/html5/webstorage/#storage-0");
+ },
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ className: "Storage",
+
+ supportsObject: function(object, type)
+ {
+ return (object instanceof Storage);
+ }
+
+});
+
+// ************************************************************************************************
+Firebug.registerRep(
+ //this.nsIDOMHistory, // make this early to avoid exceptions
+ this.Undefined,
+ this.Null,
+ this.Number,
+ this.String,
+ this.Window,
+ //this.ApplicationCache, // must come before Arr (array) else exceptions.
+ //this.ErrorMessage,
+ this.Element,
+ //this.TextNode,
+ this.Document,
+ this.StyleSheet,
+ this.Event,
+ //this.SourceLink,
+ //this.SourceFile,
+ //this.StackTrace,
+ //this.StackFrame,
+ //this.jsdStackFrame,
+ //this.jsdScript,
+ //this.NetFile,
+ this.Property,
+ this.Except,
+ this.Arr
+);
+
+Firebug.setDefaultReps(this.Func, this.Obj);
+
+}});
+
+// ************************************************************************************************
+/*
+ * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source"
+ * in only this file reps.js. John J. Barton June 2007.
+ *
+Software License Agreement (BSD License)
+
+Copyright (c) 2006, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * /
+ */
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+var saveTimeout = 400;
+var pageAmount = 10;
+
+// ************************************************************************************************
+// Globals
+
+var currentTarget = null;
+var currentGroup = null;
+var currentPanel = null;
+var currentEditor = null;
+
+var defaultEditor = null;
+
+var originalClassName = null;
+
+var originalValue = null;
+var defaultValue = null;
+var previousValue = null;
+
+var invalidEditor = false;
+var ignoreNextInput = false;
+
+// ************************************************************************************************
+
+Firebug.Editor = extend(Firebug.Module,
+{
+ supportsStopEvent: true,
+
+ dispatchName: "editor",
+ tabCharacter: " ",
+
+ startEditing: function(target, value, editor)
+ {
+ this.stopEditing();
+
+ if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter"))
+ return;
+
+ var panel = Firebug.getElementPanel(target);
+ if (!panel.editable)
+ return;
+
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("editor.startEditing " + value, target);
+
+ defaultValue = target.getAttribute("defaultValue");
+ if (value == undefined)
+ {
+ var textContent = isIE ? "innerText" : "textContent";
+ value = target[textContent];
+ if (value == defaultValue)
+ value = "";
+ }
+
+ originalValue = previousValue = value;
+
+ invalidEditor = false;
+ currentTarget = target;
+ currentPanel = panel;
+ currentGroup = getAncestorByClass(target, "editGroup");
+
+ currentPanel.editing = true;
+
+ var panelEditor = currentPanel.getEditor(target, value);
+ currentEditor = editor ? editor : panelEditor;
+ if (!currentEditor)
+ currentEditor = getDefaultEditor(currentPanel);
+
+ var inlineParent = getInlineParent(target);
+ var targetSize = getOffsetSize(inlineParent);
+
+ setClass(panel.panelNode, "editing");
+ setClass(target, "editing");
+ if (currentGroup)
+ setClass(currentGroup, "editing");
+
+ currentEditor.show(target, currentPanel, value, targetSize);
+ //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]);
+ currentEditor.beginEditing(target, value);
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("Editor start panel "+currentPanel.name);
+ this.attachListeners(currentEditor, panel.context);
+ },
+
+ stopEditing: function(cancel)
+ {
+ if (!currentTarget)
+ return;
+
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout);
+
+ clearTimeout(this.saveTimeout);
+ delete this.saveTimeout;
+
+ this.detachListeners(currentEditor, currentPanel.context);
+
+ removeClass(currentPanel.panelNode, "editing");
+ removeClass(currentTarget, "editing");
+ if (currentGroup)
+ removeClass(currentGroup, "editing");
+
+ var value = currentEditor.getValue();
+ if (value == defaultValue)
+ value = "";
+
+ var removeGroup = currentEditor.endEditing(currentTarget, value, cancel);
+
+ try
+ {
+ if (cancel)
+ {
+ //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]);
+ if (value != originalValue)
+ this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue);
+
+ if (removeGroup && !originalValue && currentGroup)
+ currentGroup.parentNode.removeChild(currentGroup);
+ }
+ else if (!value)
+ {
+ this.saveEditAndNotifyListeners(currentTarget, null, previousValue);
+
+ if (removeGroup && currentGroup)
+ currentGroup.parentNode.removeChild(currentGroup);
+ }
+ else
+ this.save(value);
+ }
+ catch (exc)
+ {
+ //throw exc.message;
+ //ERROR(exc);
+ }
+
+ currentEditor.hide();
+ currentPanel.editing = false;
+
+ //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]);
+ //if (FBTrace.DBG_EDITOR)
+ // FBTrace.sysout("Editor stop panel "+currentPanel.name);
+
+ currentTarget = null;
+ currentGroup = null;
+ currentPanel = null;
+ currentEditor = null;
+ originalValue = null;
+ invalidEditor = false;
+
+ return value;
+ },
+
+ cancelEditing: function()
+ {
+ return this.stopEditing(true);
+ },
+
+ update: function(saveNow)
+ {
+ if (this.saveTimeout)
+ clearTimeout(this.saveTimeout);
+
+ invalidEditor = true;
+
+ currentEditor.layout();
+
+ if (saveNow)
+ this.save();
+ else
+ {
+ var context = currentPanel.context;
+ this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout);
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout);
+ }
+ },
+
+ save: function(value)
+ {
+ if (!invalidEditor)
+ return;
+
+ if (value == undefined)
+ value = currentEditor.getValue();
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null"));
+ try
+ {
+ this.saveEditAndNotifyListeners(currentTarget, value, previousValue);
+
+ previousValue = value;
+ invalidEditor = false;
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("editor.save FAILS "+exc, exc);
+ }
+ },
+
+ saveEditAndNotifyListeners: function(currentTarget, value, previousValue)
+ {
+ currentEditor.saveEdit(currentTarget, value, previousValue);
+ //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]);
+ },
+
+ setEditTarget: function(element)
+ {
+ if (!element)
+ {
+ dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]);
+ this.stopEditing();
+ }
+ else if (hasClass(element, "insertBefore"))
+ this.insertRow(element, "before");
+ else if (hasClass(element, "insertAfter"))
+ this.insertRow(element, "after");
+ else
+ this.startEditing(element);
+ },
+
+ tabNextEditor: function()
+ {
+ if (!currentTarget)
+ return;
+
+ var value = currentEditor.getValue();
+ var nextEditable = currentTarget;
+ do
+ {
+ nextEditable = !value && currentGroup
+ ? getNextOutsider(nextEditable, currentGroup)
+ : getNextByClass(nextEditable, "editable");
+ }
+ while (nextEditable && !nextEditable.offsetHeight);
+
+ this.setEditTarget(nextEditable);
+ },
+
+ tabPreviousEditor: function()
+ {
+ if (!currentTarget)
+ return;
+
+ var value = currentEditor.getValue();
+ var prevEditable = currentTarget;
+ do
+ {
+ prevEditable = !value && currentGroup
+ ? getPreviousOutsider(prevEditable, currentGroup)
+ : getPreviousByClass(prevEditable, "editable");
+ }
+ while (prevEditable && !prevEditable.offsetHeight);
+
+ this.setEditTarget(prevEditable);
+ },
+
+ insertRow: function(relative, insertWhere)
+ {
+ var group =
+ relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget;
+ var value = this.stopEditing();
+
+ currentPanel = Firebug.getElementPanel(group);
+
+ currentEditor = currentPanel.getEditor(group, value);
+ if (!currentEditor)
+ currentEditor = getDefaultEditor(currentPanel);
+
+ currentGroup = currentEditor.insertNewRow(group, insertWhere);
+ if (!currentGroup)
+ return;
+
+ var editable = hasClass(currentGroup, "editable")
+ ? currentGroup
+ : getNextByClass(currentGroup, "editable");
+
+ if (editable)
+ this.setEditTarget(editable);
+ },
+
+ insertRowForObject: function(relative)
+ {
+ var container = getAncestorByClass(relative, "insertInto");
+ if (container)
+ {
+ relative = getChildByClass(container, "insertBefore");
+ if (relative)
+ this.insertRow(relative, "before");
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ attachListeners: function(editor, context)
+ {
+ var win = isIE ?
+ currentTarget.ownerDocument.parentWindow :
+ currentTarget.ownerDocument.defaultView;
+
+ addEvent(win, "resize", this.onResize);
+ addEvent(win, "blur", this.onBlur);
+
+ var chrome = Firebug.chrome;
+
+ this.listeners = [
+ chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this))
+ ];
+
+ if (editor.arrowCompletion)
+ {
+ this.listeners.push(
+ chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)),
+ chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)),
+ chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)),
+ chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount))
+ );
+ }
+
+ if (currentEditor.tabNavigation)
+ {
+ this.listeners.push(
+ chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)),
+ chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")),
+ chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)),
+ chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this))
+ );
+ }
+ else if (currentEditor.multiLine)
+ {
+ this.listeners.push(
+ chrome.keyCodeListen("TAB", null, insertTab)
+ );
+ }
+ else
+ {
+ this.listeners.push(
+ chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this))
+ );
+
+ if (currentEditor.tabCompletion)
+ {
+ this.listeners.push(
+ chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)),
+ chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1))
+ );
+ }
+ }
+ },
+
+ detachListeners: function(editor, context)
+ {
+ if (!this.listeners)
+ return;
+
+ var win = isIE ?
+ currentTarget.ownerDocument.parentWindow :
+ currentTarget.ownerDocument.defaultView;
+
+ removeEvent(win, "resize", this.onResize);
+ removeEvent(win, "blur", this.onBlur);
+
+ var chrome = Firebug.chrome;
+ if (chrome)
+ {
+ for (var i = 0; i < this.listeners.length; ++i)
+ chrome.keyIgnore(this.listeners[i]);
+ }
+
+ delete this.listeners;
+ },
+
+ onResize: function(event)
+ {
+ currentEditor.layout(true);
+ },
+
+ onBlur: function(event)
+ {
+ if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box))
+ this.stopEditing();
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Module
+
+ initialize: function()
+ {
+ Firebug.Module.initialize.apply(this, arguments);
+
+ this.onResize = bindFixed(this.onResize, this);
+ this.onBlur = bind(this.onBlur, this);
+ },
+
+ disable: function()
+ {
+ this.stopEditing();
+ },
+
+ showContext: function(browser, context)
+ {
+ this.stopEditing();
+ },
+
+ showPanel: function(browser, panel)
+ {
+ this.stopEditing();
+ }
+});
+
+// ************************************************************************************************
+// BaseEditor
+
+Firebug.BaseEditor = extend(Firebug.MeasureBox,
+{
+ getValue: function()
+ {
+ },
+
+ setValue: function(value)
+ {
+ },
+
+ show: function(target, panel, value, textSize, targetSize)
+ {
+ },
+
+ hide: function()
+ {
+ },
+
+ layout: function(forceAll)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Support for context menus within inline editors.
+
+ getContextMenuItems: function(target)
+ {
+ var items = [];
+ items.push({label: "Cut", commandID: "cmd_cut"});
+ items.push({label: "Copy", commandID: "cmd_copy"});
+ items.push({label: "Paste", commandID: "cmd_paste"});
+ return items;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Editor Module listeners will get "onBeginEditing" just before this call
+
+ beginEditing: function(target, value)
+ {
+ },
+
+ // Editor Module listeners will get "onSaveEdit" just after this call
+ saveEdit: function(target, value, previousValue)
+ {
+ },
+
+ endEditing: function(target, value, cancel)
+ {
+ // Remove empty groups by default
+ return true;
+ },
+
+ insertNewRow: function(target, insertWhere)
+ {
+ }
+});
+
+// ************************************************************************************************
+// InlineEditor
+
+// basic inline editor attributes
+var inlineEditorAttributes = {
+ "class": "textEditorInner",
+
+ type: "text",
+ spellcheck: "false",
+
+ onkeypress: "$onKeyPress",
+
+ onoverflow: "$onOverflow",
+ oncontextmenu: "$onContextMenu"
+};
+
+// IE does not support the oninput event, so we're using the onkeydown to signalize
+// the relevant keyboard events, and the onpropertychange to actually handle the
+// input event, which should happen after the onkeydown event is fired and after the
+// value of the input is updated, but before the onkeyup and before the input (with the
+// new value) is rendered
+if (isIE)
+{
+ inlineEditorAttributes.onpropertychange = "$onInput";
+ inlineEditorAttributes.onkeydown = "$onKeyDown";
+}
+// for other browsers we use the oninput event
+else
+{
+ inlineEditorAttributes.oninput = "$onInput";
+}
+
+Firebug.InlineEditor = function(doc)
+{
+ this.initializeInline(doc);
+};
+
+Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor,
+{
+ enterOnBlur: true,
+ outerMargin: 8,
+ shadowExpand: 7,
+
+ tag:
+ DIV({"class": "inlineEditor"},
+ DIV({"class": "textEditorTop1"},
+ DIV({"class": "textEditorTop2"})
+ ),
+ DIV({"class": "textEditorInner1"},
+ DIV({"class": "textEditorInner2"},
+ INPUT(
+ inlineEditorAttributes
+ )
+ )
+ ),
+ DIV({"class": "textEditorBottom1"},
+ DIV({"class": "textEditorBottom2"})
+ )
+ ),
+
+ inputTag :
+ INPUT({"class": "textEditorInner", type: "text",
+ /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"}
+ ),
+
+ expanderTag:
+ IMG({"class": "inlineExpander", src: "blank.gif"}),
+
+ initialize: function()
+ {
+ this.fixedWidth = false;
+ this.completeAsYouType = true;
+ this.tabNavigation = true;
+ this.multiLine = false;
+ this.tabCompletion = false;
+ this.arrowCompletion = true;
+ this.noWrap = true;
+ this.numeric = false;
+ },
+
+ destroy: function()
+ {
+ this.destroyInput();
+ },
+
+ initializeInline: function(doc)
+ {
+ if (FBTrace.DBG_EDITOR)
+ FBTrace.sysout("Firebug.InlineEditor initializeInline()");
+
+ //this.box = this.tag.replace({}, doc, this);
+ this.box = this.tag.append({}, doc.body, this);
+
+ //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required
+ this.input = this.box.getElementsByTagName("input")[0];
+
+ if (isIElt8)
+ {
+ this.input.style.top = "-8px";
+ }
+
+ this.expander = this.expanderTag.replace({}, doc, this);
+ this.initialize();
+ },
+
+ destroyInput: function()
+ {
+ // XXXjoe Need to remove input/keypress handlers to avoid leaks
+ },
+
+ getValue: function()
+ {
+ return this.input.value;
+ },
+
+ setValue: function(value)
+ {
+ // It's only a one-line editor, so new lines shouldn't be allowed
+ return this.input.value = stripNewLines(value);
+ },
+
+ show: function(target, panel, value, targetSize)
+ {
+ //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]);
+ this.target = target;
+ this.panel = panel;
+
+ this.targetSize = targetSize;
+
+ // TODO: xxxpedro editor
+ //this.targetOffset = getClientOffset(target);
+
+ // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the
+ // offset values of invisible elements, or empty elements. So, in order to get the
+ // correct values, we temporary inject a character in the innerHTML of the empty element,
+ // then we get the offset values, and next, we restore the original innerHTML value.
+ var innerHTML = target.innerHTML;
+ var isEmptyElement = !innerHTML;
+ if (isEmptyElement)
+ target.innerHTML = ".";
+
+ // Get the position of the target element (that is about to be edited)
+ this.targetOffset =
+ {
+ x: target.offsetLeft,
+ y: target.offsetTop
+ };
+
+ // Restore the original innerHTML value of the empty element
+ if (isEmptyElement)
+ target.innerHTML = innerHTML;
+
+ this.originalClassName = this.box.className;
+
+ var classNames = target.className.split(" ");
+ for (var i = 0; i < classNames.length; ++i)
+ setClass(this.box, "editor-" + classNames[i]);
+
+ // Make the editor match the target's font style
+ copyTextStyles(target, this.box);
+
+ this.setValue(value);
+
+ if (this.fixedWidth)
+ this.updateLayout(true);
+ else
+ {
+ this.startMeasuring(target);
+ this.textSize = this.measureInputText(value);
+
+ // Correct the height of the box to make the funky CSS drop-shadow line up
+ var parent = this.input.parentNode;
+ if (hasClass(parent, "textEditorInner2"))
+ {
+ var yDiff = this.textSize.height - this.shadowExpand;
+
+ // IE6 height offset
+ if (isIE6)
+ yDiff -= 2;
+
+ parent.style.height = yDiff + "px";
+ parent.parentNode.style.height = yDiff + "px";
+ }
+
+ this.updateLayout(true);
+ }
+
+ this.getAutoCompleter().reset();
+
+ if (isIElt8)
+ panel.panelNode.appendChild(this.box);
+ else
+ target.offsetParent.appendChild(this.box);
+
+ //console.log(target);
+ //this.input.select(); // it's called bellow, with setTimeout
+
+ if (isIE)
+ {
+ // reset input style
+ this.input.style.fontFamily = "Monospace";
+ this.input.style.fontSize = "11px";
+ }
+
+ // Insert the "expander" to cover the target element with white space
+ if (!this.fixedWidth)
+ {
+ copyBoxStyles(target, this.expander);
+
+ target.parentNode.replaceChild(this.expander, target);
+ collapse(target, true);
+ this.expander.parentNode.insertBefore(target, this.expander);
+ }
+
+ //TODO: xxxpedro
+ //scrollIntoCenterView(this.box, null, true);
+
+ // Display the editor after change its size and position to avoid flickering
+ this.box.style.display = "block";
+
+ // we need to call input.focus() and input.select() with a timeout,
+ // otherwise it won't work on all browsers due to timing issues
+ var self = this;
+ setTimeout(function(){
+ self.input.focus();
+ self.input.select();
+ },0);
+ },
+
+ hide: function()
+ {
+ this.box.className = this.originalClassName;
+
+ if (!this.fixedWidth)
+ {
+ this.stopMeasuring();
+
+ collapse(this.target, false);
+
+ if (this.expander.parentNode)
+ this.expander.parentNode.removeChild(this.expander);
+ }
+
+ if (this.box.parentNode)
+ {
+ ///setSelectionRange(this.input, 0, 0);
+ this.input.blur();
+
+ this.box.parentNode.removeChild(this.box);
+ }
+
+ delete this.target;
+ delete this.panel;
+ },
+
+ layout: function(forceAll)
+ {
+ if (!this.fixedWidth)
+ this.textSize = this.measureInputText(this.input.value);
+
+ if (forceAll)
+ this.targetOffset = getClientOffset(this.expander);
+
+ this.updateLayout(false, forceAll);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ beginEditing: function(target, value)
+ {
+ },
+
+ saveEdit: function(target, value, previousValue)
+ {
+ },
+
+ endEditing: function(target, value, cancel)
+ {
+ // Remove empty groups by default
+ return true;
+ },
+
+ insertNewRow: function(target, insertWhere)
+ {
+ },
+
+ advanceToNext: function(target, charCode)
+ {
+ return false;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getAutoCompleteRange: function(value, offset)
+ {
+ },
+
+ getAutoCompleteList: function(preExpr, expr, postExpr)
+ {
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getAutoCompleter: function()
+ {
+ if (!this.autoCompleter)
+ {
+ this.autoCompleter = new Firebug.AutoCompleter(null,
+ bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this),
+ true, false);
+ }
+
+ return this.autoCompleter;
+ },
+
+ completeValue: function(amt)
+ {
+ //console.log("completeValue");
+
+ var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0);
+
+ if (selectRangeCallback)
+ {
+ Firebug.Editor.update(true);
+
+ // We need to select the editor text after calling update in Safari/Chrome,
+ // otherwise the text won't be selected
+ if (isSafari)
+ setTimeout(selectRangeCallback,0);
+ else
+ selectRangeCallback();
+ }
+ else
+ this.incrementValue(amt);
+ },
+
+ incrementValue: function(amt)
+ {
+ var value = this.input.value;
+
+ // TODO: xxxpedro editor
+ if (isIE)
+ var start = getInputSelectionStart(this.input), end = start;
+ else
+ var start = this.input.selectionStart, end = this.input.selectionEnd;
+
+ //debugger;
+ var range = this.getAutoCompleteRange(value, start);
+ if (!range || range.type != "int")
+ range = {start: 0, end: value.length-1};
+
+ var expr = value.substr(range.start, range.end-range.start+1);
+ preExpr = value.substr(0, range.start);
+ postExpr = value.substr(range.end+1);
+
+ // See if the value is an integer, and if so increment it
+ var intValue = parseInt(expr);
+ if (!!intValue || intValue == 0)
+ {
+ var m = /\d+/.exec(expr);
+ var digitPost = expr.substr(m.index+m[0].length);
+
+ var completion = intValue-amt;
+ this.input.value = preExpr + completion + digitPost + postExpr;
+
+ setSelectionRange(this.input, start, end);
+
+ Firebug.Editor.update(true);
+
+ return true;
+ }
+ else
+ return false;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onKeyPress: function(event)
+ {
+ //console.log("onKeyPress", event);
+ if (event.keyCode == 27 && !this.completeAsYouType)
+ {
+ var reverted = this.getAutoCompleter().revert(this.input);
+ if (reverted)
+ cancelEvent(event);
+ }
+ else if (event.charCode && this.advanceToNext(this.target, event.charCode))
+ {
+ Firebug.Editor.tabNextEditor();
+ cancelEvent(event);
+ }
+ else
+ {
+ if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57)
+ && event.charCode != 45 && event.charCode != 46)
+ FBL.cancelEvent(event);
+ else
+ {
+ // If the user backspaces, don't autocomplete after the upcoming input event
+ this.ignoreNextInput = event.keyCode == 8;
+ }
+ }
+ },
+
+ onOverflow: function()
+ {
+ this.updateLayout(false, false, 3);
+ },
+
+ onKeyDown: function(event)
+ {
+ //console.log("onKeyDown", event.keyCode);
+ if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8)
+ {
+ this.keyDownPressed = true;
+ }
+ },
+
+ onInput: function(event)
+ {
+ //debugger;
+
+ // skip not relevant onpropertychange calls on IE
+ if (isIE)
+ {
+ if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed)
+ return;
+
+ this.keyDownPressed = false;
+ }
+
+ //console.log("onInput", event);
+ //console.trace();
+
+ var selectRangeCallback;
+
+ if (this.ignoreNextInput)
+ {
+ this.ignoreNextInput = false;
+ this.getAutoCompleter().reset();
+ }
+ else if (this.completeAsYouType)
+ selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false);
+ else
+ this.getAutoCompleter().reset();
+
+ Firebug.Editor.update();
+
+ if (selectRangeCallback)
+ {
+ // We need to select the editor text after calling update in Safari/Chrome,
+ // otherwise the text won't be selected
+ if (isSafari)
+ setTimeout(selectRangeCallback,0);
+ else
+ selectRangeCallback();
+ }
+ },
+
+ onContextMenu: function(event)
+ {
+ cancelEvent(event);
+
+ var popup = $("fbInlineEditorPopup");
+ FBL.eraseNode(popup);
+
+ var target = event.target || event.srcElement;
+ var menu = this.getContextMenuItems(target);
+ if (menu)
+ {
+ for (var i = 0; i < menu.length; ++i)
+ FBL.createMenuItem(popup, menu[i]);
+ }
+
+ if (!popup.firstChild)
+ return false;
+
+ popup.openPopupAtScreen(event.screenX, event.screenY, true);
+ return true;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ updateLayout: function(initial, forceAll, extraWidth)
+ {
+ if (this.fixedWidth)
+ {
+ this.box.style.left = (this.targetOffset.x) + "px";
+ this.box.style.top = (this.targetOffset.y) + "px";
+
+ var w = this.target.offsetWidth;
+ var h = this.target.offsetHeight;
+ this.input.style.width = w + "px";
+ this.input.style.height = (h-3) + "px";
+ }
+ else
+ {
+ if (initial || forceAll)
+ {
+ this.box.style.left = this.targetOffset.x + "px";
+ this.box.style.top = this.targetOffset.y + "px";
+ }
+
+ var approxTextWidth = this.textSize.width;
+ var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x)
+ - this.outerMargin;
+
+ var wrapped = initial
+ ? this.noWrap && this.targetSize.height > this.textSize.height+3
+ : this.noWrap && approxTextWidth > maxWidth;
+
+ if (wrapped)
+ {
+ var style = isIE ?
+ this.target.currentStyle :
+ this.target.ownerDocument.defaultView.getComputedStyle(this.target, "");
+
+ targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight);
+
+ // Make the width fit the remaining x-space from the offset to the far right
+ approxTextWidth = maxWidth - targetMargin;
+
+ this.input.style.width = "100%";
+ this.box.style.width = approxTextWidth + "px";
+ }
+ else
+ {
+ // Make the input one character wider than the text value so that
+ // typing does not ever cause the textbox to scroll
+ var charWidth = this.measureInputText('m').width;
+
+ // Sometimes we need to make the editor a little wider, specifically when
+ // an overflow happens, otherwise it will scroll off some text on the left
+ if (extraWidth)
+ charWidth *= extraWidth;
+
+ var inputWidth = approxTextWidth + charWidth;
+
+ if (initial)
+ {
+ if (isIE)
+ {
+ // TODO: xxxpedro
+ var xDiff = 13;
+ this.box.style.width = (inputWidth + xDiff) + "px";
+ }
+ else
+ this.box.style.width = "auto";
+ }
+ else
+ {
+ // TODO: xxxpedro
+ var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth;
+ this.box.style.width = (inputWidth + xDiff) + "px";
+ }
+
+ this.input.style.width = inputWidth + "px";
+ }
+
+ this.expander.style.width = approxTextWidth + "px";
+ this.expander.style.height = Math.max(this.textSize.height-3,0) + "px";
+ }
+
+ if (forceAll)
+ scrollIntoCenterView(this.box, null, true);
+ }
+});
+
+// ************************************************************************************************
+// Autocompletion
+
+Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive)
+{
+ var candidates = null;
+ var originalValue = null;
+ var originalOffset = -1;
+ var lastExpr = null;
+ var lastOffset = -1;
+ var exprOffset = 0;
+ var lastIndex = 0;
+ var preParsed = null;
+ var preExpr = null;
+ var postExpr = null;
+
+ this.revert = function(textBox)
+ {
+ if (originalOffset != -1)
+ {
+ textBox.value = originalValue;
+
+ setSelectionRange(textBox, originalOffset, originalOffset);
+
+ this.reset();
+ return true;
+ }
+ else
+ {
+ this.reset();
+ return false;
+ }
+ };
+
+ this.reset = function()
+ {
+ candidates = null;
+ originalValue = null;
+ originalOffset = -1;
+ lastExpr = null;
+ lastOffset = 0;
+ exprOffset = 0;
+ };
+
+ this.complete = function(context, textBox, cycle, reverse)
+ {
+ //console.log("complete", context, textBox, cycle, reverse);
+ // TODO: xxxpedro important port to firebug (variable leak)
+ //var value = lastValue = textBox.value;
+ var value = textBox.value;
+
+ //var offset = textBox.selectionStart;
+ var offset = getInputSelectionStart(textBox);
+
+ // The result of selectionStart() in Safari/Chrome is 1 unit less than the result
+ // in Firefox. Therefore, we need to manually adjust the value here.
+ if (isSafari && !cycle && offset >= 0) offset++;
+
+ if (!selectMode && originalOffset != -1)
+ offset = originalOffset;
+
+ if (!candidates || !cycle || offset != lastOffset)
+ {
+ originalOffset = offset;
+ originalValue = value;
+
+ // Find the part of the string that will be parsed
+ var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0;
+ preParsed = value.substr(0, parseStart);
+ var parsed = value.substr(parseStart);
+
+ // Find the part of the string that is being completed
+ var range = getRange ? getRange(parsed, offset-parseStart, context) : null;
+ if (!range)
+ range = {start: 0, end: parsed.length-1 };
+
+ var expr = parsed.substr(range.start, range.end-range.start+1);
+ preExpr = parsed.substr(0, range.start);
+ postExpr = parsed.substr(range.end+1);
+ exprOffset = parseStart + range.start;
+
+ if (!cycle)
+ {
+ if (!expr)
+ return;
+ else if (lastExpr && lastExpr.indexOf(expr) != 0)
+ {
+ candidates = null;
+ }
+ else if (lastExpr && lastExpr.length >= expr.length)
+ {
+ candidates = null;
+ lastExpr = expr;
+ return;
+ }
+ }
+
+ lastExpr = expr;
+ lastOffset = offset;
+
+ var searchExpr;
+
+ // Check if the cursor is at the very right edge of the expression, or
+ // somewhere in the middle of it
+ if (expr && offset != parseStart+range.end+1)
+ {
+ if (cycle)
+ {
+ // We are in the middle of the expression, but we can
+ // complete by cycling to the next item in the values
+ // list after the expression
+ offset = range.start;
+ searchExpr = expr;
+ expr = "";
+ }
+ else
+ {
+ // We can't complete unless we are at the ridge edge
+ return;
+ }
+ }
+
+ var values = evaluator(preExpr, expr, postExpr, context);
+ if (!values)
+ return;
+
+ if (expr)
+ {
+ // Filter the list of values to those which begin with expr. We
+ // will then go on to complete the first value in the resulting list
+ candidates = [];
+
+ if (caseSensitive)
+ {
+ for (var i = 0; i < values.length; ++i)
+ {
+ var name = values[i];
+ if (name.indexOf && name.indexOf(expr) == 0)
+ candidates.push(name);
+ }
+ }
+ else
+ {
+ var lowerExpr = caseSensitive ? expr : expr.toLowerCase();
+ for (var i = 0; i < values.length; ++i)
+ {
+ var name = values[i];
+ if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0)
+ candidates.push(name);
+ }
+ }
+
+ lastIndex = reverse ? candidates.length-1 : 0;
+ }
+ else if (searchExpr)
+ {
+ var searchIndex = -1;
+
+ // Find the first instance of searchExpr in the values list. We
+ // will then complete the string that is found
+ if (caseSensitive)
+ {
+ searchIndex = values.indexOf(expr);
+ }
+ else
+ {
+ var lowerExpr = searchExpr.toLowerCase();
+ for (var i = 0; i < values.length; ++i)
+ {
+ var name = values[i];
+ if (name && name.toLowerCase().indexOf(lowerExpr) == 0)
+ {
+ searchIndex = i;
+ break;
+ }
+ }
+ }
+
+ // Nothing found, so there's nothing to complete to
+ if (searchIndex == -1)
+ return this.reset();
+
+ expr = searchExpr;
+ candidates = cloneArray(values);
+ lastIndex = searchIndex;
+ }
+ else
+ {
+ expr = "";
+ candidates = [];
+ for (var i = 0; i < values.length; ++i)
+ {
+ if (values[i].substr)
+ candidates.push(values[i]);
+ }
+ lastIndex = -1;
+ }
+ }
+
+ if (cycle)
+ {
+ expr = lastExpr;
+ lastIndex += reverse ? -1 : 1;
+ }
+
+ if (!candidates.length)
+ return;
+
+ if (lastIndex >= candidates.length)
+ lastIndex = 0;
+ else if (lastIndex < 0)
+ lastIndex = candidates.length-1;
+
+ var completion = candidates[lastIndex];
+ var preCompletion = expr.substr(0, offset-exprOffset);
+ var postCompletion = completion.substr(offset-exprOffset);
+
+ textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr;
+ var offsetEnd = preParsed.length + preExpr.length + completion.length;
+
+ // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange()
+ // is working well.
+ /*
+ if (textBox.setSelectionRange)
+ {
+ // we must select the range with a timeout, otherwise the text won't
+ // be properly selected (because after this function executes, the editor's
+ // input will be resized to fit the whole text)
+ setTimeout(function(){
+ if (selectMode)
+ textBox.setSelectionRange(offset, offsetEnd);
+ else
+ textBox.setSelectionRange(offsetEnd, offsetEnd);
+ },0);
+ }
+ /**/
+
+ // we must select the range with a timeout, otherwise the text won't
+ // be properly selected (because after this function executes, the editor's
+ // input will be resized to fit the whole text)
+ /*
+ setTimeout(function(){
+ if (selectMode)
+ setSelectionRange(textBox, offset, offsetEnd);
+ else
+ setSelectionRange(textBox, offsetEnd, offsetEnd);
+ },0);
+
+ return true;
+ /**/
+
+ // The editor text should be selected only after calling the editor.update()
+ // in Safari/Chrome, otherwise the text won't be selected. So, we're returning
+ // a function to be called later (in the proper time for all browsers).
+ //
+ // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid
+ // returning a closure. the complete() function seems to be called only twice in
+ // editor.js. See if this function is called anywhere else (like css.js for example).
+ return function(){
+ //console.log("autocomplete ", textBox, offset, offsetEnd);
+
+ if (selectMode)
+ setSelectionRange(textBox, offset, offsetEnd);
+ else
+ setSelectionRange(textBox, offsetEnd, offsetEnd);
+ };
+ /**/
+ };
+};
+
+// ************************************************************************************************
+// Local Helpers
+
+var getDefaultEditor = function getDefaultEditor(panel)
+{
+ if (!defaultEditor)
+ {
+ var doc = panel.document;
+ defaultEditor = new Firebug.InlineEditor(doc);
+ }
+
+ return defaultEditor;
+}
+
+/**
+ * An outsider is the first element matching the stepper element that
+ * is not an child of group. Elements tagged with insertBefore or insertAfter
+ * classes are also excluded from these results unless they are the sibling
+ * of group, relative to group's parent editGroup. This allows for the proper insertion
+ * rows when groups are nested.
+ */
+var getOutsider = function getOutsider(element, group, stepper)
+{
+ var parentGroup = getAncestorByClass(group.parentNode, "editGroup");
+ var next;
+ do
+ {
+ next = stepper(next || element);
+ }
+ while (isAncestor(next, group) || isGroupInsert(next, parentGroup));
+
+ return next;
+}
+
+var isGroupInsert = function isGroupInsert(next, group)
+{
+ return (!group || isAncestor(next, group))
+ && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter"));
+}
+
+var getNextOutsider = function getNextOutsider(element, group)
+{
+ return getOutsider(element, group, bind(getNextByClass, FBL, "editable"));
+}
+
+var getPreviousOutsider = function getPreviousOutsider(element, group)
+{
+ return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable"));
+}
+
+var getInlineParent = function getInlineParent(element)
+{
+ var lastInline = element;
+ for (; element; element = element.parentNode)
+ {
+ //var s = element.ownerDocument.defaultView.getComputedStyle(element, "");
+ var s = isIE ?
+ element.currentStyle :
+ element.ownerDocument.defaultView.getComputedStyle(element, "");
+
+ if (s.display != "inline")
+ return lastInline;
+ else
+ lastInline = element;
+ }
+ return null;
+}
+
+var insertTab = function insertTab()
+{
+ insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter);
+}
+
+// ************************************************************************************************
+
+Firebug.registerModule(Firebug.Editor);
+
+// ************************************************************************************************
+
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+if (Env.Options.disableXHRListener)
+ return;
+
+// ************************************************************************************************
+// XHRSpy
+
+var XHRSpy = function()
+{
+ this.requestHeaders = [];
+ this.responseHeaders = [];
+};
+
+XHRSpy.prototype =
+{
+ method: null,
+ url: null,
+ async: null,
+
+ xhrRequest: null,
+
+ href: null,
+
+ loaded: false,
+
+ logRow: null,
+
+ responseText: null,
+
+ requestHeaders: null,
+ responseHeaders: null,
+
+ sourceLink: null, // {href:"file.html", line: 22}
+
+ getURL: function()
+ {
+ return this.href;
+ }
+};
+
+// ************************************************************************************************
+// XMLHttpRequestWrapper
+
+var XMLHttpRequestWrapper = function(activeXObject)
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // XMLHttpRequestWrapper internal variables
+
+ var xhrRequest = typeof activeXObject != "undefined" ?
+ activeXObject :
+ new _XMLHttpRequest(),
+
+ spy = new XHRSpy(),
+
+ self = this,
+
+ reqType,
+ reqUrl,
+ reqStartTS;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // XMLHttpRequestWrapper internal methods
+
+ var updateSelfPropertiesIgnore = {
+ abort: 1,
+ channel: 1,
+ getAllResponseHeaders: 1,
+ getInterface: 1,
+ getResponseHeader: 1,
+ mozBackgroundRequest: 1,
+ multipart: 1,
+ onreadystatechange: 1,
+ open: 1,
+ send: 1,
+ setRequestHeader: 1
+ };
+
+ var updateSelfProperties = function()
+ {
+ if (supportsXHRIterator)
+ {
+ for (var propName in xhrRequest)
+ {
+ if (propName in updateSelfPropertiesIgnore)
+ continue;
+
+ try
+ {
+ var propValue = xhrRequest[propName];
+
+ if (propValue && !isFunction(propValue))
+ self[propName] = propValue;
+ }
+ catch(E)
+ {
+ //console.log(propName, E.message);
+ }
+ }
+ }
+ else
+ {
+ // will fail to read these xhrRequest properties if the request is not completed
+ if (xhrRequest.readyState == 4)
+ {
+ self.status = xhrRequest.status;
+ self.statusText = xhrRequest.statusText;
+ self.responseText = xhrRequest.responseText;
+ self.responseXML = xhrRequest.responseXML;
+ }
+ }
+ };
+
+ var updateXHRPropertiesIgnore = {
+ channel: 1,
+ onreadystatechange: 1,
+ readyState: 1,
+ responseBody: 1,
+ responseText: 1,
+ responseXML: 1,
+ status: 1,
+ statusText: 1,
+ upload: 1
+ };
+
+ var updateXHRProperties = function()
+ {
+ for (var propName in self)
+ {
+ if (propName in updateXHRPropertiesIgnore)
+ continue;
+
+ try
+ {
+ var propValue = self[propName];
+
+ if (propValue && !xhrRequest[propName])
+ {
+ xhrRequest[propName] = propValue;
+ }
+ }
+ catch(E)
+ {
+ //console.log(propName, E.message);
+ }
+ }
+ };
+
+ var logXHR = function()
+ {
+ var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR);
+
+ if (row)
+ {
+ setClass(row, "loading");
+ spy.logRow = row;
+ }
+ };
+
+ var finishXHR = function()
+ {
+ var duration = new Date().getTime() - reqStartTS;
+ var success = xhrRequest.status == 200;
+
+ var responseHeadersText = xhrRequest.getAllResponseHeaders();
+ var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : [];
+ var reHeader = /^(\S+):\s*(.*)/;
+
+ for (var i=0, l=responses.length; i<l; i++)
+ {
+ var text = responses[i];
+ var match = text.match(reHeader);
+
+ if (match)
+ {
+ var name = match[1];
+ var value = match[2];
+
+ // update the spy mimeType property so we can detect when to show
+ // custom response viewers (such as HTML, XML or JSON viewer)
+ if (name == "Content-Type")
+ spy.mimeType = value;
+
+ /*
+ if (name == "Last Modified")
+ {
+ if (!spy.cacheEntry)
+ spy.cacheEntry = [];
+
+ spy.cacheEntry.push({
+ name: [name],
+ value: [value]
+ });
+ }
+ /**/
+
+ spy.responseHeaders.push({
+ name: [name],
+ value: [value]
+ });
+ }
+ }
+
+ with({
+ row: spy.logRow,
+ status: xhrRequest.status == 0 ?
+ // if xhrRequest.status == 0 then accessing xhrRequest.statusText
+ // will cause an error, so we must handle this case (Issue 3504)
+ "" : xhrRequest.status + " " + xhrRequest.statusText,
+ time: duration,
+ success: success
+ })
+ {
+ setTimeout(function(){
+
+ spy.responseText = xhrRequest.responseText;
+
+ // update row information to avoid "ethernal spinning gif" bug in IE
+ row = row || spy.logRow;
+
+ // if chrome document is not loaded, there will be no row yet, so just ignore
+ if (!row) return;
+
+ // update the XHR representation data
+ handleRequestStatus(success, status, time);
+
+ },200);
+ }
+
+ spy.loaded = true;
+ /*
+ // commented because they are being updated by the updateSelfProperties() function
+ self.status = xhrRequest.status;
+ self.statusText = xhrRequest.statusText;
+ self.responseText = xhrRequest.responseText;
+ self.responseXML = xhrRequest.responseXML;
+ /**/
+ updateSelfProperties();
+ };
+
+ var handleStateChange = function()
+ {
+ //Firebug.Console.log(["onreadystatechange", xhrRequest.readyState, xhrRequest.readyState == 4 && xhrRequest.status]);
+
+ self.readyState = xhrRequest.readyState;
+
+ if (xhrRequest.readyState == 4)
+ {
+ finishXHR();
+
+ xhrRequest.onreadystatechange = function(){};
+ }
+
+ //Firebug.Console.log(spy.url + ": " + xhrRequest.readyState);
+
+ self.onreadystatechange();
+ };
+
+ // update the XHR representation data
+ var handleRequestStatus = function(success, status, time)
+ {
+ var row = spy.logRow;
+ FBL.removeClass(row, "loading");
+
+ if (!success)
+ FBL.setClass(row, "error");
+
+ var item = FBL.$$(".spyStatus", row)[0];
+ item.innerHTML = status;
+
+ if (time)
+ {
+ var item = FBL.$$(".spyTime", row)[0];
+ item.innerHTML = time + "ms";
+ }
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // XMLHttpRequestWrapper public properties and handlers
+
+ this.readyState = 0;
+
+ this.onreadystatechange = function(){};
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // XMLHttpRequestWrapper public methods
+
+ this.open = function(method, url, async, user, password)
+ {
+ //Firebug.Console.log("xhrRequest open");
+
+ updateSelfProperties();
+
+ if (spy.loaded)
+ spy = new XHRSpy();
+
+ spy.method = method;
+ spy.url = url;
+ spy.async = async;
+ spy.href = url;
+ spy.xhrRequest = xhrRequest;
+ spy.urlParams = parseURLParamsArray(url);
+
+ try
+ {
+ // xhrRequest.open.apply may not be available in IE
+ if (supportsApply)
+ xhrRequest.open.apply(xhrRequest, arguments);
+ else
+ xhrRequest.open(method, url, async, user, password);
+ }
+ catch(e)
+ {
+ }
+
+ xhrRequest.onreadystatechange = handleStateChange;
+
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ this.send = function(data)
+ {
+ //Firebug.Console.log("xhrRequest send");
+ spy.data = data;
+
+ reqStartTS = new Date().getTime();
+
+ updateXHRProperties();
+
+ try
+ {
+ xhrRequest.send(data);
+ }
+ catch(e)
+ {
+ // TODO: xxxpedro XHR throws or not?
+ //throw e;
+ }
+ finally
+ {
+ logXHR();
+
+ if (!spy.async)
+ {
+ self.readyState = xhrRequest.readyState;
+
+ // sometimes an error happens when calling finishXHR()
+ // Issue 3422: Firebug Lite breaks Google Instant Search
+ try
+ {
+ finishXHR();
+ }
+ catch(E)
+ {
+ }
+ }
+ }
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ this.setRequestHeader = function(header, value)
+ {
+ spy.requestHeaders.push({name: [header], value: [value]});
+ return xhrRequest.setRequestHeader(header, value);
+ };
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ this.abort = function()
+ {
+ xhrRequest.abort();
+ updateSelfProperties();
+ handleRequestStatus(false, "Aborted");
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ this.getResponseHeader = function(header)
+ {
+ return xhrRequest.getResponseHeader(header);
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ this.getAllResponseHeaders = function()
+ {
+ return xhrRequest.getAllResponseHeaders();
+ };
+
+ /**/
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Clone XHR object
+
+ // xhrRequest.open.apply not available in IE and will throw an error in
+ // IE6 by simply reading xhrRequest.open so we must sniff it
+ var supportsApply = !isIE6 &&
+ xhrRequest &&
+ xhrRequest.open &&
+ typeof xhrRequest.open.apply != "undefined";
+
+ var numberOfXHRProperties = 0;
+ for (var propName in xhrRequest)
+ {
+ numberOfXHRProperties++;
+
+ if (propName in updateSelfPropertiesIgnore)
+ continue;
+
+ try
+ {
+ var propValue = xhrRequest[propName];
+
+ if (isFunction(propValue))
+ {
+ if (typeof self[propName] == "undefined")
+ {
+ this[propName] = (function(name, xhr){
+
+ return supportsApply ?
+ // if the browser supports apply
+ function()
+ {
+ return xhr[name].apply(xhr, arguments);
+ }
+ :
+ function(a,b,c,d,e)
+ {
+ return xhr[name](a,b,c,d,e);
+ };
+
+ })(propName, xhrRequest);
+ }
+ }
+ else
+ this[propName] = propValue;
+ }
+ catch(E)
+ {
+ //console.log(propName, E.message);
+ }
+ }
+
+ // IE6 does not support for (var prop in XHR)
+ var supportsXHRIterator = numberOfXHRProperties > 0;
+
+ /**/
+
+ return this;
+};
+
+// ************************************************************************************************
+// ActiveXObject Wrapper (IE6 only)
+
+var _ActiveXObject;
+var isIE6 = /msie 6/i.test(navigator.appVersion);
+
+if (isIE6)
+{
+ _ActiveXObject = window.ActiveXObject;
+
+ var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP ";
+
+ window.ActiveXObject = function(name)
+ {
+ var error = null;
+
+ try
+ {
+ var activeXObject = new _ActiveXObject(name);
+ }
+ catch(e)
+ {
+ error = e;
+ }
+ finally
+ {
+ if (!error)
+ {
+ if (xhrObjects.indexOf(" " + name + " ") != -1)
+ return new XMLHttpRequestWrapper(activeXObject);
+ else
+ return activeXObject;
+ }
+ else
+ throw error.message;
+ }
+ };
+}
+
+// ************************************************************************************************
+
+// Register the XMLHttpRequestWrapper for non-IE6 browsers
+if (!isIE6)
+{
+ var _XMLHttpRequest = XMLHttpRequest;
+ window.XMLHttpRequest = function()
+ {
+ return new XMLHttpRequestWrapper();
+ };
+}
+
+//************************************************************************************************
+
+FBL.getNativeXHRObject = function()
+{
+ var xhrObj = false;
+ try
+ {
+ xhrObj = new _XMLHttpRequest();
+ }
+ catch(e)
+ {
+ var progid = [
+ "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0",
+ "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"
+ ];
+
+ for ( var i=0; i < progid.length; ++i ) {
+ try
+ {
+ xhrObj = new _ActiveXObject(progid[i]);
+ }
+ catch(e)
+ {
+ continue;
+ }
+ break;
+ }
+ }
+ finally
+ {
+ return xhrObj;
+ }
+};
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var reIgnore = /about:|javascript:|resource:|chrome:|jar:/;
+var layoutInterval = 300;
+var indentWidth = 18;
+
+var cacheSession = null;
+var contexts = new Array();
+var panelName = "net";
+var maxQueueRequests = 500;
+//var panelBar1 = $("fbPanelBar1"); // chrome not available at startup
+var activeRequests = [];
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var mimeExtensionMap =
+{
+ "txt": "text/plain",
+ "html": "text/html",
+ "htm": "text/html",
+ "xhtml": "text/html",
+ "xml": "text/xml",
+ "css": "text/css",
+ "js": "application/x-javascript",
+ "jss": "application/x-javascript",
+ "jpg": "image/jpg",
+ "jpeg": "image/jpeg",
+ "gif": "image/gif",
+ "png": "image/png",
+ "bmp": "image/bmp",
+ "swf": "application/x-shockwave-flash",
+ "flv": "video/x-flv"
+};
+
+var fileCategories =
+{
+ "undefined": 1,
+ "html": 1,
+ "css": 1,
+ "js": 1,
+ "xhr": 1,
+ "image": 1,
+ "flash": 1,
+ "txt": 1,
+ "bin": 1
+};
+
+var textFileCategories =
+{
+ "txt": 1,
+ "html": 1,
+ "xhr": 1,
+ "css": 1,
+ "js": 1
+};
+
+var binaryFileCategories =
+{
+ "bin": 1,
+ "flash": 1
+};
+
+var mimeCategoryMap =
+{
+ "text/plain": "txt",
+ "application/octet-stream": "bin",
+ "text/html": "html",
+ "text/xml": "html",
+ "text/css": "css",
+ "application/x-javascript": "js",
+ "text/javascript": "js",
+ "application/javascript" : "js",
+ "image/jpeg": "image",
+ "image/jpg": "image",
+ "image/gif": "image",
+ "image/png": "image",
+ "image/bmp": "image",
+ "application/x-shockwave-flash": "flash",
+ "video/x-flv": "flash"
+};
+
+var binaryCategoryMap =
+{
+ "image": 1,
+ "flash" : 1
+};
+
+// ************************************************************************************************
+
+/**
+ * @module Represents a module object for the Net panel. This object is derived
+ * from <code>Firebug.ActivableModule</code> in order to support activation (enable/disable).
+ * This allows to avoid (performance) expensive features if the functionality is not necessary
+ * for the user.
+ */
+Firebug.NetMonitor = extend(Firebug.ActivableModule,
+{
+ dispatchName: "netMonitor",
+
+ clear: function(context)
+ {
+ // The user pressed a Clear button so, remove content of the panel...
+ var panel = context.getPanel(panelName, true);
+ if (panel)
+ panel.clear();
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Module
+
+ initialize: function()
+ {
+ return;
+
+ this.panelName = panelName;
+
+ Firebug.ActivableModule.initialize.apply(this, arguments);
+
+ if (Firebug.TraceModule)
+ Firebug.TraceModule.addListener(this.TraceListener);
+
+ // HTTP observer must be registered now (and not in monitorContext, since if a
+ // page is opened in a new tab the top document request would be missed otherwise.
+ NetHttpObserver.registerObserver();
+ NetHttpActivityObserver.registerObserver();
+
+ Firebug.Debugger.addListener(this.DebuggerListener);
+ },
+
+ shutdown: function()
+ {
+ return;
+
+ prefs.removeObserver(Firebug.prefDomain, this, false);
+ if (Firebug.TraceModule)
+ Firebug.TraceModule.removeListener(this.TraceListener);
+
+ NetHttpObserver.unregisterObserver();
+ NetHttpActivityObserver.unregisterObserver();
+
+ Firebug.Debugger.removeListener(this.DebuggerListener);
+ }
+});
+
+
+/**
+ * @domplate Represents a template that is used to reneder detailed info about a request.
+ * This template is rendered when a request is expanded.
+ */
+Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(),
+{
+ tag:
+ DIV({"class": "netInfoBody", _repObject: "$file"},
+ TAG("$infoTabs", {file: "$file"}),
+ TAG("$infoBodies", {file: "$file"})
+ ),
+
+ infoTabs:
+ DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"},
+ A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Params",
+ $collapsed: "$file|hideParams"},
+ $STR("URLParameters")
+ ),
+ A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Headers"},
+ $STR("Headers")
+ ),
+ A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Post",
+ $collapsed: "$file|hidePost"},
+ $STR("Post")
+ ),
+ A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Put",
+ $collapsed: "$file|hidePut"},
+ $STR("Put")
+ ),
+ A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Response",
+ $collapsed: "$file|hideResponse"},
+ $STR("Response")
+ ),
+ A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Cache",
+ $collapsed: "$file|hideCache"},
+ $STR("Cache")
+ ),
+ A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
+ view: "Html",
+ $collapsed: "$file|hideHtml"},
+ $STR("HTML")
+ )
+ ),
+
+ infoBodies:
+ DIV({"class": "netInfoBodies outerFocusRow"},
+ TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel",
+ cellpadding: 0, cellspacing: 0}, TBODY()),
+ DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}),
+ DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}),
+ DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}),
+ PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}),
+ DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"},
+ TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ TBODY({"role": "list", "aria-label": $STR("Cache")})
+ )
+ ),
+ DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"},
+ IFRAME({"class": "netInfoHtmlPreview", "role": "document"})
+ )
+ ),
+
+ headerDataTag:
+ FOR("param", "$headers",
+ TR({"role": "listitem"},
+ TD({"class": "netInfoParamName", "role": "presentation"},
+ TAG("$param|getNameTag", {param: "$param"})
+ ),
+ TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"},
+ FOR("line", "$param|getParamValueIterator",
+ CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line")
+ )
+ )
+ )
+ ),
+
+ customTab:
+ A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"},
+ "$tabTitle"
+ ),
+
+ customBody:
+ DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ nameTag:
+ SPAN("$param|getParamName"),
+
+ nameWithTooltipTag:
+ SPAN({title: "$param.name"}, "$param|getParamName"),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getNameTag: function(param)
+ {
+ return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag;
+ },
+
+ getParamName: function(param)
+ {
+ var limit = 25;
+ var name = param.name;
+ if (name.length > limit)
+ name = name.substr(0, limit) + "...";
+ return name;
+ },
+
+ getParamTitle: function(param)
+ {
+ var limit = 25;
+ var name = param.name;
+ if (name.length > limit)
+ return name;
+ return "";
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ hideParams: function(file)
+ {
+ return !file.urlParams || !file.urlParams.length;
+ },
+
+ hidePost: function(file)
+ {
+ return file.method.toUpperCase() != "POST";
+ },
+
+ hidePut: function(file)
+ {
+ return file.method.toUpperCase() != "PUT";
+ },
+
+ hideResponse: function(file)
+ {
+ return false;
+ //return file.category in binaryFileCategories;
+ },
+
+ hideCache: function(file)
+ {
+ return true;
+ //xxxHonza: I don't see any reason why not to display the cache also info for images.
+ return !file.cacheEntry; // || file.category=="image";
+ },
+
+ hideHtml: function(file)
+ {
+ return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml");
+ },
+
+ onClickTab: function(event)
+ {
+ this.selectTab(event.currentTarget || event.srcElement);
+ },
+
+ getParamValueIterator: function(param)
+ {
+ // TODO: xxxpedro console2
+ return param.value;
+
+ // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210).
+ // This is why the second parameter is true.
+ // The CODE (with style white-space:pre) element preserves whitespaces so they are
+ // displayed the same, as they come from the server (1194).
+ // In case of a long header values of post parameters the value must be wrapped (2105).
+ return wrapText(param.value, true);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ appendTab: function(netInfoBox, tabId, tabTitle)
+ {
+ // Create new tab and body.
+ var args = {tabId: tabId, tabTitle: tabTitle};
+ ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0));
+ ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0));
+ this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]);
+ this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]);
+ },
+
+ selectTabByName: function(netInfoBox, tabName)
+ {
+ var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab");
+ if (tab)
+ this.selectTab(tab);
+ },
+
+ selectTab: function(tab)
+ {
+ var view = tab.getAttribute("view");
+
+ var netInfoBox = getAncestorByClass(tab, "netInfoBody");
+
+ var selectedTab = netInfoBox.selectedTab;
+
+ if (selectedTab)
+ {
+ //netInfoBox.selectedText.removeAttribute("selected");
+ removeClass(netInfoBox.selectedText, "netInfoTextSelected");
+
+ removeClass(selectedTab, "netInfoTabSelected");
+ //selectedTab.removeAttribute("selected");
+ selectedTab.setAttribute("aria-selected", "false");
+ }
+
+ var textBodyName = "netInfo" + view + "Text";
+
+ selectedTab = netInfoBox.selectedTab = tab;
+
+ netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0];
+ //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0);
+
+ //netInfoBox.selectedText.setAttribute("selected", "true");
+ setClass(netInfoBox.selectedText, "netInfoTextSelected");
+
+ setClass(selectedTab, "netInfoTabSelected");
+ selectedTab.setAttribute("selected", "true");
+ selectedTab.setAttribute("aria-selected", "true");
+
+ var file = Firebug.getRepObject(netInfoBox);
+
+ //var context = Firebug.getElementPanel(netInfoBox).context;
+ var context = Firebug.chrome;
+
+ this.updateInfo(netInfoBox, file, context);
+ },
+
+ updateInfo: function(netInfoBox, file, context)
+ {
+ if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.updateInfo; file", file);
+
+ if (!netInfoBox)
+ {
+ if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS)
+ FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file);
+ return;
+ }
+
+ var tab = netInfoBox.selectedTab;
+
+ if (hasClass(tab, "netInfoParamsTab"))
+ {
+ if (file.urlParams && !netInfoBox.urlParamsPresented)
+ {
+ netInfoBox.urlParamsPresented = true;
+ this.insertHeaderRows(netInfoBox, file.urlParams, "Params");
+ }
+ }
+
+ else if (hasClass(tab, "netInfoHeadersTab"))
+ {
+ var headersText = $$(".netInfoHeadersText", netInfoBox)[0];
+ //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0);
+
+ if (file.responseHeaders && !netInfoBox.responseHeadersPresented)
+ {
+ netInfoBox.responseHeadersPresented = true;
+ NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders");
+ }
+
+ if (file.requestHeaders && !netInfoBox.requestHeadersPresented)
+ {
+ netInfoBox.requestHeadersPresented = true;
+ NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders");
+ }
+ }
+
+ else if (hasClass(tab, "netInfoPostTab"))
+ {
+ if (!netInfoBox.postPresented)
+ {
+ netInfoBox.postPresented = true;
+ //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0);
+ var postText = $$(".netInfoPostText", netInfoBox)[0];
+ NetInfoPostData.render(context, postText, file);
+ }
+ }
+
+ else if (hasClass(tab, "netInfoPutTab"))
+ {
+ if (!netInfoBox.putPresented)
+ {
+ netInfoBox.putPresented = true;
+ //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0);
+ var putText = $$(".netInfoPutText", netInfoBox)[0];
+ NetInfoPostData.render(context, putText, file);
+ }
+ }
+
+ else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented)
+ {
+ ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0);
+ var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0];
+ if (file.category == "image")
+ {
+ netInfoBox.responsePresented = true;
+
+ var responseImage = netInfoBox.ownerDocument.createElement("img");
+ responseImage.src = file.href;
+
+ clearNode(responseTextBox);
+ responseTextBox.appendChild(responseImage, responseTextBox);
+ }
+ else ///if (!(binaryCategoryMap.hasOwnProperty(file.category)))
+ {
+ this.setResponseText(file, netInfoBox, responseTextBox, context);
+ }
+ }
+
+ else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented)
+ {
+ var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0);
+ if (file.cacheEntry) {
+ netInfoBox.cachePresented = true;
+ this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache");
+ }
+ }
+
+ else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented)
+ {
+ netInfoBox.htmlPresented = true;
+
+ var text = Utils.getResponseText(file, context);
+
+ ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0);
+ var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0];
+
+ ///iframe.contentWindow.document.body.innerHTML = text;
+
+ // TODO: xxxpedro net - remove scripts
+ var reScript = /<script(.|\s)*?\/script>/gi;
+
+ text = text.replace(reScript, "");
+
+ iframe.contentWindow.document.write(text);
+ iframe.contentWindow.document.close();
+ }
+
+ // Notify listeners about update so, content of custom tabs can be updated.
+ dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]);
+ },
+
+ setResponseText: function(file, netInfoBox, responseTextBox, context)
+ {
+ //**********************************************
+ //**********************************************
+ //**********************************************
+ netInfoBox.responsePresented = true;
+ // line breaks somehow are different in IE
+ // make this only once in the initialization? we don't have net panels and modules yet.
+ if (isIE)
+ responseTextBox.style.whiteSpace = "nowrap";
+
+ responseTextBox[
+ typeof responseTextBox.textContent != "undefined" ?
+ "textContent" :
+ "innerText"
+ ] = file.responseText;
+
+ return;
+ //**********************************************
+ //**********************************************
+ //**********************************************
+
+ // Get response text and make sure it doesn't exceed the max limit.
+ var text = Utils.getResponseText(file, context);
+ var limit = Firebug.netDisplayedResponseLimit + 15;
+ var limitReached = text ? (text.length > limit) : false;
+ if (limitReached)
+ text = text.substr(0, limit) + "...";
+
+ // Insert the response into the UI.
+ if (text)
+ insertWrappedText(text, responseTextBox);
+ else
+ insertWrappedText("", responseTextBox);
+
+ // Append a message informing the user that the response isn't fully displayed.
+ if (limitReached)
+ {
+ var object = {
+ text: $STR("net.responseSizeLimitMessage"),
+ onClickLink: function() {
+ var panel = context.getPanel("net", true);
+ panel.openResponseInTab(file);
+ }
+ };
+ Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox);
+ }
+
+ netInfoBox.responsePresented = true;
+
+ if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.setResponseText; response text updated");
+ },
+
+ insertHeaderRows: function(netInfoBox, headers, tableName, rowName)
+ {
+ if (!headers.length)
+ return;
+
+ var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0];
+ //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0);
+ var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body");
+ if (!tbody)
+ tbody = headersTable.firstChild;
+ var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title");
+
+ this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody);
+ removeClass(titleRow, "collapsed");
+ }
+});
+
+var NetInfoBody = Firebug.NetMonitor.NetInfoBody;
+
+// ************************************************************************************************
+
+/**
+ * @domplate Used within the Net panel to display raw source of request and response headers
+ * as well as pretty-formatted summary of these headers.
+ */
+Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(),
+{
+ tag:
+ DIV({"class": "netInfoHeadersTable", "role": "tabpanel"},
+ DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"},
+ SPAN($STR("ResponseHeaders")),
+ SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource",
+ _sourceDisplayed: false, _rowName: "ResponseHeaders"},
+ $STR("net.headers.view source")
+ )
+ ),
+ TABLE({cellpadding: 0, cellspacing: 0},
+ TBODY({"class": "netInfoResponseHeadersBody", "role": "list",
+ "aria-label": $STR("ResponseHeaders")})
+ ),
+ DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"},
+ SPAN($STR("RequestHeaders")),
+ SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource",
+ _sourceDisplayed: false, _rowName: "RequestHeaders"},
+ $STR("net.headers.view source")
+ )
+ ),
+ TABLE({cellpadding: 0, cellspacing: 0},
+ TBODY({"class": "netInfoRequestHeadersBody", "role": "list",
+ "aria-label": $STR("RequestHeaders")})
+ )
+ ),
+
+ sourceTag:
+ TR({"role": "presentation"},
+ TD({colspan: 2, "role": "presentation"},
+ PRE({"class": "source"})
+ )
+ ),
+
+ onViewSource: function(event)
+ {
+ var target = event.target;
+ var requestHeaders = (target.rowName == "RequestHeaders");
+
+ var netInfoBox = getAncestorByClass(target, "netInfoBody");
+ var file = netInfoBox.repObject;
+
+ if (target.sourceDisplayed)
+ {
+ var headers = requestHeaders ? file.requestHeaders : file.responseHeaders;
+ this.insertHeaderRows(netInfoBox, headers, target.rowName);
+ target.innerHTML = $STR("net.headers.view source");
+ }
+ else
+ {
+ var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText;
+ this.insertSource(netInfoBox, source, target.rowName);
+ target.innerHTML = $STR("net.headers.pretty print");
+ }
+
+ target.sourceDisplayed = !target.sourceDisplayed;
+
+ cancelEvent(event);
+ },
+
+ insertSource: function(netInfoBox, source, rowName)
+ {
+ // This breaks copy to clipboard.
+ //if (source)
+ // source = source.replace(/\r\n/gm, "<span style='color:lightgray'>\\r\\n</span>\r\n");
+
+ ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0);
+ var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0];
+ var node = this.sourceTag.replace({}, tbody);
+ ///var sourceNode = node.getElementsByClassName("source").item(0);
+ var sourceNode = $$(".source", node)[0];
+ sourceNode.innerHTML = source;
+ },
+
+ insertHeaderRows: function(netInfoBox, headers, rowName)
+ {
+ var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0];
+ var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0];
+
+ //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0);
+ //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0);
+
+ clearNode(tbody);
+
+ if (!headers.length)
+ return;
+
+ NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody);
+
+ var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title");
+ removeClass(titleRow, "collapsed");
+ },
+
+ init: function(parent)
+ {
+ var rootNode = this.tag.append({}, parent);
+
+ var netInfoBox = getAncestorByClass(parent, "netInfoBody");
+ var file = netInfoBox.repObject;
+
+ var viewSource;
+
+ viewSource = $$(".request", rootNode)[0];
+ //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0);
+ if (file.requestHeadersText)
+ removeClass(viewSource, "collapsed");
+
+ viewSource = $$(".response", rootNode)[0];
+ //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0);
+ if (file.responseHeadersText)
+ removeClass(viewSource, "collapsed");
+ },
+
+ renderHeaders: function(parent, headers, rowName)
+ {
+ if (!parent.firstChild)
+ this.init(parent);
+
+ this.insertHeaderRows(parent, headers, rowName);
+ }
+});
+
+var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders;
+
+// ************************************************************************************************
+
+/**
+ * @domplate Represents posted data within request info (the info, which is visible when
+ * a request entry is expanded. This template renders content of the Post tab.
+ */
+Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/
+{
+ // application/x-www-form-urlencoded
+ paramsTable:
+ TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")},
+ TR({"class": "netInfoPostParamsTitle", "role": "presentation"},
+ TD({colspan: 3, "role": "presentation"},
+ DIV({"class": "netInfoPostParams"},
+ $STR("net.label.Parameters"),
+ SPAN({"class": "netInfoPostContentType"},
+ "application/x-www-form-urlencoded"
+ )
+ )
+ )
+ )
+ )
+ ),
+
+ // multipart/form-data
+ partsTable:
+ TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ TBODY({"role": "list", "aria-label": $STR("net.label.Parts")},
+ TR({"class": "netInfoPostPartsTitle", "role": "presentation"},
+ TD({colspan: 2, "role":"presentation" },
+ DIV({"class": "netInfoPostParams"},
+ $STR("net.label.Parts"),
+ SPAN({"class": "netInfoPostContentType"},
+ "multipart/form-data"
+ )
+ )
+ )
+ )
+ )
+ ),
+
+ // application/json
+ jsonTable:
+ TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")},
+ TBODY({"role": "list", "aria-label": $STR("JSON")},
+ TR({"class": "netInfoPostJSONTitle", "role": "presentation"},
+ TD({"role": "presentation" },
+ DIV({"class": "netInfoPostParams"},
+ ///$STR("jsonviewer.tab.JSON")
+ $STR("JSON")
+ )
+ )
+ ),
+ TR(
+ TD({"class": "netInfoPostJSONBody"})
+ )
+ )
+ ),
+
+ // application/xml
+ xmlTable:
+ TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")},
+ TR({"class": "netInfoPostXMLTitle", "role": "presentation"},
+ TD({"role": "presentation" },
+ DIV({"class": "netInfoPostParams"},
+ $STR("xmlviewer.tab.XML")
+ )
+ )
+ ),
+ TR(
+ TD({"class": "netInfoPostXMLBody"})
+ )
+ )
+ ),
+
+ sourceTable:
+ TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
+ TBODY({"role": "list", "aria-label": $STR("net.label.Source")},
+ TR({"class": "netInfoPostSourceTitle", "role": "presentation"},
+ TD({colspan: 2, "role": "presentation"},
+ DIV({"class": "netInfoPostSource"},
+ $STR("net.label.Source")
+ )
+ )
+ )
+ )
+ ),
+
+ sourceBodyTag:
+ TR({"role": "presentation"},
+ TD({colspan: 2, "role": "presentation"},
+ FOR("line", "$param|getParamValueIterator",
+ CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line")
+ )
+ )
+ ),
+
+ getParamValueIterator: function(param)
+ {
+ return NetInfoBody.getParamValueIterator(param);
+ },
+
+ render: function(context, parentNode, file)
+ {
+ //debugger;
+ var spy = getAncestorByClass(parentNode, "spyHead");
+ var spyObject = spy.repObject;
+ var data = spyObject.data;
+
+ ///var contentType = Utils.findHeader(file.requestHeaders, "content-type");
+ var contentType = file.mimeType;
+
+ ///var text = Utils.getPostText(file, context, true);
+ ///if (text == undefined)
+ /// return;
+
+ ///if (Utils.isURLEncodedRequest(file, context))
+ // fake Utils.isURLEncodedRequest identification
+ if (contentType && contentType == "application/x-www-form-urlencoded" ||
+ data && data.indexOf("=") != -1)
+ {
+ ///var lines = text.split("\n");
+ ///var params = parseURLEncodedText(lines[lines.length-1]);
+ var params = parseURLEncodedTextArray(data);
+ if (params)
+ this.insertParameters(parentNode, params);
+ }
+
+ ///if (Utils.isMultiPartRequest(file, context))
+ ///{
+ /// var data = this.parseMultiPartText(file, context);
+ /// if (data)
+ /// this.insertParts(parentNode, data);
+ ///}
+
+ // moved to the top
+ ///var contentType = Utils.findHeader(file.requestHeaders, "content-type");
+
+ ///if (Firebug.JSONViewerModel.isJSON(contentType))
+ var jsonData = {
+ responseText: data
+ };
+
+ if (Firebug.JSONViewerModel.isJSON(contentType, data))
+ ///this.insertJSON(parentNode, file, context);
+ this.insertJSON(parentNode, jsonData, context);
+
+ ///if (Firebug.XMLViewerModel.isXML(contentType))
+ /// this.insertXML(parentNode, file, context);
+
+ ///var postText = Utils.getPostText(file, context);
+ ///postText = Utils.formatPostText(postText);
+ var postText = data;
+ if (postText)
+ this.insertSource(parentNode, postText);
+ },
+
+ insertParameters: function(parentNode, params)
+ {
+ if (!params || !params.length)
+ return;
+
+ var paramTable = this.paramsTable.append({object:{}}, parentNode);
+ var row = $$(".netInfoPostParamsTitle", paramTable)[0];
+ //var paramTable = this.paramsTable.append(null, parentNode);
+ //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0);
+
+ var tbody = paramTable.getElementsByTagName("tbody")[0];
+
+ NetInfoBody.headerDataTag.insertRows({headers: params}, row);
+ },
+
+ insertParts: function(parentNode, data)
+ {
+ if (!data.params || !data.params.length)
+ return;
+
+ var partsTable = this.partsTable.append({object:{}}, parentNode);
+ var row = $$(".netInfoPostPartsTitle", paramTable)[0];
+ //var partsTable = this.partsTable.append(null, parentNode);
+ //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0);
+
+ NetInfoBody.headerDataTag.insertRows({headers: data.params}, row);
+ },
+
+ insertJSON: function(parentNode, file, context)
+ {
+ ///var text = Utils.getPostText(file, context);
+ var text = file.responseText;
+ ///var data = parseJSONString(text, "http://" + file.request.originalURI.host);
+ var data = parseJSONString(text);
+ if (!data)
+ return;
+
+ ///var jsonTable = this.jsonTable.append(null, parentNode);
+ var jsonTable = this.jsonTable.append({}, parentNode);
+ ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0);
+ var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0];
+
+ if (!this.toggles)
+ this.toggles = {};
+
+ Firebug.DOMPanel.DirTable.tag.replace(
+ {object: data, toggles: this.toggles}, jsonBody);
+ },
+
+ insertXML: function(parentNode, file, context)
+ {
+ var text = Utils.getPostText(file, context);
+
+ var jsonTable = this.xmlTable.append(null, parentNode);
+ ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0);
+ var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0];
+
+ Firebug.XMLViewerModel.insertXML(jsonBody, text);
+ },
+
+ insertSource: function(parentNode, text)
+ {
+ var sourceTable = this.sourceTable.append({object:{}}, parentNode);
+ var row = $$(".netInfoPostSourceTitle", sourceTable)[0];
+ //var sourceTable = this.sourceTable.append(null, parentNode);
+ //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0);
+
+ var param = {value: [text]};
+ this.sourceBodyTag.insertRows({param: param}, row);
+ },
+
+ parseMultiPartText: function(file, context)
+ {
+ var text = Utils.getPostText(file, context);
+ if (text == undefined)
+ return null;
+
+ FBTrace.sysout("net.parseMultiPartText; boundary: ", text);
+
+ var boundary = text.match(/\s*boundary=\s*(.*)/)[1];
+
+ var divider = "\r\n\r\n";
+ var bodyStart = text.indexOf(divider);
+ var body = text.substr(bodyStart + divider.length);
+
+ var postData = {};
+ postData.mimeType = "multipart/form-data";
+ postData.params = [];
+
+ var parts = body.split("--" + boundary);
+ for (var i=0; i<parts.length; i++)
+ {
+ var part = parts[i].split(divider);
+ if (part.length != 2)
+ continue;
+
+ var m = part[0].match(/\s*name=\"(.*)\"(;|$)/);
+ postData.params.push({
+ name: (m && m.length > 1) ? m[1] : "",
+ value: trim(part[1])
+ });
+ }
+
+ return postData;
+ }
+});
+
+var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData;
+
+// ************************************************************************************************
+
+
+// TODO: xxxpedro net i18n
+var $STRP = function(a){return a;};
+
+Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep,
+{
+ collapsed: true,
+
+ tableTag:
+ DIV(
+ TABLE({width: "100%", cellpadding: 0, cellspacing: 0},
+ TBODY()
+ )
+ ),
+
+ limitTag:
+ TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"},
+ TD({"class": "netCol netLimitCol", colspan: 6},
+ TABLE({cellpadding: 0, cellspacing: 0},
+ TBODY(
+ TR(
+ TD(
+ SPAN({"class": "netLimitLabel"},
+ $STRP("plural.Limit_Exceeded", [0])
+ )
+ ),
+ TD({style: "width:100%"}),
+ TD(
+ BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle",
+ onclick: "$onPreferences"},
+ $STR("LimitPrefs")
+ )
+ ),
+ TD("&nbsp;")
+ )
+ )
+ )
+ )
+ ),
+
+ isCollapsed: function()
+ {
+ return this.collapsed;
+ },
+
+ onPreferences: function(event)
+ {
+ openNewTab("about:config");
+ },
+
+ updateCounter: function(row)
+ {
+ removeClass(row, "collapsed");
+
+ // Update info within the limit row.
+ var limitLabel = row.getElementsByClassName("netLimitLabel").item(0);
+ limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]);
+ },
+
+ createTable: function(parent, limitInfo)
+ {
+ var table = this.tableTag.replace({}, parent);
+ var row = this.createRow(table.firstChild.firstChild, limitInfo);
+ return [table, row];
+ },
+
+ createRow: function(parent, limitInfo)
+ {
+ var row = this.limitTag.insertRows(limitInfo, parent, this)[0];
+ row.limitInfo = limitInfo;
+ return row;
+ },
+
+ // nsIPrefObserver
+ observe: function(subject, topic, data)
+ {
+ // We're observing preferences only.
+ if (topic != "nsPref:changed")
+ return;
+
+ if (data.indexOf("net.logLimit") != -1)
+ this.updateMaxLimit();
+ },
+
+ updateMaxLimit: function()
+ {
+ var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit");
+ maxQueueRequests = value ? value : maxQueueRequests;
+ }
+});
+
+var NetLimit = Firebug.NetMonitor.NetLimit;
+
+// ************************************************************************************************
+
+Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep,
+{
+ tag:
+ DIV({"class": "netInfoResponseSizeLimit"},
+ SPAN("$object.beforeLink"),
+ A({"class": "objectLink", onclick: "$onClickLink"},
+ "$object.linkText"
+ ),
+ SPAN("$object.afterLink")
+ ),
+
+ reLink: /^(.*)<a>(.*)<\/a>(.*$)/,
+ append: function(obj, parent)
+ {
+ var m = obj.text.match(this.reLink);
+ return this.tag.append({onClickLink: obj.onClickLink,
+ object: {
+ beforeLink: m[1],
+ linkText: m[2],
+ afterLink: m[3]
+ }}, parent, this);
+ }
+});
+
+// ************************************************************************************************
+// ************************************************************************************************
+
+Firebug.NetMonitor.Utils =
+{
+ findHeader: function(headers, name)
+ {
+ if (!headers)
+ return null;
+
+ name = name.toLowerCase();
+ for (var i = 0; i < headers.length; ++i)
+ {
+ var headerName = headers[i].name.toLowerCase();
+ if (headerName == name)
+ return headers[i].value;
+ }
+ },
+
+ formatPostText: function(text)
+ {
+ if (text instanceof XMLDocument)
+ return getElementXML(text.documentElement);
+ else
+ return text;
+ },
+
+ getPostText: function(file, context, noLimit)
+ {
+ if (!file.postText)
+ {
+ file.postText = readPostTextFromRequest(file.request, context);
+
+ if (!file.postText && context)
+ file.postText = readPostTextFromPage(file.href, context);
+ }
+
+ if (!file.postText)
+ return file.postText;
+
+ var limit = Firebug.netDisplayedPostBodyLimit;
+ if (file.postText.length > limit && !noLimit)
+ {
+ return cropString(file.postText, limit,
+ "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n");
+ }
+
+ return file.postText;
+ },
+
+ getResponseText: function(file, context)
+ {
+ // The response can be also empty string so, check agains "undefined".
+ return (typeof(file.responseText) != "undefined")? file.responseText :
+ context.sourceCache.loadText(file.href, file.method, file);
+ },
+
+ isURLEncodedRequest: function(file, context)
+ {
+ var text = Utils.getPostText(file, context);
+ if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0)
+ return true;
+
+ // The header value doesn't have to be always exactly "application/x-www-form-urlencoded",
+ // there can be even charset specified. So, use indexOf rather than just "==".
+ var headerValue = Utils.findHeader(file.requestHeaders, "content-type");
+ if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0)
+ return true;
+
+ return false;
+ },
+
+ isMultiPartRequest: function(file, context)
+ {
+ var text = Utils.getPostText(file, context);
+ if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0)
+ return true;
+ return false;
+ },
+
+ getMimeType: function(mimeType, uri)
+ {
+ if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType)))
+ {
+ var ext = getFileExtension(uri);
+ if (!ext)
+ return mimeType;
+ else
+ {
+ var extMimeType = mimeExtensionMap[ext.toLowerCase()];
+ return extMimeType ? extMimeType : mimeType;
+ }
+ }
+ else
+ return mimeType;
+ },
+
+ getDateFromSeconds: function(s)
+ {
+ var d = new Date();
+ d.setTime(s*1000);
+ return d;
+ },
+
+ getHttpHeaders: function(request, file)
+ {
+ try
+ {
+ var http = QI(request, Ci.nsIHttpChannel);
+ file.status = request.responseStatus;
+
+ // xxxHonza: is there any problem to do this in requestedFile method?
+ file.method = http.requestMethod;
+ file.urlParams = parseURLParams(file.href);
+ file.mimeType = Utils.getMimeType(request.contentType, request.name);
+
+ if (!file.responseHeaders && Firebug.collectHttpHeaders)
+ {
+ var requestHeaders = [], responseHeaders = [];
+
+ http.visitRequestHeaders({
+ visitHeader: function(name, value)
+ {
+ requestHeaders.push({name: name, value: value});
+ }
+ });
+ http.visitResponseHeaders({
+ visitHeader: function(name, value)
+ {
+ responseHeaders.push({name: name, value: value});
+ }
+ });
+
+ file.requestHeaders = requestHeaders;
+ file.responseHeaders = responseHeaders;
+ }
+ }
+ catch (exc)
+ {
+ // An exception can be throwed e.g. when the request is aborted and
+ // request.responseStatus is accessed.
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc);
+ }
+ },
+
+ isXHR: function(request)
+ {
+ try
+ {
+ var callbacks = request.notificationCallbacks;
+ var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null;
+ if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request));
+
+ return (xhrRequest != null);
+ }
+ catch (exc)
+ {
+ }
+
+ return false;
+ },
+
+ getFileCategory: function(file)
+ {
+ if (file.category)
+ {
+ if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file);
+ return file.category;
+ }
+
+ if (file.isXHR)
+ {
+ if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file);
+ return file.category = "xhr";
+ }
+
+ if (!file.mimeType)
+ {
+ var ext = getFileExtension(file.href);
+ if (ext)
+ file.mimeType = mimeExtensionMap[ext.toLowerCase()];
+ }
+
+ /*if (FBTrace.DBG_NET)
+ FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] +
+ ", mimeType: " + file.mimeType + " for: " + file.href, file);*/
+
+ if (!file.mimeType)
+ return "";
+
+ // Solve cases when charset is also specified, eg "text/html; charset=UTF-8".
+ var mimeType = file.mimeType;
+ if (mimeType)
+ mimeType = mimeType.split(";")[0];
+
+ return (file.category = mimeCategoryMap[mimeType]);
+ }
+};
+
+var Utils = Firebug.NetMonitor.Utils;
+
+// ************************************************************************************************
+
+//Firebug.registerRep(Firebug.NetMonitor.NetRequestTable);
+//Firebug.registerActivableModule(Firebug.NetMonitor);
+//Firebug.registerPanel(NetPanel);
+
+Firebug.registerModule(Firebug.NetMonitor);
+//Firebug.registerRep(Firebug.NetMonitor.BreakpointRep);
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+//const Cc = Components.classes;
+//const Ci = Components.interfaces;
+
+// List of contexts with XHR spy attached.
+var contexts = [];
+
+// ************************************************************************************************
+// Spy Module
+
+/**
+ * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor
+ * XHR activity of the current page and create appropriate log into the Console panel.
+ * This feature can be controlled by an option <i>Show XMLHttpRequests</i> (from within the
+ * console panel).
+ *
+ * The module is responsible for attaching/detaching a HTTP Observers when Firebug is
+ * activated/deactivated for a site.
+ */
+Firebug.Spy = extend(Firebug.Module,
+/** @lends Firebug.Spy */
+{
+ dispatchName: "spy",
+
+ initialize: function()
+ {
+ if (Firebug.TraceModule)
+ Firebug.TraceModule.addListener(this.TraceListener);
+
+ Firebug.Module.initialize.apply(this, arguments);
+ },
+
+ shutdown: function()
+ {
+ Firebug.Module.shutdown.apply(this, arguments);
+
+ if (Firebug.TraceModule)
+ Firebug.TraceModule.removeListener(this.TraceListener);
+ },
+
+ initContext: function(context)
+ {
+ context.spies = [];
+
+ if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled())
+ this.attachObserver(context, context.window);
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName());
+ },
+
+ destroyContext: function(context)
+ {
+ // For any spies that are in progress, remove our listeners so that they don't leak
+ this.detachObserver(context, null);
+
+ if (FBTrace.DBG_SPY && context.spies.length)
+ FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies ("
+ + context.spies.length + ") " + context.getName());
+
+ delete context.spies;
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName());
+ },
+
+ watchWindow: function(context, win)
+ {
+ if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled())
+ this.attachObserver(context, win);
+ },
+
+ unwatchWindow: function(context, win)
+ {
+ try
+ {
+ // This make sure that the existing context is properly removed from "contexts" array.
+ this.detachObserver(context, win);
+ }
+ catch (ex)
+ {
+ // Get exceptions here sometimes, so let's just ignore them
+ // since the window is going away anyhow
+ ERROR(ex);
+ }
+ },
+
+ updateOption: function(name, value)
+ {
+ // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called,
+ // but somehow seems not correct
+ if (name == "showXMLHttpRequests")
+ {
+ var tach = value ? this.attachObserver : this.detachObserver;
+ for (var i = 0; i < TabWatcher.contexts.length; ++i)
+ {
+ var context = TabWatcher.contexts[i];
+ iterateWindows(context.window, function(win)
+ {
+ tach.apply(this, [context, win]);
+ });
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Attaching Spy to XHR requests.
+
+ /**
+ * Returns false if Spy should not be attached to XHRs executed by the specified window.
+ */
+ skipSpy: function(win)
+ {
+ if (!win)
+ return true;
+
+ // Don't attach spy to chrome.
+ var uri = safeGetWindowLocation(win);
+ if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0))
+ return true;
+ },
+
+ attachObserver: function(context, win)
+ {
+ if (Firebug.Spy.skipSpy(win))
+ return;
+
+ for (var i=0; i<contexts.length; ++i)
+ {
+ if ((contexts[i].context == context) && (contexts[i].win == win))
+ return;
+ }
+
+ // Register HTTP observers only once.
+ if (contexts.length == 0)
+ {
+ httpObserver.addObserver(SpyHttpObserver, "firebug-http-event", false);
+ SpyHttpActivityObserver.registerObserver();
+ }
+
+ contexts.push({context: context, win: win});
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.attachObserver (HTTP) " + contexts.length + " ", context.getName());
+ },
+
+ detachObserver: function(context, win)
+ {
+ for (var i=0; i<contexts.length; ++i)
+ {
+ if (contexts[i].context == context)
+ {
+ if (win && (contexts[i].win != win))
+ continue;
+
+ contexts.splice(i, 1);
+
+ // If no context is using spy, remvove the (only one) HTTP observer.
+ if (contexts.length == 0)
+ {
+ httpObserver.removeObserver(SpyHttpObserver, "firebug-http-event");
+ SpyHttpActivityObserver.unregisterObserver();
+ }
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.detachObserver (HTTP) " + contexts.length + " ",
+ context.getName());
+ return;
+ }
+ }
+ },
+
+ /**
+ * Return XHR object that is associated with specified request <i>nsIHttpChannel</i>.
+ * Returns null if the request doesn't represent XHR.
+ */
+ getXHR: function(request)
+ {
+ // Does also query-interface for nsIHttpChannel.
+ if (!(request instanceof Ci.nsIHttpChannel))
+ return null;
+
+ try
+ {
+ var callbacks = request.notificationCallbacks;
+ return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null);
+ }
+ catch (exc)
+ {
+ if (exc.name == "NS_NOINTERFACE")
+ {
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " +
+ safeGetRequestName(request));
+ }
+ }
+
+ return null;
+ }
+});
+
+
+
+
+
+// ************************************************************************************************
+
+/*
+function getSpyForXHR(request, xhrRequest, context, noCreate)
+{
+ var spy = null;
+
+ // Iterate all existing spy objects in this context and look for one that is
+ // already created for this request.
+ var length = context.spies.length;
+ for (var i=0; i<length; i++)
+ {
+ spy = context.spies[i];
+ if (spy.request == request)
+ return spy;
+ }
+
+ if (noCreate)
+ return null;
+
+ spy = new Firebug.Spy.XMLHttpRequestSpy(request, xhrRequest, context);
+ context.spies.push(spy);
+
+ var name = request.URI.asciiSpec;
+ var origName = request.originalURI.asciiSpec;
+
+ // Attach spy only to the original request. Notice that there can be more network requests
+ // made by the same XHR if redirects are involved.
+ if (name == origName)
+ spy.attach();
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.getSpyForXHR; New spy object created (" +
+ (name == origName ? "new XHR" : "redirected XHR") + ") for: " + name, spy);
+
+ return spy;
+}
+/**/
+
+// ************************************************************************************************
+
+/**
+ * @class This class represents a Spy object that is attached to XHR. This object
+ * registers various listeners into the XHR in order to monitor various events fired
+ * during the request process (onLoad, onAbort, etc.)
+ */
+/*
+Firebug.Spy.XMLHttpRequestSpy = function(request, xhrRequest, context)
+{
+ this.request = request;
+ this.xhrRequest = xhrRequest;
+ this.context = context;
+ this.responseText = "";
+
+ // For compatibility with the Net templates.
+ this.isXHR = true;
+
+ // Support for activity-observer
+ this.transactionStarted = false;
+ this.transactionClosed = false;
+};
+/**/
+
+//Firebug.Spy.XMLHttpRequestSpy.prototype =
+/** @lends Firebug.Spy.XMLHttpRequestSpy */
+/*
+{
+ attach: function()
+ {
+ var spy = this;
+ this.onReadyStateChange = function(event) { onHTTPSpyReadyStateChange(spy, event); };
+ this.onLoad = function() { onHTTPSpyLoad(spy); };
+ this.onError = function() { onHTTPSpyError(spy); };
+ this.onAbort = function() { onHTTPSpyAbort(spy); };
+
+ // xxxHonza: #502959 is still failing on Fx 3.5
+ // Use activity distributor to identify 3.6
+ if (SpyHttpActivityObserver.getActivityDistributor())
+ {
+ this.onreadystatechange = this.xhrRequest.onreadystatechange;
+ this.xhrRequest.onreadystatechange = this.onReadyStateChange;
+ }
+
+ this.xhrRequest.addEventListener("load", this.onLoad, false);
+ this.xhrRequest.addEventListener("error", this.onError, false);
+ this.xhrRequest.addEventListener("abort", this.onAbort, false);
+
+ // xxxHonza: should be removed from FB 3.6
+ if (!SpyHttpActivityObserver.getActivityDistributor())
+ this.context.sourceCache.addListener(this);
+ },
+
+ detach: function()
+ {
+ // Bubble out if already detached.
+ if (!this.onLoad)
+ return;
+
+ // If the activity distributor is available, let's detach it when the XHR
+ // transaction is closed. Since, in case of multipart XHRs the onLoad method
+ // (readyState == 4) can be called mutliple times.
+ // Keep in mind:
+ // 1) It can happen that that the TRANSACTION_CLOSE event comes before
+ // the onLoad (if the XHR is made as part of the page load) so, detach if
+ // it's already closed.
+ // 2) In case of immediate cache responses, the transaction doesn't have to
+ // be started at all (or the activity observer is no available in Firefox 3.5).
+ // So, also detach in this case.
+ if (this.transactionStarted && !this.transactionClosed)
+ return;
+
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.detach; " + this.href);
+
+ // Remove itself from the list of active spies.
+ remove(this.context.spies, this);
+
+ if (this.onreadystatechange)
+ this.xhrRequest.onreadystatechange = this.onreadystatechange;
+
+ try { this.xhrRequest.removeEventListener("load", this.onLoad, false); } catch (e) {}
+ try { this.xhrRequest.removeEventListener("error", this.onError, false); } catch (e) {}
+ try { this.xhrRequest.removeEventListener("abort", this.onAbort, false); } catch (e) {}
+
+ this.onreadystatechange = null;
+ this.onLoad = null;
+ this.onError = null;
+ this.onAbort = null;
+
+ // xxxHonza: shouuld be removed from FB 1.6
+ if (!SpyHttpActivityObserver.getActivityDistributor())
+ this.context.sourceCache.removeListener(this);
+ },
+
+ getURL: function()
+ {
+ return this.xhrRequest.channel ? this.xhrRequest.channel.name : this.href;
+ },
+
+ // Cache listener
+ onStopRequest: function(context, request, responseText)
+ {
+ if (!responseText)
+ return;
+
+ if (request == this.request)
+ this.responseText = responseText;
+ },
+};
+/**/
+// ************************************************************************************************
+/*
+function onHTTPSpyReadyStateChange(spy, event)
+{
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.onHTTPSpyReadyStateChange " + spy.xhrRequest.readyState +
+ " (multipart: " + spy.xhrRequest.multipart + ")");
+
+ // Remember just in case spy is detached (readyState == 4).
+ var originalHandler = spy.onreadystatechange;
+
+ // Force response text to be updated in the UI (in case the console entry
+ // has been already expanded and the response tab selected).
+ if (spy.logRow && spy.xhrRequest.readyState >= 3)
+ {
+ var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
+ if (netInfoBox)
+ {
+ netInfoBox.htmlPresented = false;
+ netInfoBox.responsePresented = false;
+ }
+ }
+
+ // If the request is loading update the end time.
+ if (spy.xhrRequest.readyState == 3)
+ {
+ spy.responseTime = spy.endTime - spy.sendTime;
+ updateTime(spy);
+ }
+
+ // Request loaded. Get all the info from the request now, just in case the
+ // XHR would be aborted in the original onReadyStateChange handler.
+ if (spy.xhrRequest.readyState == 4)
+ {
+ // Cumulate response so, multipart response content is properly displayed.
+ if (SpyHttpActivityObserver.getActivityDistributor())
+ spy.responseText += spy.xhrRequest.responseText;
+ else
+ {
+ // xxxHonza: remove from FB 1.6
+ if (!spy.responseText)
+ spy.responseText = spy.xhrRequest.responseText;
+ }
+
+ // The XHR is loaded now (used also by the activity observer).
+ spy.loaded = true;
+
+ // Update UI.
+ updateHttpSpyInfo(spy);
+
+ // Notify Net pane about a request beeing loaded.
+ // xxxHonza: I don't think this is necessary.
+ var netProgress = spy.context.netProgress;
+ if (netProgress)
+ netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]);
+
+ // Notify registered listeners about finish of the XHR.
+ dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]);
+ }
+
+ // Pass the event to the original page handler.
+ callPageHandler(spy, event, originalHandler);
+}
+
+function onHTTPSpyLoad(spy)
+{
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy);
+
+ // Detach must be done in onLoad (not in onreadystatechange) otherwise
+ // onAbort would not be handled.
+ spy.detach();
+
+ // xxxHonza: Still needed for Fx 3.5 (#502959)
+ if (!SpyHttpActivityObserver.getActivityDistributor())
+ onHTTPSpyReadyStateChange(spy, null);
+}
+
+function onHTTPSpyError(spy)
+{
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy);
+
+ spy.detach();
+ spy.loaded = true;
+
+ if (spy.logRow)
+ {
+ removeClass(spy.logRow, "loading");
+ setClass(spy.logRow, "error");
+ }
+}
+
+function onHTTPSpyAbort(spy)
+{
+ if (FBTrace.DBG_SPY)
+ FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy);
+
+ spy.detach();
+ spy.loaded = true;
+
+ if (spy.logRow)
+ {
+ removeClass(spy.logRow, "loading");
+ setClass(spy.logRow, "error");
+ }
+
+ spy.statusText = "Aborted";
+ updateLogRow(spy);
+
+ // Notify Net pane about a request beeing aborted.
+ // xxxHonza: the net panel shoud find out this itself.
+ var netProgress = spy.context.netProgress;
+ if (netProgress)
+ netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]);
+}
+/**/
+
+// ************************************************************************************************
+
+/**
+ * @domplate Represents a template for XHRs logged in the Console panel. The body of the
+ * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}.
+ */
+
+Firebug.Spy.XHR = domplate(Firebug.Rep,
+/** @lends Firebug.Spy.XHR */
+
+{
+ tag:
+ DIV({"class": "spyHead", _repObject: "$object"},
+ TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0,
+ "role": "listitem", "aria-expanded": "false"},
+ TBODY({"role": "presentation"},
+ TR({"class": "spyRow"},
+ TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"},
+ DIV({"class": "spyTitle"},
+ "$object|getCaption"
+ ),
+ DIV({"class": "spyFullTitle spyTitle"},
+ "$object|getFullUri"
+ )
+ ),
+ TD({"class": "spyCol"},
+ DIV({"class": "spyStatus"}, "$object|getStatus")
+ ),
+ TD({"class": "spyCol"},
+ SPAN({"class": "spyIcon"})
+ ),
+ TD({"class": "spyCol"},
+ SPAN({"class": "spyTime"})
+ ),
+ TD({"class": "spyCol"},
+ TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"})
+ )
+ )
+ )
+ )
+ ),
+
+ getCaption: function(spy)
+ {
+ return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100);
+ },
+
+ getFullUri: function(spy)
+ {
+ return spy.method.toUpperCase() + " " + spy.getURL();
+ },
+
+ getStatus: function(spy)
+ {
+ var text = "";
+ if (spy.statusCode)
+ text += spy.statusCode + " ";
+
+ if (spy.statusText)
+ return text += spy.statusText;
+
+ return text;
+ },
+
+ onToggleBody: function(event)
+ {
+ var target = event.currentTarget || event.srcElement;
+ var logRow = getAncestorByClass(target, "logRow-spy");
+
+ if (isLeftClick(event))
+ {
+ toggleClass(logRow, "opened");
+
+ var spy = getChildByClass(logRow, "spyHead").repObject;
+ var spyHeadTable = getAncestorByClass(target, "spyHeadTable");
+
+ if (hasClass(logRow, "opened"))
+ {
+ updateHttpSpyInfo(spy, logRow);
+ if (spyHeadTable)
+ spyHeadTable.setAttribute('aria-expanded', 'true');
+ }
+ else
+ {
+ //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
+ //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]);
+ //if (spyHeadTable)
+ // spyHeadTable.setAttribute('aria-expanded', 'false');
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ copyURL: function(spy)
+ {
+ copyToClipboard(spy.getURL());
+ },
+
+ copyParams: function(spy)
+ {
+ var text = spy.postText;
+ if (!text)
+ return;
+
+ var url = reEncodeURL(spy, text, true);
+ copyToClipboard(url);
+ },
+
+ copyResponse: function(spy)
+ {
+ copyToClipboard(spy.responseText);
+ },
+
+ openInTab: function(spy)
+ {
+ openNewTab(spy.getURL(), spy.postText);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ supportsObject: function(object)
+ {
+ // TODO: xxxpedro spy xhr
+ return false;
+
+ return object instanceof Firebug.Spy.XMLHttpRequestSpy;
+ },
+
+ browseObject: function(spy, context)
+ {
+ var url = spy.getURL();
+ openNewTab(url);
+ return true;
+ },
+
+ getRealObject: function(spy, context)
+ {
+ return spy.xhrRequest;
+ },
+
+ getContextMenuItems: function(spy)
+ {
+ var items = [
+ {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) }
+ ];
+
+ if (spy.postText)
+ {
+ items.push(
+ {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) }
+ );
+ }
+
+ items.push(
+ {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) },
+ "-",
+ {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) }
+ );
+
+ return items;
+ }
+});
+
+// ************************************************************************************************
+
+function updateTime(spy)
+{
+ var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0);
+ if (spy.responseTime)
+ timeBox.textContent = " " + formatTime(spy.responseTime);
+}
+
+function updateLogRow(spy)
+{
+ updateTime(spy);
+
+ var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0);
+ statusBox.textContent = Firebug.Spy.XHR.getStatus(spy);
+
+ removeClass(spy.logRow, "loading");
+ setClass(spy.logRow, "loaded");
+
+ try
+ {
+ var errorRange = Math.floor(spy.xhrRequest.status/100);
+ if (errorRange == 4 || errorRange == 5)
+ setClass(spy.logRow, "error");
+ }
+ catch (exc)
+ {
+ }
+}
+
+var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow)
+{
+ if (!spy.logRow && logRow)
+ spy.logRow = logRow;
+
+ if (!spy.logRow || !hasClass(spy.logRow, "opened"))
+ return;
+
+ if (!spy.params)
+ //spy.params = parseURLParams(spy.href+"");
+ spy.params = parseURLParams(spy.href+"");
+
+ if (!spy.requestHeaders)
+ spy.requestHeaders = getRequestHeaders(spy);
+
+ if (!spy.responseHeaders && spy.loaded)
+ spy.responseHeaders = getResponseHeaders(spy);
+
+ var template = Firebug.NetMonitor.NetInfoBody;
+ var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
+ if (!netInfoBox)
+ {
+ var head = getChildByClass(spy.logRow, "spyHead");
+ netInfoBox = template.tag.append({"file": spy}, head);
+ dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]);
+ template.selectTabByName(netInfoBox, "Response");
+ }
+ else
+ {
+ template.updateInfo(netInfoBox, spy, spy.context);
+ }
+};
+
+
+
+// ************************************************************************************************
+
+function getRequestHeaders(spy)
+{
+ var headers = [];
+
+ var channel = spy.xhrRequest.channel;
+ if (channel instanceof Ci.nsIHttpChannel)
+ {
+ channel.visitRequestHeaders({
+ visitHeader: function(name, value)
+ {
+ headers.push({name: name, value: value});
+ }
+ });
+ }
+
+ return headers;
+}
+
+function getResponseHeaders(spy)
+{
+ var headers = [];
+
+ try
+ {
+ var channel = spy.xhrRequest.channel;
+ if (channel instanceof Ci.nsIHttpChannel)
+ {
+ channel.visitResponseHeaders({
+ visitHeader: function(name, value)
+ {
+ headers.push({name: name, value: value});
+ }
+ });
+ }
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS)
+ FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " +
+ safeGetRequestName(spy.request), exc);
+ }
+
+ return headers;
+}
+
+// ************************************************************************************************
+// Registration
+
+Firebug.registerModule(Firebug.Spy);
+//Firebug.registerRep(Firebug.Spy.XHR);
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+
+// List of JSON content types.
+var contentTypes =
+{
+ // TODO: create issue: jsonViewer will not try to evaluate the contents of the requested file
+ // if the content-type is set to "text/plain"
+ //"text/plain": 1,
+ "text/javascript": 1,
+ "text/x-javascript": 1,
+ "text/json": 1,
+ "text/x-json": 1,
+ "application/json": 1,
+ "application/x-json": 1,
+ "application/javascript": 1,
+ "application/x-javascript": 1,
+ "application/json-rpc": 1
+};
+
+// ************************************************************************************************
+// Model implementation
+
+Firebug.JSONViewerModel = extend(Firebug.Module,
+{
+ dispatchName: "jsonViewer",
+ initialize: function()
+ {
+ Firebug.NetMonitor.NetInfoBody.addListener(this);
+
+ // Used by Firebug.DOMPanel.DirTable domplate.
+ this.toggles = {};
+ },
+
+ shutdown: function()
+ {
+ Firebug.NetMonitor.NetInfoBody.removeListener(this);
+ },
+
+ initTabBody: function(infoBox, file)
+ {
+ if (FBTrace.DBG_JSONVIEWER)
+ FBTrace.sysout("jsonviewer.initTabBody", infoBox);
+
+ // Let listeners to parse the JSON.
+ dispatch(this.fbListeners, "onParseJSON", [file]);
+
+ // The JSON is still no there, try to parse most common cases.
+ if (!file.jsonObject)
+ {
+ ///if (this.isJSON(safeGetContentType(file.request), file.responseText))
+ if (this.isJSON(file.mimeType, file.responseText))
+ file.jsonObject = this.parseJSON(file);
+ }
+
+ // The jsonObject is created so, the JSON tab can be displayed.
+ if (file.jsonObject && hasProperties(file.jsonObject))
+ {
+ Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON",
+ ///$STR("jsonviewer.tab.JSON"));
+ $STR("JSON"));
+
+ if (FBTrace.DBG_JSONVIEWER)
+ FBTrace.sysout("jsonviewer.initTabBody; JSON object available " +
+ (typeof(file.jsonObject) != "undefined"), file.jsonObject);
+ }
+ },
+
+ isJSON: function(contentType, data)
+ {
+ // Workaround for JSON responses without proper content type
+ // Let's consider all responses starting with "{" as JSON. In the worst
+ // case there will be an exception when parsing. This means that no-JSON
+ // responses (and post data) (with "{") can be parsed unnecessarily,
+ // which represents a little overhead, but this happens only if the request
+ // is actually expanded by the user in the UI (Net & Console panels).
+
+ ///var responseText = data ? trimLeft(data) : null;
+ ///if (responseText && responseText.indexOf("{") == 0)
+ /// return true;
+ var responseText = data ? trim(data) : null;
+ if (responseText && responseText.indexOf("{") == 0)
+ return true;
+
+ if (!contentType)
+ return false;
+
+ contentType = contentType.split(";")[0];
+ contentType = trim(contentType);
+ return contentTypes[contentType];
+ },
+
+ // Update listener for TabView
+ updateTabBody: function(infoBox, file, context)
+ {
+ var tab = infoBox.selectedTab;
+ ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0);
+ var tabBody = $$(".netInfoJSONText", infoBox)[0];
+ if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated)
+ return;
+
+ tabBody.updated = true;
+
+ if (file.jsonObject) {
+ Firebug.DOMPanel.DirTable.tag.replace(
+ {object: file.jsonObject, toggles: this.toggles}, tabBody);
+ }
+ },
+
+ parseJSON: function(file)
+ {
+ var jsonString = new String(file.responseText);
+ ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host);
+ return parseJSONString(jsonString);
+ }
+});
+
+// ************************************************************************************************
+// Registration
+
+Firebug.registerModule(Firebug.JSONViewerModel);
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+// List of XML related content types.
+var xmlContentTypes =
+[
+ "text/xml",
+ "application/xml",
+ "application/xhtml+xml",
+ "application/rss+xml",
+ "application/atom+xml",,
+ "application/vnd.mozilla.maybe.feed",
+ "application/rdf+xml",
+ "application/vnd.mozilla.xul+xml"
+];
+
+// ************************************************************************************************
+// Model implementation
+
+/**
+ * @module Implements viewer for XML based network responses. In order to create a new
+ * tab wihin network request detail, a listener is registered into
+ * <code>Firebug.NetMonitor.NetInfoBody</code> object.
+ */
+Firebug.XMLViewerModel = extend(Firebug.Module,
+{
+ dispatchName: "xmlViewer",
+
+ initialize: function()
+ {
+ ///Firebug.ActivableModule.initialize.apply(this, arguments);
+ Firebug.Module.initialize.apply(this, arguments);
+ Firebug.NetMonitor.NetInfoBody.addListener(this);
+ },
+
+ shutdown: function()
+ {
+ ///Firebug.ActivableModule.shutdown.apply(this, arguments);
+ Firebug.Module.shutdown.apply(this, arguments);
+ Firebug.NetMonitor.NetInfoBody.removeListener(this);
+ },
+
+ /**
+ * Check response's content-type and if it's a XML, create a new tab with XML preview.
+ */
+ initTabBody: function(infoBox, file)
+ {
+ if (FBTrace.DBG_XMLVIEWER)
+ FBTrace.sysout("xmlviewer.initTabBody", infoBox);
+
+ // If the response is XML let's display a pretty preview.
+ ///if (this.isXML(safeGetContentType(file.request)))
+ if (this.isXML(file.mimeType, file.responseText))
+ {
+ Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML",
+ ///$STR("xmlviewer.tab.XML"));
+ $STR("XML"));
+
+ if (FBTrace.DBG_XMLVIEWER)
+ FBTrace.sysout("xmlviewer.initTabBody; XML response available");
+ }
+ },
+
+ isXML: function(contentType)
+ {
+ if (!contentType)
+ return false;
+
+ // Look if the response is XML based.
+ for (var i=0; i<xmlContentTypes.length; i++)
+ {
+ if (contentType.indexOf(xmlContentTypes[i]) == 0)
+ return true;
+ }
+
+ return false;
+ },
+
+ /**
+ * Parse XML response and render pretty printed preview.
+ */
+ updateTabBody: function(infoBox, file, context)
+ {
+ var tab = infoBox.selectedTab;
+ ///var tabBody = infoBox.getElementsByClassName("netInfoXMLText").item(0);
+ var tabBody = $$(".netInfoXMLText", infoBox)[0];
+ if (!hasClass(tab, "netInfoXMLTab") || tabBody.updated)
+ return;
+
+ tabBody.updated = true;
+
+ this.insertXML(tabBody, Firebug.NetMonitor.Utils.getResponseText(file, context));
+ },
+
+ insertXML: function(parentNode, text)
+ {
+ var xmlText = text.replace(/^\s*<?.+?>\s*/, "");
+
+ var div = parentNode.ownerDocument.createElement("div");
+ div.innerHTML = xmlText;
+
+ var root = div.getElementsByTagName("*")[0];
+
+ /***
+ var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
+ var doc = parser.parseFromString(text, "text/xml");
+ var root = doc.documentElement;
+
+ // Error handling
+ var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
+ if (root.namespaceURI == nsURI && root.nodeName == "parsererror")
+ {
+ this.ParseError.tag.replace({error: {
+ message: root.firstChild.nodeValue,
+ source: root.lastChild.textContent
+ }}, parentNode);
+ return;
+ }
+ /**/
+
+ if (FBTrace.DBG_XMLVIEWER)
+ FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc);
+
+ // Override getHidden in these templates. The parsed XML documen is
+ // hidden, but we want to display it using 'visible' styling.
+ /*
+ var templates = [
+ Firebug.HTMLPanel.CompleteElement,
+ Firebug.HTMLPanel.Element,
+ Firebug.HTMLPanel.TextElement,
+ Firebug.HTMLPanel.EmptyElement,
+ Firebug.HTMLPanel.XEmptyElement,
+ ];
+
+ var originals = [];
+ for (var i=0; i<templates.length; i++)
+ {
+ originals[i] = templates[i].getHidden;
+ templates[i].getHidden = function() {
+ return "";
+ }
+ }
+ /**/
+
+ // Generate XML preview.
+ ///Firebug.HTMLPanel.CompleteElement.tag.replace({object: doc.documentElement}, parentNode);
+
+ // TODO: xxxpedro html3
+ ///Firebug.HTMLPanel.CompleteElement.tag.replace({object: root}, parentNode);
+ var html = [];
+ Firebug.Reps.appendNode(root, html);
+ parentNode.innerHTML = html.join("");
+
+
+ /*
+ for (var i=0; i<originals.length; i++)
+ templates[i].getHidden = originals[i];/**/
+ }
+});
+
+// ************************************************************************************************
+// Domplate
+
+/**
+ * @domplate Represents a template for displaying XML parser errors. Used by
+ * <code>Firebug.XMLViewerModel</code>.
+ */
+Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep,
+{
+ tag:
+ DIV({"class": "xmlInfoError"},
+ DIV({"class": "xmlInfoErrorMsg"}, "$error.message"),
+ PRE({"class": "xmlInfoErrorSource"}, "$error|getSource")
+ ),
+
+ getSource: function(error)
+ {
+ var parts = error.source.split("\n");
+ if (parts.length != 2)
+ return error.source;
+
+ var limit = 50;
+ var column = parts[1].length;
+ if (column >= limit) {
+ parts[0] = "..." + parts[0].substr(column - limit);
+ parts[1] = "..." + parts[1].substr(column - limit);
+ }
+
+ if (parts[0].length > 80)
+ parts[0] = parts[0].substr(0, 80) + "...";
+
+ return parts.join("\n");
+ }
+});
+
+// ************************************************************************************************
+// Registration
+
+Firebug.registerModule(Firebug.XMLViewerModel);
+
+}});
+
+
+/* See license.txt for terms of usage */
+
+// next-generation Console Panel (will override consoje.js)
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Constants
+
+/*
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const nsIPrefBranch2 = Ci.nsIPrefBranch2;
+const PrefService = Cc["@mozilla.org/preferences-service;1"];
+const prefs = PrefService.getService(nsIPrefBranch2);
+/**/
+/*
+
+// new offline message handler
+o = {x:1,y:2};
+
+r = Firebug.getRep(o);
+
+r.tag.tag.compile();
+
+outputs = [];
+html = r.tag.renderHTML({object:o}, outputs);
+
+
+// finish rendering the template (the DOM part)
+target = $("build");
+target.innerHTML = html;
+root = target.firstChild;
+
+domArgs = [root, r.tag.context, 0];
+domArgs.push.apply(domArgs, r.tag.domArgs);
+domArgs.push.apply(domArgs, outputs);
+r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs);
+
+
+ */
+var consoleQueue = [];
+var lastHighlightedObject;
+var FirebugContext = Env.browser;
+
+// ************************************************************************************************
+
+var maxQueueRequests = 500;
+
+// ************************************************************************************************
+
+Firebug.ConsoleBase =
+{
+ log: function(object, context, className, rep, noThrottle, sourceLink)
+ {
+ //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]);
+ return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle);
+ },
+
+ logFormatted: function(objects, context, className, noThrottle, sourceLink)
+ {
+ //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]);
+ return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle);
+ },
+
+ openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush)
+ {
+ return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle);
+ },
+
+ closeGroup: function(context, noThrottle)
+ {
+ return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true);
+ },
+
+ logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
+ {
+ // TODO: xxxpedro console console2
+ noThrottle = true; // xxxpedro forced because there is no TabContext yet
+
+ if (!context)
+ context = FirebugContext;
+
+ if (FBTrace.DBG_ERRORS && !context)
+ FBTrace.sysout("Console.logRow has no context, skipping objects", objects);
+
+ if (!context)
+ return;
+
+ if (noThrottle || !context)
+ {
+ var panel = this.getPanel(context);
+ if (panel)
+ {
+ var row = panel.append(appender, objects, className, rep, sourceLink, noRow);
+ var container = panel.panelNode;
+
+ // TODO: xxxpedro what is this? console console2
+ /*
+ var template = Firebug.NetMonitor.NetLimit;
+
+ while (container.childNodes.length > maxQueueRequests + 1)
+ {
+ clearDomplate(container.firstChild.nextSibling);
+ container.removeChild(container.firstChild.nextSibling);
+ panel.limit.limitInfo.totalCount++;
+ template.updateCounter(panel.limit);
+ }
+ dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]);
+ /**/
+ return row;
+ }
+ else
+ {
+ consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]);
+ }
+ }
+ else
+ {
+ if (!context.throttle)
+ {
+ //FBTrace.sysout("console.logRow has not context.throttle! ");
+ return;
+ }
+ var args = [appender, objects, context, className, rep, sourceLink, true, noRow];
+ context.throttle(this.logRow, this, args);
+ }
+ },
+
+ appendFormatted: function(args, row, context)
+ {
+ if (!context)
+ context = FirebugContext;
+
+ var panel = this.getPanel(context);
+ panel.appendFormatted(args, row);
+ },
+
+ clear: function(context)
+ {
+ if (!context)
+ //context = FirebugContext;
+ context = Firebug.context;
+
+ /*
+ if (context)
+ Firebug.Errors.clear(context);
+ /**/
+
+ var panel = this.getPanel(context, true);
+ if (panel)
+ {
+ panel.clear();
+ }
+ },
+
+ // Override to direct output to your panel
+ getPanel: function(context, noCreate)
+ {
+ //return context.getPanel("console", noCreate);
+ // TODO: xxxpedro console console2
+ return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null;
+ }
+
+};
+
+// ************************************************************************************************
+
+//TODO: xxxpedro
+//var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase);
+var ActivableConsole = extend(Firebug.ConsoleBase,
+{
+ isAlwaysEnabled: function()
+ {
+ return true;
+ }
+});
+
+Firebug.Console = Firebug.Console = extend(ActivableConsole,
+//Firebug.Console = extend(ActivableConsole,
+{
+ dispatchName: "console",
+
+ error: function()
+ {
+ Firebug.Console.logFormatted(arguments, Firebug.browser, "error");
+ },
+
+ flush: function()
+ {
+ dispatch(this.fbListeners,"flush",[]);
+
+ for (var i=0, length=consoleQueue.length; i<length; i++)
+ {
+ var args = consoleQueue[i];
+ this.logRow.apply(this, args);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Module
+
+ showPanel: function(browser, panel)
+ {
+ },
+
+ getFirebugConsoleElement: function(context, win)
+ {
+ var element = win.document.getElementById("_firebugConsole");
+ if (!element)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("getFirebugConsoleElement forcing element");
+ var elementForcer = "(function(){var r=null; try { r = window._getFirebugConsoleElement();}catch(exc){r=exc;} return r;})();"; // we could just add the elements here
+
+ if (context.stopped)
+ Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack
+ else
+ var r = Firebug.CommandLine.evaluateInWebPage(elementForcer, context, win);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("getFirebugConsoleElement forcing element result "+r, r);
+
+ var element = win.document.getElementById("_firebugConsole");
+ if (!element) // elementForce fails
+ {
+ if (FBTrace.DBG_ERRORS) FBTrace.sysout("console.getFirebugConsoleElement: no _firebugConsole in win:", win);
+ Firebug.Console.logFormatted(["Firebug cannot find _firebugConsole element", r, win], context, "error", true);
+ }
+ }
+
+ return element;
+ },
+
+ isReadyElsePreparing: function(context, win) // this is the only code that should call injector.attachIfNeeded
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.isReadyElsePreparing, win is " +
+ (win?"an argument: ":"null, context.window: ") +
+ (win?win.location:context.window.location), (win?win:context.window));
+
+ if (win)
+ return this.injector.attachIfNeeded(context, win);
+ else
+ {
+ var attached = true;
+ for (var i = 0; i < context.windows.length; i++)
+ attached = attached && this.injector.attachIfNeeded(context, context.windows[i]);
+ // already in the list above attached = attached && this.injector.attachIfNeeded(context, context.window);
+ if (context.windows.indexOf(context.window) == -1)
+ FBTrace.sysout("isReadyElsePreparing ***************** context.window not in context.windows");
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.isReadyElsePreparing attached to "+context.windows.length+" and returns "+attached);
+ return attached;
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends ActivableModule
+
+ initialize: function()
+ {
+ this.panelName = "console";
+
+ //TODO: xxxpedro
+ //Firebug.ActivableModule.initialize.apply(this, arguments);
+ //Firebug.Debugger.addListener(this);
+ },
+
+ enable: function()
+ {
+ if (Firebug.Console.isAlwaysEnabled())
+ this.watchForErrors();
+ },
+
+ disable: function()
+ {
+ if (Firebug.Console.isAlwaysEnabled())
+ this.unwatchForErrors();
+ },
+
+ initContext: function(context, persistedState)
+ {
+ Firebug.ActivableModule.initContext.apply(this, arguments);
+ context.consoleReloadWarning = true; // mark as need to warn.
+ },
+
+ loadedContext: function(context)
+ {
+ for (var url in context.sourceFileMap)
+ return; // if there are any sourceFiles, then do nothing
+
+ // else we saw no JS, so the reload warning it not needed.
+ this.clearReloadWarning(context);
+ },
+
+ clearReloadWarning: function(context) // remove the warning about reloading.
+ {
+ if (context.consoleReloadWarning)
+ {
+ var panel = context.getPanel(this.panelName);
+ panel.clearReloadWarning();
+ delete context.consoleReloadWarning;
+ }
+ },
+
+ togglePersist: function(context)
+ {
+ var panel = context.getPanel(this.panelName);
+ panel.persistContent = panel.persistContent ? false : true;
+ Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", panel.persistContent);
+ },
+
+ showContext: function(browser, context)
+ {
+ Firebug.chrome.setGlobalAttribute("cmd_clearConsole", "disabled", !context);
+
+ Firebug.ActivableModule.showContext.apply(this, arguments);
+ },
+
+ destroyContext: function(context, persistedState)
+ {
+ Firebug.Console.injector.detachConsole(context, context.window); // TODO iterate windows?
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onPanelEnable: function(panelName)
+ {
+ if (panelName != this.panelName) // we don't care about other panels
+ return;
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onPanelEnable**************");
+
+ this.watchForErrors();
+ Firebug.Debugger.addDependentModule(this); // we inject the console during JS compiles so we need jsd
+ },
+
+ onPanelDisable: function(panelName)
+ {
+ if (panelName != this.panelName) // we don't care about other panels
+ return;
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onPanelDisable**************");
+
+ Firebug.Debugger.removeDependentModule(this); // we inject the console during JS compiles so we need jsd
+ this.unwatchForErrors();
+
+ // Make sure possible errors coming from the page and displayed in the Firefox
+ // status bar are removed.
+ this.clear();
+ },
+
+ onSuspendFirebug: function()
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onSuspendFirebug\n");
+ if (Firebug.Console.isAlwaysEnabled())
+ this.unwatchForErrors();
+ },
+
+ onResumeFirebug: function()
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onResumeFirebug\n");
+ if (Firebug.Console.isAlwaysEnabled())
+ this.watchForErrors();
+ },
+
+ watchForErrors: function()
+ {
+ Firebug.Errors.checkEnabled();
+ $('fbStatusIcon').setAttribute("console", "on");
+ },
+
+ unwatchForErrors: function()
+ {
+ Firebug.Errors.checkEnabled();
+ $('fbStatusIcon').removeAttribute("console");
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Firebug.Debugger listener
+
+ onMonitorScript: function(context, frame)
+ {
+ Firebug.Console.log(frame, context);
+ },
+
+ onFunctionCall: function(context, frame, depth, calling)
+ {
+ if (calling)
+ Firebug.Console.openGroup([frame, "depth:"+depth], context);
+ else
+ Firebug.Console.closeGroup(context);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
+ {
+ if (!context)
+ context = FirebugContext;
+
+ if (FBTrace.DBG_WINDOWS && !context) FBTrace.sysout("Console.logRow: no context \n");
+
+ if (this.isAlwaysEnabled())
+ return Firebug.ConsoleBase.logRow.apply(this, arguments);
+ }
+});
+
+Firebug.ConsoleListener =
+{
+ log: function(context, object, className, sourceLink)
+ {
+ },
+
+ logFormatted: function(context, objects, className, sourceLink)
+ {
+ }
+};
+
+// ************************************************************************************************
+
+Firebug.ConsolePanel = function () {} // XXjjb attach Firebug so this panel can be extended.
+
+//TODO: xxxpedro
+//Firebug.ConsolePanel.prototype = extend(Firebug.ActivablePanel,
+Firebug.ConsolePanel.prototype = extend(Firebug.Panel,
+{
+ wasScrolledToBottom: false,
+ messageCount: 0,
+ lastLogTime: 0,
+ groups: null,
+ limit: null,
+
+ append: function(appender, objects, className, rep, sourceLink, noRow)
+ {
+ var container = this.getTopContainer();
+
+ if (noRow)
+ {
+ appender.apply(this, [objects]);
+ }
+ else
+ {
+ // xxxHonza: Don't update the this.wasScrolledToBottom flag now.
+ // At the beginning (when the first log is created) the isScrolledToBottom
+ // always returns true.
+ //if (this.panelNode.offsetHeight)
+ // this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
+
+ var row = this.createRow("logRow", className);
+ appender.apply(this, [objects, row, rep]);
+
+ if (sourceLink)
+ FirebugReps.SourceLink.tag.append({object: sourceLink}, row);
+
+ container.appendChild(row);
+
+ this.filterLogRow(row, this.wasScrolledToBottom);
+
+ if (this.wasScrolledToBottom)
+ scrollToBottom(this.panelNode);
+
+ return row;
+ }
+ },
+
+ clear: function()
+ {
+ if (this.panelNode)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("ConsolePanel.clear");
+ clearNode(this.panelNode);
+ this.insertLogLimit(this.context);
+ }
+ },
+
+ insertLogLimit: function()
+ {
+ // Create limit row. This row is the first in the list of entries
+ // and initially hidden. It's displayed as soon as the number of
+ // entries reaches the limit.
+ var row = this.createRow("limitRow");
+
+ var limitInfo = {
+ totalCount: 0,
+ limitPrefsTitle: $STRF("LimitPrefsTitle", [Firebug.prefDomain+".console.logLimit"])
+ };
+
+ //TODO: xxxpedro console net limit!?
+ return;
+ var netLimitRep = Firebug.NetMonitor.NetLimit;
+ var nodes = netLimitRep.createTable(row, limitInfo);
+
+ this.limit = nodes[1];
+
+ var container = this.panelNode;
+ container.insertBefore(nodes[0], container.firstChild);
+ },
+
+ insertReloadWarning: function()
+ {
+ // put the message in, we will clear if the window console is injected.
+ this.warningRow = this.append(appendObject, $STR("message.Reload to activate window console"), "info");
+ },
+
+ clearReloadWarning: function()
+ {
+ if (this.warningRow)
+ {
+ this.warningRow.parentNode.removeChild(this.warningRow);
+ delete this.warningRow;
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ appendObject: function(object, row, rep)
+ {
+ if (!rep)
+ rep = Firebug.getRep(object);
+ return rep.tag.append({object: object}, row);
+ },
+
+ appendFormatted: function(objects, row, rep)
+ {
+ if (!objects || !objects.length)
+ return;
+
+ function logText(text, row)
+ {
+ var node = row.ownerDocument.createTextNode(text);
+ row.appendChild(node);
+ }
+
+ var format = objects[0];
+ var objIndex = 0;
+
+ if (typeof(format) != "string")
+ {
+ format = "";
+ objIndex = -1;
+ }
+ else // a string
+ {
+ if (objects.length === 1) // then we have only a string...
+ {
+ if (format.length < 1) { // ...and it has no characters.
+ logText("(an empty string)", row);
+ return;
+ }
+ }
+ }
+
+ var parts = parseFormat(format);
+ var trialIndex = objIndex;
+ for (var i= 0; i < parts.length; i++)
+ {
+ var part = parts[i];
+ if (part && typeof(part) == "object")
+ {
+ if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted.
+ {
+ format = "";
+ objIndex = -1;
+ parts.length = 0;
+ break;
+ }
+ }
+
+ }
+ for (var i = 0; i < parts.length; ++i)
+ {
+ var part = parts[i];
+ if (part && typeof(part) == "object")
+ {
+ var object = objects[++objIndex];
+ if (typeof(object) != "undefined")
+ this.appendObject(object, row, part.rep);
+ else
+ this.appendObject(part.type, row, FirebugReps.Text);
+ }
+ else
+ FirebugReps.Text.tag.append({object: part}, row);
+ }
+
+ for (var i = objIndex+1; i < objects.length; ++i)
+ {
+ logText(" ", row);
+ var object = objects[i];
+ if (typeof(object) == "string")
+ FirebugReps.Text.tag.append({object: object}, row);
+ else
+ this.appendObject(object, row);
+ }
+ },
+
+ appendOpenGroup: function(objects, row, rep)
+ {
+ if (!this.groups)
+ this.groups = [];
+
+ setClass(row, "logGroup");
+ setClass(row, "opened");
+
+ var innerRow = this.createRow("logRow");
+ setClass(innerRow, "logGroupLabel");
+ if (rep)
+ rep.tag.replace({"objects": objects}, innerRow);
+ else
+ this.appendFormatted(objects, innerRow, rep);
+ row.appendChild(innerRow);
+ //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]);
+ var groupBody = this.createRow("logGroupBody");
+ row.appendChild(groupBody);
+ groupBody.setAttribute('role', 'group');
+ this.groups.push(groupBody);
+
+ addEvent(innerRow, "mousedown", function(event)
+ {
+ if (isLeftClick(event))
+ {
+ //console.log(event.currentTarget == event.target);
+
+ var target = event.target || event.srcElement;
+
+ target = getAncestorByClass(target, "logGroupLabel");
+
+ var groupRow = target.parentNode;
+
+ if (hasClass(groupRow, "opened"))
+ {
+ removeClass(groupRow, "opened");
+ target.setAttribute('aria-expanded', 'false');
+ }
+ else
+ {
+ setClass(groupRow, "opened");
+ target.setAttribute('aria-expanded', 'true');
+ }
+ }
+ });
+ },
+
+ appendCloseGroup: function(object, row, rep)
+ {
+ if (this.groups)
+ this.groups.pop();
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // TODO: xxxpedro console2
+ onMouseMove: function(event)
+ {
+ if (!Firebug.Inspector) return;
+
+ var target = event.srcElement || event.target;
+
+ var object = getAncestorByClass(target, "objectLink-element");
+ object = object ? object.repObject : null;
+
+ if(object && instanceOf(object, "Element") && object.nodeType == 1)
+ {
+ if(object != lastHighlightedObject)
+ {
+ Firebug.Inspector.drawBoxModel(object);
+ object = lastHighlightedObject;
+ }
+ }
+ else
+ Firebug.Inspector.hideBoxModel();
+
+ },
+
+ onMouseDown: function(event)
+ {
+ var target = event.srcElement || event.target;
+
+ var object = getAncestorByClass(target, "objectLink");
+ var repObject = object ? object.repObject : null;
+
+ if (!repObject)
+ {
+ return;
+ }
+
+ if (hasClass(object, "objectLink-object"))
+ {
+ Firebug.chrome.selectPanel("DOM");
+ Firebug.chrome.getPanel("DOM").select(repObject, true);
+ }
+ else if (hasClass(object, "objectLink-element"))
+ {
+ Firebug.chrome.selectPanel("HTML");
+ Firebug.chrome.getPanel("HTML").select(repObject, true);
+ }
+
+ /*
+ if(object && instanceOf(object, "Element") && object.nodeType == 1)
+ {
+ if(object != lastHighlightedObject)
+ {
+ Firebug.Inspector.drawBoxModel(object);
+ object = lastHighlightedObject;
+ }
+ }
+ else
+ Firebug.Inspector.hideBoxModel();
+ /**/
+
+ },
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "Console",
+ title: "Console",
+ //searchable: true,
+ //breakable: true,
+ //editable: false,
+
+ options:
+ {
+ hasCommandLine: true,
+ hasToolButtons: true,
+ isPreRendered: true
+ },
+
+ create: function()
+ {
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.context = Firebug.browser.window;
+ this.document = Firebug.chrome.document;
+ this.onMouseMove = bind(this.onMouseMove, this);
+ this.onMouseDown = bind(this.onMouseDown, this);
+
+ this.clearButton = new Button({
+ element: $("fbConsole_btClear"),
+ owner: Firebug.Console,
+ onClick: Firebug.Console.clear
+ });
+ },
+
+ initialize: function()
+ {
+ Firebug.Panel.initialize.apply(this, arguments); // loads persisted content
+ //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content
+
+ if (!this.persistedContent && Firebug.Console.isAlwaysEnabled())
+ {
+ this.insertLogLimit(this.context);
+
+ // Initialize log limit and listen for changes.
+ this.updateMaxLimit();
+
+ if (this.context.consoleReloadWarning) // we have not yet injected the console
+ this.insertReloadWarning();
+ }
+
+ //Firebug.Console.injector.install(Firebug.browser.window);
+
+ addEvent(this.panelNode, "mouseover", this.onMouseMove);
+ addEvent(this.panelNode, "mousedown", this.onMouseDown);
+
+ this.clearButton.initialize();
+
+ //consolex.trace();
+ //TODO: xxxpedro remove this
+ /*
+ Firebug.Console.openGroup(["asd"], null, "group", null, false);
+ Firebug.Console.log("asd");
+ Firebug.Console.log("asd");
+ Firebug.Console.log("asd");
+ /**/
+
+ //TODO: xxxpedro preferences prefs
+ //prefs.addObserver(Firebug.prefDomain, this, false);
+ },
+
+ initializeNode : function()
+ {
+ //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]);
+ if (FBTrace.DBG_CONSOLE)
+ {
+ this.onScroller = bind(this.onScroll, this);
+ addEvent(this.panelNode, "scroll", this.onScroller);
+ }
+
+ this.onResizer = bind(this.onResize, this);
+ this.resizeEventTarget = Firebug.chrome.$('fbContentBox');
+ addEvent(this.resizeEventTarget, "resize", this.onResizer);
+ },
+
+ destroyNode : function()
+ {
+ //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]);
+ if (this.onScroller)
+ removeEvent(this.panelNode, "scroll", this.onScroller);
+
+ //removeEvent(this.resizeEventTarget, "resize", this.onResizer);
+ },
+
+ shutdown: function()
+ {
+ //TODO: xxxpedro console console2
+ this.clearButton.shutdown();
+
+ removeEvent(this.panelNode, "mousemove", this.onMouseMove);
+ removeEvent(this.panelNode, "mousedown", this.onMouseDown);
+
+ this.destroyNode();
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+
+ //TODO: xxxpedro preferences prefs
+ //prefs.removeObserver(Firebug.prefDomain, this, false);
+ },
+
+ ishow: function(state)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.panel show; " + this.context.getName(), state);
+
+ var enabled = Firebug.Console.isAlwaysEnabled();
+ if (enabled)
+ {
+ Firebug.Console.disabledPanelPage.hide(this);
+ this.showCommandLine(true);
+ this.showToolbarButtons("fbConsoleButtons", true);
+ Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent);
+
+ if (state && state.wasScrolledToBottom)
+ {
+ this.wasScrolledToBottom = state.wasScrolledToBottom;
+ delete state.wasScrolledToBottom;
+ }
+
+ if (this.wasScrolledToBottom)
+ scrollToBottom(this.panelNode);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " +
+ this.wasScrolledToBottom + ", " + this.context.getName());
+ }
+ else
+ {
+ this.hide(state);
+ Firebug.Console.disabledPanelPage.show(this);
+ }
+ },
+
+ ihide: function(state)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.panel hide; " + this.context.getName(), state);
+
+ this.showToolbarButtons("fbConsoleButtons", false);
+ this.showCommandLine(false);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " +
+ this.wasScrolledToBottom + ", " + this.context.getName());
+ },
+
+ destroy: function(state)
+ {
+ if (this.panelNode.offsetHeight)
+ this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
+
+ if (state)
+ state.wasScrolledToBottom = this.wasScrolledToBottom;
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " +
+ this.wasScrolledToBottom + ", " + this.context.getName());
+ },
+
+ shouldBreakOnNext: function()
+ {
+ // xxxHonza: shouldn't the breakOnErrors be context related?
+ // xxxJJB, yes, but we can't support it because we can't yet tell
+ // which window the error is on.
+ return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors");
+ },
+
+ getBreakOnNextTooltip: function(enabled)
+ {
+ return (enabled ? $STR("console.Disable Break On All Errors") :
+ $STR("console.Break On All Errors"));
+ },
+
+ enablePanel: function(module)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName());
+
+ Firebug.ActivablePanel.enablePanel.apply(this, arguments);
+
+ this.showCommandLine(true);
+
+ if (this.wasScrolledToBottom)
+ scrollToBottom(this.panelNode);
+ },
+
+ disablePanel: function(module)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName());
+
+ Firebug.ActivablePanel.disablePanel.apply(this, arguments);
+
+ this.showCommandLine(false);
+ },
+
+ getOptionsMenuItems: function()
+ {
+ return [
+ optionMenu("ShowJavaScriptErrors", "showJSErrors"),
+ optionMenu("ShowJavaScriptWarnings", "showJSWarnings"),
+ optionMenu("ShowCSSErrors", "showCSSErrors"),
+ optionMenu("ShowXMLErrors", "showXMLErrors"),
+ optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"),
+ optionMenu("ShowChromeErrors", "showChromeErrors"),
+ optionMenu("ShowChromeMessages", "showChromeMessages"),
+ optionMenu("ShowExternalErrors", "showExternalErrors"),
+ optionMenu("ShowNetworkErrors", "showNetworkErrors"),
+ this.getShowStackTraceMenuItem(),
+ this.getStrictOptionMenuItem(),
+ "-",
+ optionMenu("LargeCommandLine", "largeCommandLine")
+ ];
+ },
+
+ getShowStackTraceMenuItem: function()
+ {
+ var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace");
+ if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled())
+ menuItem.disabled = true;
+ return menuItem;
+ },
+
+ getStrictOptionMenuItem: function()
+ {
+ var strictDomain = "javascript.options";
+ var strictName = "strict";
+ var strictValue = prefs.getBoolPref(strictDomain+"."+strictName);
+ return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue,
+ command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) };
+ },
+
+ getBreakOnMenuItems: function()
+ {
+ //xxxHonza: no BON options for now.
+ /*return [
+ optionMenu("console.option.Persist Break On Error", "persistBreakOnError")
+ ];*/
+ return [];
+ },
+
+ search: function(text)
+ {
+ if (!text)
+ return;
+
+ // Make previously visible nodes invisible again
+ if (this.matchSet)
+ {
+ for (var i in this.matchSet)
+ removeClass(this.matchSet[i], "matched");
+ }
+
+ this.matchSet = [];
+
+ function findRow(node) { return getAncestorByClass(node, "logRow"); }
+ var search = new TextSearch(this.panelNode, findRow);
+
+ var logRow = search.find(text);
+ if (!logRow)
+ {
+ dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]);
+ return false;
+ }
+ for (; logRow; logRow = search.findNext())
+ {
+ setClass(logRow, "matched");
+ this.matchSet.push(logRow);
+ }
+ dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]);
+ return true;
+ },
+
+ breakOnNext: function(breaking)
+ {
+ Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // private
+
+ createRow: function(rowName, className)
+ {
+ var elt = this.document.createElement("div");
+ elt.className = rowName + (className ? " " + rowName + "-" + className : "");
+ return elt;
+ },
+
+ getTopContainer: function()
+ {
+ if (this.groups && this.groups.length)
+ return this.groups[this.groups.length-1];
+ else
+ return this.panelNode;
+ },
+
+ filterLogRow: function(logRow, scrolledToBottom)
+ {
+ if (this.searchText)
+ {
+ setClass(logRow, "matching");
+ setClass(logRow, "matched");
+
+ // Search after a delay because we must wait for a frame to be created for
+ // the new logRow so that the finder will be able to locate it
+ setTimeout(bindFixed(function()
+ {
+ if (this.searchFilter(this.searchText, logRow))
+ this.matchSet.push(logRow);
+ else
+ removeClass(logRow, "matched");
+
+ removeClass(logRow, "matching");
+
+ if (scrolledToBottom)
+ scrollToBottom(this.panelNode);
+ }, this), 100);
+ }
+ },
+
+ searchFilter: function(text, logRow)
+ {
+ var count = this.panelNode.childNodes.length;
+ var searchRange = this.document.createRange();
+ searchRange.setStart(this.panelNode, 0);
+ searchRange.setEnd(this.panelNode, count);
+
+ var startPt = this.document.createRange();
+ startPt.setStartBefore(logRow);
+
+ var endPt = this.document.createRange();
+ endPt.setStartAfter(logRow);
+
+ return finder.Find(text, searchRange, startPt, endPt) != null;
+ },
+
+ // nsIPrefObserver
+ observe: function(subject, topic, data)
+ {
+ // We're observing preferences only.
+ if (topic != "nsPref:changed")
+ return;
+
+ // xxxHonza check this out.
+ var prefDomain = "Firebug.extension.";
+ var prefName = data.substr(prefDomain.length);
+ if (prefName == "console.logLimit")
+ this.updateMaxLimit();
+ },
+
+ updateMaxLimit: function()
+ {
+ var value = 1000;
+ //TODO: xxxpedro preferences log limit?
+ //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit");
+ maxQueueRequests = value ? value : maxQueueRequests;
+ },
+
+ showCommandLine: function(shouldShow)
+ {
+ //TODO: xxxpedro show command line important
+ return;
+
+ if (shouldShow)
+ {
+ collapse(Firebug.chrome.$("fbCommandBox"), false);
+ Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome);
+ }
+ else
+ {
+ // Make sure that entire content of the Console panel is hidden when
+ // the panel is disabled.
+ Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine);
+ collapse(Firebug.chrome.$("fbCommandBox"), true);
+ }
+ },
+
+ onScroll: function(event)
+ {
+ // Update the scroll position flag if the position changes.
+ this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " +
+ this.wasScrolledToBottom + ", wasScrolledToBottom: " +
+ this.context.getName(), event);
+ },
+
+ onResize: function(event)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " +
+ this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight +
+ ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " +
+ this.panelNode.scrollHeight + ", " + this.context.getName(), event);
+
+ if (this.wasScrolledToBottom)
+ scrollToBottom(this.panelNode);
+ }
+});
+
+// ************************************************************************************************
+
+function parseFormat(format)
+{
+ var parts = [];
+ if (format.length <= 0)
+ return parts;
+
+ var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/;
+ for (var m = reg.exec(format); m; m = reg.exec(format))
+ {
+ if (m[0].substr(0, 2) == "%%")
+ {
+ parts.push(format.substr(0, m.index));
+ parts.push(m[0].substr(1));
+ }
+ else
+ {
+ var type = m[8] ? m[8] : m[5];
+ var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+ var rep = null;
+ switch (type)
+ {
+ case "s":
+ rep = FirebugReps.Text;
+ break;
+ case "f":
+ case "i":
+ case "d":
+ rep = FirebugReps.Number;
+ break;
+ case "o":
+ rep = null;
+ break;
+ }
+
+ parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+ parts.push({rep: rep, precision: precision, type: ("%" + type)});
+ }
+
+ format = format.substr(m.index+m[0].length);
+ }
+
+ parts.push(format);
+ return parts;
+}
+
+// ************************************************************************************************
+
+var appendObject = Firebug.ConsolePanel.prototype.appendObject;
+var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted;
+var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup;
+var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup;
+
+// ************************************************************************************************
+
+//Firebug.registerActivableModule(Firebug.Console);
+Firebug.registerModule(Firebug.Console);
+Firebug.registerPanel(Firebug.ConsolePanel);
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+//const Cc = Components.classes;
+//const Ci = Components.interfaces;
+
+var frameCounters = {};
+var traceRecursion = 0;
+
+Firebug.Console.injector =
+{
+ install: function(context)
+ {
+ var win = context.window;
+
+ var consoleHandler = new FirebugConsoleHandler(context, win);
+
+ var properties =
+ [
+ "log",
+ "debug",
+ "info",
+ "warn",
+ "error",
+ "assert",
+ "dir",
+ "dirxml",
+ "group",
+ "groupCollapsed",
+ "groupEnd",
+ "time",
+ "timeEnd",
+ "count",
+ "trace",
+ "profile",
+ "profileEnd",
+ "clear",
+ "open",
+ "close"
+ ];
+
+ var Handler = function(name)
+ {
+ var c = consoleHandler;
+ var f = consoleHandler[name];
+ return function(){return f.apply(c,arguments);};
+ };
+
+ var installer = function(c)
+ {
+ for (var i=0, l=properties.length; i<l; i++)
+ {
+ var name = properties[i];
+ c[name] = new Handler(name);
+ c.firebuglite = Firebug.version;
+ }
+ };
+
+ var sandbox;
+
+ if (win.console)
+ {
+ if (Env.Options.overrideConsole)
+ sandbox = new win.Function("arguments.callee.install(window.console={})");
+ else
+ // if there's a console object and overrideConsole is false we should just quit
+ return;
+ }
+ else
+ {
+ try
+ {
+ // try overriding the console object
+ sandbox = new win.Function("arguments.callee.install(window.console={})");
+ }
+ catch(E)
+ {
+ // if something goes wrong create the firebug object instead
+ sandbox = new win.Function("arguments.callee.install(window.firebug={})");
+ }
+ }
+
+ sandbox.install = installer;
+ sandbox();
+ },
+
+ isAttached: function(context, win)
+ {
+ if (win.wrappedJSObject)
+ {
+ var attached = (win.wrappedJSObject._getFirebugConsoleElement ? true : false);
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.isAttached:"+attached+" to win.wrappedJSObject "+safeGetWindowLocation(win.wrappedJSObject));
+
+ return attached;
+ }
+ else
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.isAttached? to win "+win.location+" fnc:"+win._getFirebugConsoleElement);
+ return (win._getFirebugConsoleElement ? true : false);
+ }
+ },
+
+ attachIfNeeded: function(context, win)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.attachIfNeeded has win "+(win? ((win.wrappedJSObject?"YES":"NO")+" wrappedJSObject"):"null") );
+
+ if (this.isAttached(context, win))
+ return true;
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("Console.attachIfNeeded found isAttached false ");
+
+ this.attachConsoleInjector(context, win);
+ this.addConsoleListener(context, win);
+
+ Firebug.Console.clearReloadWarning(context);
+
+ var attached = this.isAttached(context, win);
+ if (attached)
+ dispatch(Firebug.Console.fbListeners, "onConsoleInjected", [context, win]);
+
+ return attached;
+ },
+
+ attachConsoleInjector: function(context, win)
+ {
+ var consoleInjection = this.getConsoleInjectionScript(); // Do it all here.
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("attachConsoleInjector evaluating in "+win.location, consoleInjection);
+
+ Firebug.CommandLine.evaluateInWebPage(consoleInjection, context, win);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("attachConsoleInjector evaluation completed for "+win.location);
+ },
+
+ getConsoleInjectionScript: function() {
+ if (!this.consoleInjectionScript)
+ {
+ var script = "";
+ script += "window.__defineGetter__('console', function() {\n";
+ script += " return (window._firebug ? window._firebug : window.loadFirebugConsole()); })\n\n";
+
+ script += "window.loadFirebugConsole = function() {\n";
+ script += "window._firebug = new _FirebugConsole();";
+
+ if (FBTrace.DBG_CONSOLE)
+ script += " window.dump('loadFirebugConsole '+window.location+'\\n');\n";
+
+ script += " return window._firebug };\n";
+
+ var theFirebugConsoleScript = getResource("chrome://firebug/content/consoleInjected.js");
+ script += theFirebugConsoleScript;
+
+
+ this.consoleInjectionScript = script;
+ }
+ return this.consoleInjectionScript;
+ },
+
+ forceConsoleCompilationInPage: function(context, win)
+ {
+ if (!win)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("no win in forceConsoleCompilationInPage!");
+ return;
+ }
+
+ var consoleForcer = "window.loadFirebugConsole();";
+
+ if (context.stopped)
+ Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack
+ else
+ Firebug.CommandLine.evaluateInWebPage(consoleForcer, context, win);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("forceConsoleCompilationInPage "+win.location, consoleForcer);
+ },
+
+ evaluateConsoleScript: function(context)
+ {
+ var scriptSource = this.getConsoleInjectionScript(); // TODO XXXjjb this should be getConsoleInjectionScript
+ Firebug.Debugger.evaluate(scriptSource, context);
+ },
+
+ addConsoleListener: function(context, win)
+ {
+ if (!context.activeConsoleHandlers) // then we have not been this way before
+ context.activeConsoleHandlers = [];
+ else
+ { // we've been this way before...
+ for (var i=0; i<context.activeConsoleHandlers.length; i++)
+ {
+ if (context.activeConsoleHandlers[i].window == win)
+ {
+ context.activeConsoleHandlers[i].detach();
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("consoleInjector addConsoleListener removed handler("+context.activeConsoleHandlers[i].handler_name+") from _firebugConsole in : "+win.location+"\n");
+ context.activeConsoleHandlers.splice(i,1);
+ }
+ }
+ }
+
+ // We need the element to attach our event listener.
+ var element = Firebug.Console.getFirebugConsoleElement(context, win);
+ if (element)
+ element.setAttribute("FirebugVersion", Firebug.version); // Initialize Firebug version.
+ else
+ return false;
+
+ var handler = new FirebugConsoleHandler(context, win);
+ handler.attachTo(element);
+
+ context.activeConsoleHandlers.push(handler);
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("consoleInjector addConsoleListener attached handler("+handler.handler_name+") to _firebugConsole in : "+win.location+"\n");
+ return true;
+ },
+
+ detachConsole: function(context, win)
+ {
+ if (win && win.document)
+ {
+ var element = win.document.getElementById("_firebugConsole");
+ if (element)
+ element.parentNode.removeChild(element);
+ }
+ }
+};
+
+var total_handlers = 0;
+var FirebugConsoleHandler = function FirebugConsoleHandler(context, win)
+{
+ this.window = win;
+
+ this.attachTo = function(element)
+ {
+ this.element = element;
+ // When raised on our injected element, callback to Firebug and append to console
+ this.boundHandler = bind(this.handleEvent, this);
+ this.element.addEventListener('firebugAppendConsole', this.boundHandler, true); // capturing
+ };
+
+ this.detach = function()
+ {
+ this.element.removeEventListener('firebugAppendConsole', this.boundHandler, true);
+ };
+
+ this.handler_name = ++total_handlers;
+ this.handleEvent = function(event)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("FirebugConsoleHandler("+this.handler_name+") "+event.target.getAttribute("methodName")+", event", event);
+ if (!Firebug.CommandLine.CommandHandler.handle(event, this, win))
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("FirebugConsoleHandler", this);
+
+ var methodName = event.target.getAttribute("methodName");
+ Firebug.Console.log($STRF("console.MethodNotSupported", [methodName]));
+ }
+ };
+
+ this.firebuglite = Firebug.version;
+
+ this.init = function()
+ {
+ var consoleElement = win.document.getElementById('_firebugConsole');
+ consoleElement.setAttribute("FirebugVersion", Firebug.version);
+ };
+
+ this.log = function()
+ {
+ logFormatted(arguments, "log");
+ };
+
+ this.debug = function()
+ {
+ logFormatted(arguments, "debug", true);
+ };
+
+ this.info = function()
+ {
+ logFormatted(arguments, "info", true);
+ };
+
+ this.warn = function()
+ {
+ logFormatted(arguments, "warn", true);
+ };
+
+ this.error = function()
+ {
+ //TODO: xxxpedro console error
+ //if (arguments.length == 1)
+ //{
+ // logAssert("error", arguments); // add more info based on stack trace
+ //}
+ //else
+ //{
+ //Firebug.Errors.increaseCount(context);
+ logFormatted(arguments, "error", true); // user already added info
+ //}
+ };
+
+ this.exception = function()
+ {
+ logAssert("error", arguments);
+ };
+
+ this.assert = function(x)
+ {
+ if (!x)
+ {
+ var rest = [];
+ for (var i = 1; i < arguments.length; i++)
+ rest.push(arguments[i]);
+ logAssert("assert", rest);
+ }
+ };
+
+ this.dir = function(o)
+ {
+ Firebug.Console.log(o, context, "dir", Firebug.DOMPanel.DirTable);
+ };
+
+ this.dirxml = function(o)
+ {
+ ///if (o instanceof Window)
+ if (instanceOf(o, "Window"))
+ o = o.document.documentElement;
+ ///else if (o instanceof Document)
+ else if (instanceOf(o, "Document"))
+ o = o.documentElement;
+
+ Firebug.Console.log(o, context, "dirxml", Firebug.HTMLPanel.SoloElement);
+ };
+
+ this.group = function()
+ {
+ //TODO: xxxpedro;
+ //var sourceLink = getStackLink();
+ var sourceLink = null;
+ Firebug.Console.openGroup(arguments, null, "group", null, false, sourceLink);
+ };
+
+ this.groupEnd = function()
+ {
+ Firebug.Console.closeGroup(context);
+ };
+
+ this.groupCollapsed = function()
+ {
+ var sourceLink = getStackLink();
+ // noThrottle true is probably ok, openGroups will likely be short strings.
+ var row = Firebug.Console.openGroup(arguments, null, "group", null, true, sourceLink);
+ removeClass(row, "opened");
+ };
+
+ this.profile = function(title)
+ {
+ logFormatted(["console.profile() not supported."], "warn", true);
+
+ //Firebug.Profiler.startProfiling(context, title);
+ };
+
+ this.profileEnd = function()
+ {
+ logFormatted(["console.profile() not supported."], "warn", true);
+
+ //Firebug.Profiler.stopProfiling(context);
+ };
+
+ this.count = function(key)
+ {
+ // TODO: xxxpedro console2: is there a better way to find a unique ID for the coun() call?
+ var frameId = "0";
+ //var frameId = FBL.getStackFrameId();
+ if (frameId)
+ {
+ if (!frameCounters)
+ frameCounters = {};
+
+ if (key != undefined)
+ frameId += key;
+
+ var frameCounter = frameCounters[frameId];
+ if (!frameCounter)
+ {
+ var logRow = logFormatted(["0"], null, true, true);
+
+ frameCounter = {logRow: logRow, count: 1};
+ frameCounters[frameId] = frameCounter;
+ }
+ else
+ ++frameCounter.count;
+
+ var label = key == undefined
+ ? frameCounter.count
+ : key + " " + frameCounter.count;
+
+ frameCounter.logRow.firstChild.firstChild.nodeValue = label;
+ }
+ };
+
+ this.trace = function()
+ {
+ var getFuncName = function getFuncName (f)
+ {
+ if (f.getName instanceof Function)
+ {
+ return f.getName();
+ }
+ if (f.name) // in FireFox, Function objects have a name property...
+ {
+ return f.name;
+ }
+
+ var name = f.toString().match(/function\s*([_$\w\d]*)/)[1];
+ return name || "anonymous";
+ };
+
+ var wasVisited = function(fn)
+ {
+ for (var i=0, l=frames.length; i<l; i++)
+ {
+ if (frames[i].fn == fn)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ traceRecursion++;
+
+ if (traceRecursion > 1)
+ {
+ traceRecursion--;
+ return;
+ }
+
+ var frames = [];
+
+ for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller)
+ {
+ if (wasVisited(fn)) break;
+
+ var args = [];
+
+ for (var i = 0, l = fn.arguments.length; i < l; ++i)
+ {
+ args.push({value: fn.arguments[i]});
+ }
+
+ frames.push({fn: fn, name: getFuncName(fn), args: args});
+ }
+
+
+ // ****************************************************************************************
+
+ try
+ {
+ (0)();
+ }
+ catch(e)
+ {
+ var result = e;
+
+ var stack =
+ result.stack || // Firefox / Google Chrome
+ result.stacktrace || // Opera
+ "";
+
+ stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks
+ var items = stack.split(/[\n\r]/);
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Google Chrome
+ if (FBL.isSafari)
+ {
+ //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/;
+ //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/;
+ var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/;
+
+ var reChromeStackItemName = /\s*\($/;
+ var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/;
+
+ var framePos = 0;
+ for (var i=4, length=items.length; i<length; i++, framePos++)
+ {
+ var frame = frames[framePos];
+ var item = items[i];
+ var match = item.match(reChromeStackItem);
+
+ //Firebug.Console.log("["+ framePos +"]--------------------------");
+ //Firebug.Console.log(item);
+ //Firebug.Console.log("................");
+
+ if (match)
+ {
+ var name = match[1];
+ if (name)
+ {
+ name = name.replace(reChromeStackItemName, "");
+ frame.name = name;
+ }
+
+ //Firebug.Console.log("name: "+name);
+
+ var value = match[2].match(reChromeStackItemValue);
+ if (value)
+ {
+ frame.href = value[1];
+ frame.lineNo = value[2];
+
+ //Firebug.Console.log("url: "+value[1]);
+ //Firebug.Console.log("line: "+value[2]);
+ }
+ //else
+ // Firebug.Console.log(match[2]);
+
+ }
+ }
+ }
+ /**/
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ else if (FBL.isFirefox)
+ {
+ // Firefox
+ var reFirefoxStackItem = /^(.*)@(.*)$/;
+ var reFirefoxStackItemValue = /^(.+)\:(\d+)$/;
+
+ var framePos = 0;
+ for (var i=2, length=items.length; i<length; i++, framePos++)
+ {
+ var frame = frames[framePos] || {};
+ var item = items[i];
+ var match = item.match(reFirefoxStackItem);
+
+ if (match)
+ {
+ var name = match[1];
+
+ //Firebug.Console.logFormatted("name: "+name);
+
+ var value = match[2].match(reFirefoxStackItemValue);
+ if (value)
+ {
+ frame.href = value[1];
+ frame.lineNo = value[2];
+
+ //Firebug.Console.log("href: "+ value[1]);
+ //Firebug.Console.log("line: " + value[2]);
+ }
+ //else
+ // Firebug.Console.logFormatted([match[2]]);
+ }
+ }
+ }
+ /**/
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ /*
+ else if (FBL.isOpera)
+ {
+ // Opera
+ var reOperaStackItem = /^\s\s(?:\.\.\.\s\s)?Line\s(\d+)\sof\s(.+)$/;
+ var reOperaStackItemValue = /^linked\sscript\s(.+)$/;
+
+ for (var i=0, length=items.length; i<length; i+=2)
+ {
+ var item = items[i];
+
+ var match = item.match(reOperaStackItem);
+
+ if (match)
+ {
+ //Firebug.Console.log(match[1]);
+
+ var value = match[2].match(reOperaStackItemValue);
+
+ if (value)
+ {
+ //Firebug.Console.log(value[1]);
+ }
+ //else
+ // Firebug.Console.log(match[2]);
+
+ //Firebug.Console.log("--------------------------");
+ }
+ }
+ }
+ /**/
+ }
+
+ //console.log(stack);
+ //console.dir(frames);
+ Firebug.Console.log({frames: frames}, context, "stackTrace", FirebugReps.StackTrace);
+
+ traceRecursion--;
+ };
+
+ this.trace_ok = function()
+ {
+ var getFuncName = function getFuncName (f)
+ {
+ if (f.getName instanceof Function)
+ return f.getName();
+ if (f.name) // in FireFox, Function objects have a name property...
+ return f.name;
+
+ var name = f.toString().match(/function\s*([_$\w\d]*)/)[1];
+ return name || "anonymous";
+ };
+
+ var wasVisited = function(fn)
+ {
+ for (var i=0, l=frames.length; i<l; i++)
+ {
+ if (frames[i].fn == fn)
+ return true;
+ }
+
+ return false;
+ };
+
+ var frames = [];
+
+ for (var fn = arguments.callee.caller; fn; fn = fn.caller)
+ {
+ if (wasVisited(fn)) break;
+
+ var args = [];
+
+ for (var i = 0, l = fn.arguments.length; i < l; ++i)
+ {
+ args.push({value: fn.arguments[i]});
+ }
+
+ frames.push({fn: fn, name: getFuncName(fn), args: args});
+ }
+
+ Firebug.Console.log({frames: frames}, context, "stackTrace", FirebugReps.StackTrace);
+ };
+
+ this.clear = function()
+ {
+ Firebug.Console.clear(context);
+ };
+
+ this.time = function(name, reset)
+ {
+ if (!name)
+ return;
+
+ var time = new Date().getTime();
+
+ if (!this.timeCounters)
+ this.timeCounters = {};
+
+ var key = "KEY"+name.toString();
+
+ if (!reset && this.timeCounters[key])
+ return;
+
+ this.timeCounters[key] = time;
+ };
+
+ this.timeEnd = function(name)
+ {
+ var time = new Date().getTime();
+
+ if (!this.timeCounters)
+ return;
+
+ var key = "KEY"+name.toString();
+
+ var timeCounter = this.timeCounters[key];
+ if (timeCounter)
+ {
+ var diff = time - timeCounter;
+ var label = name + ": " + diff + "ms";
+
+ this.info(label);
+
+ delete this.timeCounters[key];
+ }
+ return diff;
+ };
+
+ // These functions are over-ridden by commandLine
+ this.evaluated = function(result, context)
+ {
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("consoleInjector.FirebugConsoleHandler evalutated default called", result);
+
+ Firebug.Console.log(result, context);
+ };
+ this.evaluateError = function(result, context)
+ {
+ Firebug.Console.log(result, context, "errorMessage");
+ };
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ function logFormatted(args, className, linkToSource, noThrottle)
+ {
+ var sourceLink = linkToSource ? getStackLink() : null;
+ return Firebug.Console.logFormatted(args, context, className, noThrottle, sourceLink);
+ }
+
+ function logAssert(category, args)
+ {
+ Firebug.Errors.increaseCount(context);
+
+ if (!args || !args.length || args.length == 0)
+ var msg = [FBL.$STR("Assertion")];
+ else
+ var msg = args[0];
+
+ if (Firebug.errorStackTrace)
+ {
+ var trace = Firebug.errorStackTrace;
+ delete Firebug.errorStackTrace;
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("logAssert trace from errorStackTrace", trace);
+ }
+ else if (msg.stack)
+ {
+ var trace = parseToStackTrace(msg.stack);
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("logAssert trace from msg.stack", trace);
+ }
+ else
+ {
+ var trace = getJSDUserStack();
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("logAssert trace from getJSDUserStack", trace);
+ }
+
+ var errorObject = new FBL.ErrorMessage(msg, (msg.fileName?msg.fileName:win.location), (msg.lineNumber?msg.lineNumber:0), "", category, context, trace);
+
+
+ if (trace && trace.frames && trace.frames[0])
+ errorObject.correctWithStackTrace(trace);
+
+ errorObject.resetSource();
+
+ var objects = errorObject;
+ if (args.length > 1)
+ {
+ objects = [errorObject];
+ for (var i = 1; i < args.length; i++)
+ objects.push(args[i]);
+ }
+
+ var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle
+ row.scrollIntoView();
+ }
+
+ function getComponentsStackDump()
+ {
+ // Starting with our stack, walk back to the user-level code
+ var frame = Components.stack;
+ var userURL = win.location.href.toString();
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame);
+
+ // Drop frames until we get into user code.
+ while (frame && FBL.isSystemURL(frame.filename) )
+ frame = frame.caller;
+
+ // Drop two more frames, the injected console function and firebugAppendConsole()
+ if (frame)
+ frame = frame.caller;
+ if (frame)
+ frame = frame.caller;
+
+ if (FBTrace.DBG_CONSOLE)
+ FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame);
+
+ return frame;
+ }
+
+ function getStackLink()
+ {
+ // TODO: xxxpedro console2
+ return;
+ //return FBL.getFrameSourceLink(getComponentsStackDump());
+ }
+
+ function getJSDUserStack()
+ {
+ var trace = FBL.getCurrentStackTrace(context);
+
+ var frames = trace ? trace.frames : null;
+ if (frames && (frames.length > 0) )
+ {
+ var oldest = frames.length - 1; // 6 - 1 = 5
+ for (var i = 0; i < frames.length; i++)
+ {
+ if (frames[oldest - i].href.indexOf("chrome:") == 0) break;
+ var fn = frames[oldest - i].fn + "";
+ if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line
+ }
+ FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace);
+ trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code
+
+ return trace;
+ }
+ else
+ return "Firebug failed to get stack trace with any frames";
+ }
+};
+
+// ************************************************************************************************
+// Register console namespace
+
+FBL.registerConsole = function()
+{
+ var win = Env.browser.window;
+ Firebug.Console.injector.install(win);
+};
+
+registerConsole();
+
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+
+// ************************************************************************************************
+// Globals
+
+var commandPrefix = ">>>";
+var reOpenBracket = /[\[\(\{]/;
+var reCloseBracket = /[\]\)\}]/;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var commandHistory = [];
+var commandPointer = -1;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var isAutoCompleting = null;
+var autoCompletePrefix = null;
+var autoCompleteExpr = null;
+var autoCompleteBuffer = null;
+var autoCompletePosition = null;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var fbCommandLine = null;
+var fbLargeCommandLine = null;
+var fbLargeCommandButtons = null;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var _completion =
+{
+ window:
+ [
+ "console"
+ ],
+
+ document:
+ [
+ "getElementById",
+ "getElementsByTagName"
+ ]
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var _stack = function(command)
+{
+ Firebug.context.persistedState.commandHistory.push(command);
+ Firebug.context.persistedState.commandPointer =
+ Firebug.context.persistedState.commandHistory.length;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+// ************************************************************************************************
+// CommandLine
+
+Firebug.CommandLine = extend(Firebug.Module,
+{
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ element: null,
+ isMultiLine: false,
+ isActive: false,
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ initialize: function(doc)
+ {
+ this.clear = bind(this.clear, this);
+ this.enter = bind(this.enter, this);
+
+ this.onError = bind(this.onError, this);
+ this.onKeyDown = bind(this.onKeyDown, this);
+ this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this);
+
+ addEvent(Firebug.browser.window, "error", this.onError);
+ addEvent(Firebug.chrome.window, "error", this.onError);
+ },
+
+ shutdown: function(doc)
+ {
+ this.deactivate();
+
+ removeEvent(Firebug.browser.window, "error", this.onError);
+ removeEvent(Firebug.chrome.window, "error", this.onError);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ activate: function(multiLine, hideToggleIcon, onRun)
+ {
+ defineCommandLineAPI();
+
+ Firebug.context.persistedState.commandHistory =
+ Firebug.context.persistedState.commandHistory || [];
+
+ Firebug.context.persistedState.commandPointer =
+ Firebug.context.persistedState.commandPointer || -1;
+
+ if (this.isActive)
+ {
+ if (this.isMultiLine == multiLine) return;
+
+ this.deactivate();
+ }
+
+ fbCommandLine = $("fbCommandLine");
+ fbLargeCommandLine = $("fbLargeCommandLine");
+ fbLargeCommandButtons = $("fbLargeCommandButtons");
+
+ if (multiLine)
+ {
+ onRun = onRun || this.enter;
+
+ this.isMultiLine = true;
+
+ this.element = fbLargeCommandLine;
+
+ addEvent(this.element, "keydown", this.onMultiLineKeyDown);
+
+ addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine);
+
+ this.runButton = new Button({
+ element: $("fbCommand_btRun"),
+ owner: Firebug.CommandLine,
+ onClick: onRun
+ });
+
+ this.runButton.initialize();
+
+ this.clearButton = new Button({
+ element: $("fbCommand_btClear"),
+ owner: Firebug.CommandLine,
+ onClick: this.clear
+ });
+
+ this.clearButton.initialize();
+ }
+ else
+ {
+ this.isMultiLine = false;
+ this.element = fbCommandLine;
+
+ if (!fbCommandLine)
+ return;
+
+ addEvent(this.element, "keydown", this.onKeyDown);
+ }
+
+ //Firebug.Console.log("activate", this.element);
+
+ if (isOpera)
+ fixOperaTabKey(this.element);
+
+ if(this.lastValue)
+ this.element.value = this.lastValue;
+
+ this.isActive = true;
+ },
+
+ deactivate: function()
+ {
+ if (!this.isActive) return;
+
+ //Firebug.Console.log("deactivate", this.element);
+
+ this.isActive = false;
+
+ this.lastValue = this.element.value;
+
+ if (this.isMultiLine)
+ {
+ removeEvent(this.element, "keydown", this.onMultiLineKeyDown);
+
+ removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine);
+
+ this.runButton.destroy();
+ this.clearButton.destroy();
+ }
+ else
+ {
+ removeEvent(this.element, "keydown", this.onKeyDown);
+ }
+
+ this.element = null;
+ delete this.element;
+
+ fbCommandLine = null;
+ fbLargeCommandLine = null;
+ fbLargeCommandButtons = null;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ focus: function()
+ {
+ this.element.focus();
+ },
+
+ blur: function()
+ {
+ this.element.blur();
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ clear: function()
+ {
+ this.element.value = "";
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ evaluate: function(expr)
+ {
+ // TODO: need to register the API in console.firebug.commandLineAPI
+ var api = "Firebug.CommandLine.API";
+
+ var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error);
+
+ return result;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ enter: function()
+ {
+ var command = this.element.value;
+
+ if (!command) return;
+
+ _stack(command);
+
+ Firebug.Console.log(commandPrefix + " " + stripNewLines(command),
+ Firebug.browser, "command", FirebugReps.Text);
+
+ var result = this.evaluate(command);
+
+ Firebug.Console.log(result);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ prevCommand: function()
+ {
+ if (Firebug.context.persistedState.commandPointer > 0 &&
+ Firebug.context.persistedState.commandHistory.length > 0)
+ {
+ this.element.value = Firebug.context.persistedState.commandHistory
+ [--Firebug.context.persistedState.commandPointer];
+ }
+ },
+
+ nextCommand: function()
+ {
+ var element = this.element;
+
+ var limit = Firebug.context.persistedState.commandHistory.length -1;
+ var i = Firebug.context.persistedState.commandPointer;
+
+ if (i < limit)
+ element.value = Firebug.context.persistedState.commandHistory
+ [++Firebug.context.persistedState.commandPointer];
+
+ else if (i == limit)
+ {
+ ++Firebug.context.persistedState.commandPointer;
+ element.value = "";
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ autocomplete: function(reverse)
+ {
+ var element = this.element;
+
+ var command = element.value;
+ var offset = getExpressionOffset(command);
+
+ var valBegin = offset ? command.substr(0, offset) : "";
+ var val = command.substr(offset);
+
+ var buffer, obj, objName, commandBegin, result, prefix;
+
+ // if it is the beginning of the completion
+ if(!isAutoCompleting)
+ {
+
+ // group1 - command begin
+ // group2 - base object
+ // group3 - property prefix
+ var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/;
+ var r = reObj.exec(val);
+
+ // parse command
+ if (r[1] || r[2] || r[3])
+ {
+ commandBegin = r[1] || "";
+ objName = r[2] || "";
+ prefix = r[3] || "";
+ }
+ else if (val == "")
+ {
+ commandBegin = objName = prefix = "";
+ } else
+ return;
+
+ isAutoCompleting = true;
+
+ // find base object
+ if(objName == "")
+ obj = window;
+
+ else
+ {
+ objName = objName.replace(/\.$/, "");
+
+ var n = objName.split(".");
+ var target = window, o;
+
+ for (var i=0, ni; ni = n[i]; i++)
+ {
+ if (o = target[ni])
+ target = o;
+
+ else
+ {
+ target = null;
+ break;
+ }
+ }
+ obj = target;
+ }
+
+ // map base object
+ if(obj)
+ {
+ autoCompletePrefix = prefix;
+ autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : "");
+ autoCompletePosition = -1;
+
+ buffer = autoCompleteBuffer = isIE ?
+ _completion[objName || "window"] || [] : [];
+
+ for(var p in obj)
+ buffer.push(p);
+ }
+
+ // if it is the continuation of the last completion
+ } else
+ buffer = autoCompleteBuffer;
+
+ if (buffer)
+ {
+ prefix = autoCompletePrefix;
+
+ var diff = reverse ? -1 : 1;
+
+ for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i<l; i+=diff)
+ {
+ bi = buffer[i];
+
+ if (bi.indexOf(prefix) == 0)
+ {
+ autoCompletePosition = i;
+ result = bi;
+ break;
+ }
+ }
+ }
+
+ if (result)
+ element.value = autoCompleteExpr + result;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ setMultiLine: function(multiLine)
+ {
+ if (multiLine == this.isMultiLine) return;
+
+ this.activate(multiLine);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onError: function(msg, href, lineNo)
+ {
+ href = href || "";
+
+ var lastSlash = href.lastIndexOf("/");
+ var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+ var html = [
+ '<span class="errorMessage">', msg, '</span>',
+ '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+ ];
+
+ // TODO: xxxpedro ajust to Console2
+ //Firebug.Console.writeRow(html, "error");
+ },
+
+ onKeyDown: function(e)
+ {
+ e = e || event;
+
+ var code = e.keyCode;
+
+ /*tab, shift, control, alt*/
+ if (code != 9 && code != 16 && code != 17 && code != 18)
+ {
+ isAutoCompleting = false;
+ }
+
+ if (code == 13 /* enter */)
+ {
+ this.enter();
+ this.clear();
+ }
+ else if (code == 27 /* ESC */)
+ {
+ setTimeout(this.clear, 0);
+ }
+ else if (code == 38 /* up */)
+ {
+ this.prevCommand();
+ }
+ else if (code == 40 /* down */)
+ {
+ this.nextCommand();
+ }
+ else if (code == 9 /* tab */)
+ {
+ this.autocomplete(e.shiftKey);
+ }
+ else
+ return;
+
+ cancelEvent(e, true);
+ return false;
+ },
+
+ onMultiLineKeyDown: function(e)
+ {
+ e = e || event;
+
+ var code = e.keyCode;
+
+ if (code == 13 /* enter */ && e.ctrlKey)
+ {
+ this.enter();
+ }
+ }
+});
+
+Firebug.registerModule(Firebug.CommandLine);
+
+
+// ************************************************************************************************
+//
+
+function getExpressionOffset(command)
+{
+ // XXXjoe This is kind of a poor-man's JavaScript parser - trying
+ // to find the start of the expression that the cursor is inside.
+ // Not 100% fool proof, but hey...
+
+ var bracketCount = 0;
+
+ var start = command.length-1;
+ for (; start >= 0; --start)
+ {
+ var c = command[start];
+ if ((c == "," || c == ";" || c == " ") && !bracketCount)
+ break;
+ if (reOpenBracket.test(c))
+ {
+ if (bracketCount)
+ --bracketCount;
+ else
+ break;
+ }
+ else if (reCloseBracket.test(c))
+ ++bracketCount;
+ }
+
+ return start + 1;
+}
+
+// ************************************************************************************************
+// CommandLine API
+
+var CommandLineAPI =
+{
+ $: function(id)
+ {
+ return Firebug.browser.document.getElementById(id);
+ },
+
+ $$: function(selector, context)
+ {
+ context = context || Firebug.browser.document;
+ return Firebug.Selector ?
+ Firebug.Selector(selector, context) :
+ Firebug.Console.error("Firebug.Selector module not loaded.");
+ },
+
+ $0: null,
+
+ $1: null,
+
+ dir: function(o)
+ {
+ Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable);
+ },
+
+ dirxml: function(o)
+ {
+ ///if (o instanceof Window)
+ if (instanceOf(o, "Window"))
+ o = o.document.documentElement;
+ ///else if (o instanceof Document)
+ else if (instanceOf(o, "Document"))
+ o = o.documentElement;
+
+ Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement);
+ }
+};
+
+// ************************************************************************************************
+
+var defineCommandLineAPI = function defineCommandLineAPI()
+{
+ Firebug.CommandLine.API = {};
+ for (var m in CommandLineAPI)
+ if (!Env.browser.window[m])
+ Firebug.CommandLine.API[m] = CommandLineAPI[m];
+
+ var stack = FirebugChrome.htmlSelectionStack;
+ if (stack)
+ {
+ Firebug.CommandLine.API.$0 = stack[0];
+ Firebug.CommandLine.API.$1 = stack[1];
+ }
+};
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Globals
+
+var ElementCache = Firebug.Lite.Cache.Element;
+var cacheID = Firebug.Lite.Cache.ID;
+
+var ignoreHTMLProps =
+{
+ // ignores the attributes injected by Sizzle, otherwise it will
+ // be visible on IE (when enumerating element.attributes)
+ sizcache: 1,
+ sizset: 1
+};
+
+if (Firebug.ignoreFirebugElements)
+ // ignores also the cache property injected by firebug
+ ignoreHTMLProps[cacheID] = 1;
+
+
+// ************************************************************************************************
+// HTML Module
+
+Firebug.HTML = extend(Firebug.Module,
+{
+ appendTreeNode: function(nodeArray, html)
+ {
+ var reTrim = /^\s+|\s+$/g;
+
+ if (!nodeArray.length) nodeArray = [nodeArray];
+
+ for (var n=0, node; node=nodeArray[n]; n++)
+ {
+ if (node.nodeType == 1)
+ {
+ if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue;
+
+ var uid = ElementCache(node);
+ var child = node.childNodes;
+ var childLength = child.length;
+
+ var nodeName = node.nodeName.toLowerCase();
+
+ var nodeVisible = isVisible(node);
+
+ var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 &&
+ nodeName != "script" && nodeName != "style";
+
+ var nodeControl = !hasSingleTextChild && childLength > 0 ?
+ ('<div class="nodeControl"></div>') : '';
+
+ // FIXME xxxpedro remove this
+ //var isIE = false;
+
+ if(isIE && nodeControl)
+ html.push(nodeControl);
+
+ if (typeof uid != 'undefined')
+ html.push(
+ '<div class="objectBox-element" ',
+ 'id="', uid,
+ '">',
+ !isIE && nodeControl ? nodeControl: "",
+ '<span ',
+ cacheID,
+ '="', uid,
+ '" class="nodeBox',
+ nodeVisible ? "" : " nodeHidden",
+ '">&lt;<span class="nodeTag">', nodeName, '</span>'
+ );
+ else
+ html.push(
+ '<div class="objectBox-element"><span class="nodeBox',
+ nodeVisible ? "" : " nodeHidden",
+ '">&lt;<span class="nodeTag">',
+ nodeName, '</span>'
+ );
+
+ for (var i = 0; i < node.attributes.length; ++i)
+ {
+ var attr = node.attributes[i];
+ if (!attr.specified ||
+ // Issue 4432: Firebug Lite: HTML is mixed-up with functions
+ // The problem here is that expando properties added to DOM elements in
+ // IE < 9 will behave like DOM attributes and so they'll show up when
+ // looking at element.attributes list.
+ isIE && (browserVersion-0<9) && typeof attr.nodeValue != "string" ||
+ Firebug.ignoreFirebugElements && ignoreHTMLProps.hasOwnProperty(attr.nodeName))
+ continue;
+
+ var name = attr.nodeName.toLowerCase();
+ var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue;
+
+ html.push('&nbsp;<span class="nodeName">', name,
+ '</span>=&quot;<span class="nodeValue">', escapeHTML(value),
+ '</span>&quot;');
+ }
+
+ /*
+ // source code nodes
+ if (nodeName == 'script' || nodeName == 'style')
+ {
+
+ if(document.all){
+ var src = node.innerHTML+'\n';
+
+ }else {
+ var src = '\n'+node.innerHTML+'\n';
+ }
+
+ var match = src.match(/\n/g);
+ var num = match ? match.length : 0;
+ var s = [], sl = 0;
+
+ for(var c=1; c<num; c++){
+ s[sl++] = '<div line="'+c+'">' + c + '</div>';
+ }
+
+ html.push('&gt;</div><div class="nodeGroup"><div class="nodeChildren"><div class="lineNo">',
+ s.join(''),
+ '</div><pre class="nodeCode">',
+ escapeHTML(src),
+ '</pre>',
+ '</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
+ nodeName,
+ '</span>&gt;</div>',
+ '</div>'
+ );
+
+
+ }/**/
+
+ // Just a single text node child
+ if (hasSingleTextChild)
+ {
+ var value = child[0].nodeValue.replace(reTrim, '');
+ if(value)
+ {
+ html.push(
+ '&gt;<span class="nodeText">',
+ escapeHTML(value),
+ '</span>&lt;/<span class="nodeTag">',
+ nodeName,
+ '</span>&gt;</span></div>'
+ );
+ }
+ else
+ html.push('/&gt;</span></div>'); // blank text, print as childless node
+
+ }
+ else if (childLength > 0)
+ {
+ html.push('&gt;</span></div>');
+ }
+ else
+ html.push('/&gt;</span></div>');
+
+ }
+ else if (node.nodeType == 3)
+ {
+ if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" ||
+ node.parentNode.nodeName.toLowerCase() == "style" ) )
+ {
+ var value = node.nodeValue.replace(reTrim, '');
+
+ if(isIE){
+ var src = value+'\n';
+
+ }else {
+ var src = '\n'+value+'\n';
+ }
+
+ var match = src.match(/\n/g);
+ var num = match ? match.length : 0;
+ var s = [], sl = 0;
+
+ for(var c=1; c<num; c++){
+ s[sl++] = '<div line="'+c+'">' + c + '</div>';
+ }
+
+ html.push('<div class="lineNo">',
+ s.join(''),
+ '</div><pre class="sourceCode">',
+ escapeHTML(src),
+ '</pre>'
+ );
+
+ }
+ else
+ {
+ var value = node.nodeValue.replace(reTrim, '');
+ if (value)
+ html.push('<div class="nodeText">', escapeHTML(value),'</div>');
+ }
+ }
+ }
+ },
+
+ appendTreeChildren: function(treeNode)
+ {
+ var doc = Firebug.chrome.document;
+ var uid = treeNode.id;
+ var parentNode = ElementCache.get(uid);
+
+ if (parentNode.childNodes.length == 0) return;
+
+ var treeNext = treeNode.nextSibling;
+ var treeParent = treeNode.parentNode;
+
+ // FIXME xxxpedro remove this
+ //var isIE = false;
+ var control = isIE ? treeNode.previousSibling : treeNode.firstChild;
+ control.className = 'nodeControl nodeMaximized';
+
+ var html = [];
+ var children = doc.createElement("div");
+ children.className = "nodeChildren";
+ this.appendTreeNode(parentNode.childNodes, html);
+ children.innerHTML = html.join("");
+
+ treeParent.insertBefore(children, treeNext);
+
+ var closeElement = doc.createElement("div");
+ closeElement.className = "objectBox-element";
+ closeElement.innerHTML = '&lt;/<span class="nodeTag">' +
+ parentNode.nodeName.toLowerCase() + '&gt;</span>';
+
+ treeParent.insertBefore(closeElement, treeNext);
+
+ },
+
+ removeTreeChildren: function(treeNode)
+ {
+ var children = treeNode.nextSibling;
+ var closeTag = children.nextSibling;
+
+ // FIXME xxxpedro remove this
+ //var isIE = false;
+ var control = isIE ? treeNode.previousSibling : treeNode.firstChild;
+ control.className = 'nodeControl';
+
+ children.parentNode.removeChild(children);
+ closeTag.parentNode.removeChild(closeTag);
+ },
+
+ isTreeNodeVisible: function(id)
+ {
+ return $(id);
+ },
+
+ select: function(el)
+ {
+ var id = el && ElementCache(el);
+ if (id)
+ this.selectTreeNode(id);
+ },
+
+ selectTreeNode: function(id)
+ {
+ id = ""+id;
+ var node, stack = [];
+ while(id && !this.isTreeNodeVisible(id))
+ {
+ stack.push(id);
+
+ var node = ElementCache.get(id).parentNode;
+
+ if (node)
+ id = ElementCache(node);
+ else
+ break;
+ }
+
+ stack.push(id);
+
+ while(stack.length > 0)
+ {
+ id = stack.pop();
+ node = $(id);
+
+ if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0)
+ this.appendTreeChildren(node);
+ }
+
+ selectElement(node);
+
+ // TODO: xxxpedro
+ if (fbPanel1)
+ fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2);
+ }
+
+});
+
+Firebug.registerModule(Firebug.HTML);
+
+// ************************************************************************************************
+// HTML Panel
+
+function HTMLPanel(){};
+
+HTMLPanel.prototype = extend(Firebug.Panel,
+{
+ name: "HTML",
+ title: "HTML",
+
+ options: {
+ hasSidePanel: true,
+ //hasToolButtons: true,
+ isPreRendered: !Firebug.flexChromeEnabled /* FIXME xxxpedro chromenew */,
+ innerHTMLSync: true
+ },
+
+ create: function(){
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.panelNode.style.padding = "4px 3px 1px 15px";
+ this.panelNode.style.minWidth = "500px";
+
+ if (Env.Options.enablePersistent || Firebug.chrome.type != "popup")
+ this.createUI();
+
+ if(this.sidePanelBar && !this.sidePanelBar.selectedPanel)
+ {
+ this.sidePanelBar.selectPanel("css");
+ }
+ },
+
+ destroy: function()
+ {
+ selectedElement = null;
+ fbPanel1 = null;
+
+ selectedSidePanelTS = null;
+ selectedSidePanelTimer = null;
+
+ Firebug.Panel.destroy.apply(this, arguments);
+ },
+
+ createUI: function()
+ {
+ var rootNode = Firebug.browser.document.documentElement;
+ var html = [];
+ Firebug.HTML.appendTreeNode(rootNode, html);
+
+ this.panelNode.innerHTML = html.join("");
+ },
+
+ initialize: function()
+ {
+ Firebug.Panel.initialize.apply(this, arguments);
+ addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick);
+
+ fbPanel1 = $("fbPanel1");
+
+ if(!selectedElement)
+ {
+ Firebug.context.persistedState.selectedHTMLElementId =
+ Firebug.context.persistedState.selectedHTMLElementId &&
+ ElementCache.get(Firebug.context.persistedState.selectedHTMLElementId) ?
+ Firebug.context.persistedState.selectedHTMLElementId :
+ ElementCache(Firebug.browser.document.body);
+
+ Firebug.HTML.selectTreeNode(Firebug.context.persistedState.selectedHTMLElementId);
+ }
+
+ // TODO: xxxpedro
+ addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove);
+ addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove);
+ addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove);
+ },
+
+ shutdown: function()
+ {
+ // TODO: xxxpedro
+ removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove);
+ removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove);
+ removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove);
+
+ removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick);
+
+ fbPanel1 = null;
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+ },
+
+ reattach: function()
+ {
+ // TODO: panel reattach
+ if(Firebug.context.persistedState.selectedHTMLElementId)
+ Firebug.HTML.selectTreeNode(Firebug.context.persistedState.selectedHTMLElementId);
+ },
+
+ updateSelection: function(object)
+ {
+ var id = ElementCache(object);
+
+ if (id)
+ {
+ Firebug.HTML.selectTreeNode(id);
+ }
+ }
+});
+
+Firebug.registerPanel(HTMLPanel);
+
+// ************************************************************************************************
+
+var formatStyles = function(styles)
+{
+ return isIE ?
+ // IE return CSS property names in upper case, so we need to convert them
+ styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":";}) :
+ // other browsers are just fine
+ styles;
+};
+
+// ************************************************************************************************
+
+var selectedElement = null;
+var fbPanel1 = null;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+var selectedSidePanelTS, selectedSidePanelTimer;
+
+var selectElement= function selectElement(e)
+{
+ if (e != selectedElement)
+ {
+ if (selectedElement)
+ selectedElement.className = "objectBox-element";
+
+ e.className = e.className + " selectedElement";
+
+ if (FBL.isFirefox)
+ e.style.MozBorderRadius = "2px";
+
+ else if (FBL.isSafari)
+ e.style.WebkitBorderRadius = "2px";
+
+ e.style.borderRadius = "2px";
+
+ selectedElement = e;
+
+ Firebug.context.persistedState.selectedHTMLElementId = e.id;
+
+ var target = ElementCache.get(e.id);
+ var sidePanelBar = Firebug.chrome.getPanel("HTML").sidePanelBar;
+ var selectedSidePanel = sidePanelBar ? sidePanelBar.selectedPanel : null;
+
+ var stack = FirebugChrome.htmlSelectionStack;
+
+ stack.unshift(target);
+
+ if (stack.length > 2)
+ stack.pop();
+
+ var lazySelect = function()
+ {
+ selectedSidePanelTS = new Date().getTime();
+
+ if (selectedSidePanel)
+ selectedSidePanel.select(target, true);
+ };
+
+ if (selectedSidePanelTimer)
+ {
+ clearTimeout(selectedSidePanelTimer);
+ selectedSidePanelTimer = null;
+ }
+
+ if (new Date().getTime() - selectedSidePanelTS > 100)
+ setTimeout(lazySelect, 0);
+ else
+ selectedSidePanelTimer = setTimeout(lazySelect, 150);
+ }
+};
+
+
+// ************************************************************************************************
+// *** TODO: REFACTOR **************************************************************************
+// ************************************************************************************************
+Firebug.HTML.onTreeClick = function (e)
+{
+ e = e || event;
+ var targ;
+
+ if (e.target) targ = e.target;
+ else if (e.srcElement) targ = e.srcElement;
+ if (targ.nodeType == 3) // defeat Safari bug
+ targ = targ.parentNode;
+
+
+ if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag')
+ {
+ // FIXME xxxpedro remove this
+ //var isIE = false;
+
+ if(targ.className == 'nodeTag')
+ {
+ var control = isIE ? (targ.parentNode.previousSibling || targ) :
+ (targ.parentNode.previousSibling || targ);
+
+ selectElement(targ.parentNode.parentNode);
+
+ if (control.className.indexOf('nodeControl') == -1)
+ return;
+
+ } else
+ control = targ;
+
+ FBL.cancelEvent(e);
+
+ var treeNode = isIE ? control.nextSibling : control.parentNode;
+
+ //FBL.Firebug.Console.log(treeNode);
+
+ if (control.className.indexOf(' nodeMaximized') != -1) {
+ FBL.Firebug.HTML.removeTreeChildren(treeNode);
+ } else {
+ FBL.Firebug.HTML.appendTreeChildren(treeNode);
+ }
+ }
+ else if (targ.className == 'nodeValue' || targ.className == 'nodeName')
+ {
+ /*
+ var input = FBL.Firebug.chrome.document.getElementById('treeInput');
+
+ input.style.display = "block";
+ input.style.left = targ.offsetLeft + 'px';
+ input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px';
+ input.style.width = targ.offsetWidth + 6 + 'px';
+ input.value = targ.textContent || targ.innerText;
+ input.focus();
+ /**/
+ }
+};
+
+function onListMouseOut(e)
+{
+ e = e || event || window;
+ var targ;
+
+ if (e.target) targ = e.target;
+ else if (e.srcElement) targ = e.srcElement;
+ if (targ.nodeType == 3) // defeat Safari bug
+ targ = targ.parentNode;
+
+ if (hasClass(targ, "fbPanel")) {
+ FBL.Firebug.Inspector.hideBoxModel();
+ hoverElement = null;
+ }
+};
+
+var hoverElement = null;
+var hoverElementTS = 0;
+
+Firebug.HTML.onListMouseMove = function onListMouseMove(e)
+{
+ try
+ {
+ e = e || event || window;
+ var targ;
+
+ if (e.target) targ = e.target;
+ else if (e.srcElement) targ = e.srcElement;
+ if (targ.nodeType == 3) // defeat Safari bug
+ targ = targ.parentNode;
+
+ var found = false;
+ while (targ && !found) {
+ if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " "))
+ targ = targ.parentNode;
+ else
+ found = true;
+ }
+
+ if (!targ)
+ {
+ FBL.Firebug.Inspector.hideBoxModel();
+ hoverElement = null;
+ return;
+ }
+
+ /*
+ if (typeof targ.attributes[cacheID] == 'undefined') return;
+
+ var uid = targ.attributes[cacheID];
+ if (!uid) return;
+ /**/
+
+ if (typeof targ.attributes[cacheID] == 'undefined') return;
+
+ var uid = targ.attributes[cacheID];
+ if (!uid) return;
+
+ var el = ElementCache.get(uid.value);
+
+ var nodeName = el.nodeName.toLowerCase();
+
+ if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1)
+ return;
+
+ if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return;
+
+ if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) {
+ FBL.Firebug.Inspector.hideBoxModel();
+ hoverElement = null;
+ return;
+ }
+
+ if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) {
+ hoverElementTS = new Date().getTime();
+ hoverElement = el;
+ FBL.Firebug.Inspector.drawBoxModel(el);
+ }
+ }
+ catch(E)
+ {
+ }
+};
+
+
+// ************************************************************************************************
+
+Firebug.Reps = {
+
+ appendText: function(object, html)
+ {
+ html.push(escapeHTML(objectToString(object)));
+ },
+
+ appendNull: function(object, html)
+ {
+ html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+ },
+
+ appendString: function(object, html)
+ {
+ html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+ '&quot;</span>');
+ },
+
+ appendInteger: function(object, html)
+ {
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ },
+
+ appendFloat: function(object, html)
+ {
+ html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+ },
+
+ appendFunction: function(object, html)
+ {
+ var reName = /function ?(.*?)\(/;
+ var m = reName.exec(objectToString(object));
+ var name = m && m[1] ? m[1] : "function";
+ html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
+ },
+
+ appendObject: function(object, html)
+ {
+ /*
+ var rep = Firebug.getRep(object);
+ var outputs = [];
+
+ rep.tag.tag.compile();
+
+ var str = rep.tag.renderHTML({object: object}, outputs);
+ html.push(str);
+ /**/
+
+ try
+ {
+ if (object == undefined)
+ this.appendNull("undefined", html);
+ else if (object == null)
+ this.appendNull("null", html);
+ else if (typeof object == "string")
+ this.appendString(object, html);
+ else if (typeof object == "number")
+ this.appendInteger(object, html);
+ else if (typeof object == "boolean")
+ this.appendInteger(object, html);
+ else if (typeof object == "function")
+ this.appendFunction(object, html);
+ else if (object.nodeType == 1)
+ this.appendSelector(object, html);
+ else if (typeof object == "object")
+ {
+ if (typeof object.length != "undefined")
+ this.appendArray(object, html);
+ else
+ this.appendObjectFormatted(object, html);
+ }
+ else
+ this.appendText(object, html);
+ }
+ catch (exc)
+ {
+ }
+ /**/
+ },
+
+ appendObjectFormatted: function(object, html)
+ {
+ var text = objectToString(object);
+ var reObject = /\[object (.*?)\]/;
+
+ var m = reObject.exec(text);
+ html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>');
+ },
+
+ appendSelector: function(object, html)
+ {
+ var uid = ElementCache(object);
+ var uidString = uid ? [cacheID, '="', uid, '"'].join("") : "";
+
+ html.push('<span class="objectBox-selector"', uidString, '>');
+
+ html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+ if (object.id)
+ html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+ if (object.className)
+ html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+
+ html.push('</span>');
+ },
+
+ appendNode: function(node, html)
+ {
+ if (node.nodeType == 1)
+ {
+ var uid = ElementCache(node);
+ var uidString = uid ? [cacheID, '="', uid, '"'].join("") : "";
+
+ html.push(
+ '<div class="objectBox-element"', uidString, '">',
+ '<span ', cacheID, '="', uid, '" class="nodeBox">',
+ '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+
+ for (var i = 0; i < node.attributes.length; ++i)
+ {
+ var attr = node.attributes[i];
+ if (!attr.specified || attr.nodeName == cacheID)
+ continue;
+
+ var name = attr.nodeName.toLowerCase();
+ var value = name == "style" ? node.style.cssText : attr.nodeValue;
+
+ html.push('&nbsp;<span class="nodeName">', name,
+ '</span>=&quot;<span class="nodeValue">', escapeHTML(value),
+ '</span>&quot;');
+ }
+
+ if (node.firstChild)
+ {
+ html.push('&gt;</div><div class="nodeChildren">');
+
+ for (var child = node.firstChild; child; child = child.nextSibling)
+ this.appendNode(child, html);
+
+ html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
+ node.nodeName.toLowerCase(), '&gt;</span></span></div>');
+ }
+ else
+ html.push('/&gt;</span></div>');
+ }
+ else if (node.nodeType == 3)
+ {
+ var value = trim(node.nodeValue);
+ if (value)
+ html.push('<div class="nodeText">', escapeHTML(value),'</div>');
+ }
+ },
+
+ appendArray: function(object, html)
+ {
+ html.push('<span class="objectBox-array"><b>[</b> ');
+
+ for (var i = 0, l = object.length, obj; i < l; ++i)
+ {
+ this.appendObject(object[i], html);
+
+ if (i < l-1)
+ html.push(', ');
+ }
+
+ html.push(' <b>]</b></span>');
+ }
+
+};
+
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+/*
+
+Hack:
+Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel;
+Firebug.showInfoTips = true;
+Firebug.InfoTip.initializeBrowser(Firebug.chrome);
+
+/**/
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// Constants
+
+var maxWidth = 100, maxHeight = 80;
+var infoTipMargin = 10;
+var infoTipWindowPadding = 25;
+
+// ************************************************************************************************
+
+Firebug.InfoTip = extend(Firebug.Module,
+{
+ dispatchName: "infoTip",
+ tags: domplate(
+ {
+ infoTipTag: DIV({"class": "infoTip"}),
+
+ colorTag:
+ DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, "&nbsp;"),
+
+ imgTag:
+ DIV({"class": "infoTipImageBox infoTipLoading"},
+ IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat",
+ onload: "$onLoadImage"}),
+ IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}),
+ DIV({"class": "infoTipCaption"})
+ ),
+
+ onLoadImage: function(event)
+ {
+ var img = event.currentTarget || event.srcElement;
+ ///var bgImg = img.nextSibling;
+ ///if (!bgImg)
+ /// return; // Sometimes gets called after element is dead
+
+ ///var caption = bgImg.nextSibling;
+ var innerBox = img.parentNode;
+
+ /// TODO: xxxpedro infoTip hack
+ var caption = getElementByClass(innerBox, "infoTipCaption");
+ var bgImg = getElementByClass(innerBox, "infoTipBgImage");
+ if (!bgImg)
+ return; // Sometimes gets called after element is dead
+
+ // TODO: xxxpedro infoTip IE and timing issue
+ // TODO: use offline document to avoid flickering
+ if (isIE)
+ removeClass(innerBox, "infoTipLoading");
+
+ var updateInfoTip = function(){
+
+ var w = img.naturalWidth || img.width || 10,
+ h = img.naturalHeight || img.height || 10;
+
+ var repeat = img.getAttribute("repeat");
+
+ if (repeat == "repeat-x" || (w == 1 && h > 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat-x";
+ bgImg.style.width = maxWidth + "px";
+ if (h > maxHeight)
+ bgImg.style.height = maxHeight + "px";
+ else
+ bgImg.style.height = h + "px";
+ }
+ else if (repeat == "repeat-y" || (h == 1 && w > 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat-y";
+ bgImg.style.height = maxHeight + "px";
+ if (w > maxWidth)
+ bgImg.style.width = maxWidth + "px";
+ else
+ bgImg.style.width = w + "px";
+ }
+ else if (repeat == "repeat" || (w == 1 && h == 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat";
+ bgImg.style.width = maxWidth + "px";
+ bgImg.style.height = maxHeight + "px";
+ }
+ else
+ {
+ if (w > maxWidth || h > maxHeight)
+ {
+ if (w > h)
+ {
+ img.style.width = maxWidth + "px";
+ img.style.height = Math.round((h / w) * maxWidth) + "px";
+ }
+ else
+ {
+ img.style.width = Math.round((w / h) * maxHeight) + "px";
+ img.style.height = maxHeight + "px";
+ }
+ }
+ }
+
+ //caption.innerHTML = $STRF("Dimensions", [w, h]);
+ caption.innerHTML = $STRF(w + " x " + h);
+
+
+ };
+
+ if (isIE)
+ setTimeout(updateInfoTip, 0);
+ else
+ {
+ updateInfoTip();
+ removeClass(innerBox, "infoTipLoading");
+ }
+
+ ///
+ }
+
+ /*
+ /// onLoadImage original
+ onLoadImage: function(event)
+ {
+ var img = event.currentTarget;
+ var bgImg = img.nextSibling;
+ if (!bgImg)
+ return; // Sometimes gets called after element is dead
+
+ var caption = bgImg.nextSibling;
+ var innerBox = img.parentNode;
+
+ var w = img.naturalWidth, h = img.naturalHeight;
+ var repeat = img.getAttribute("repeat");
+
+ if (repeat == "repeat-x" || (w == 1 && h > 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat-x";
+ bgImg.style.width = maxWidth + "px";
+ if (h > maxHeight)
+ bgImg.style.height = maxHeight + "px";
+ else
+ bgImg.style.height = h + "px";
+ }
+ else if (repeat == "repeat-y" || (h == 1 && w > 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat-y";
+ bgImg.style.height = maxHeight + "px";
+ if (w > maxWidth)
+ bgImg.style.width = maxWidth + "px";
+ else
+ bgImg.style.width = w + "px";
+ }
+ else if (repeat == "repeat" || (w == 1 && h == 1))
+ {
+ collapse(img, true);
+ collapse(bgImg, false);
+ bgImg.style.background = "url(" + img.src + ") repeat";
+ bgImg.style.width = maxWidth + "px";
+ bgImg.style.height = maxHeight + "px";
+ }
+ else
+ {
+ if (w > maxWidth || h > maxHeight)
+ {
+ if (w > h)
+ {
+ img.style.width = maxWidth + "px";
+ img.style.height = Math.round((h / w) * maxWidth) + "px";
+ }
+ else
+ {
+ img.style.width = Math.round((w / h) * maxHeight) + "px";
+ img.style.height = maxHeight + "px";
+ }
+ }
+ }
+
+ caption.innerHTML = $STRF("Dimensions", [w, h]);
+
+ removeClass(innerBox, "infoTipLoading");
+ }
+ /**/
+
+ }),
+
+ initializeBrowser: function(browser)
+ {
+ browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser);
+ browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser);
+
+ ///var doc = browser.contentDocument;
+ var doc = browser.document;
+ if (!doc)
+ return;
+
+ ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true);
+ ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true);
+ ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true);
+ addEvent(doc, "mouseover", browser.onInfoTipMouseMove);
+ addEvent(doc, "mouseout", browser.onInfoTipMouseOut);
+ addEvent(doc, "mousemove", browser.onInfoTipMouseMove);
+
+ return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc));
+ },
+
+ uninitializeBrowser: function(browser)
+ {
+ if (browser.infoTip)
+ {
+ ///var doc = browser.contentDocument;
+ var doc = browser.document;
+ ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true);
+ ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true);
+ ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true);
+ removeEvent(doc, "mouseover", browser.onInfoTipMouseMove);
+ removeEvent(doc, "mouseout", browser.onInfoTipMouseOut);
+ removeEvent(doc, "mousemove", browser.onInfoTipMouseMove);
+
+ browser.infoTip.parentNode.removeChild(browser.infoTip);
+ delete browser.infoTip;
+ delete browser.onInfoTipMouseMove;
+ }
+ },
+
+ showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset)
+ {
+ if (!Firebug.showInfoTips)
+ return;
+
+ var scrollParent = getOverflowParent(target);
+ var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0);
+
+ if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset))
+ {
+ var htmlElt = infoTip.ownerDocument.documentElement;
+ var panelWidth = htmlElt.clientWidth;
+ var panelHeight = htmlElt.clientHeight;
+
+ if (x+infoTip.offsetWidth+infoTipMargin > panelWidth)
+ {
+ infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px";
+ infoTip.style.right = "auto";
+ }
+ else
+ {
+ infoTip.style.left = (x+infoTipMargin) + "px";
+ infoTip.style.right = "auto";
+ }
+
+ if (y+infoTip.offsetHeight+infoTipMargin > panelHeight)
+ {
+ infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px";
+ infoTip.style.bottom = "auto";
+ }
+ else
+ {
+ infoTip.style.top = (y+infoTipMargin) + "px";
+ infoTip.style.bottom = "auto";
+ }
+
+ if (FBTrace.DBG_INFOTIP)
+ FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top +
+ ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom +
+ ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight +
+ ", offsetWidth: " + infoTip.offsetWidth +
+ ", x: " + x + ", panelWidth: " + panelWidth +
+ ", y: " + y + ", panelHeight: " + panelHeight);
+
+ infoTip.setAttribute("active", "true");
+ }
+ else
+ this.hideInfoTip(infoTip);
+ },
+
+ hideInfoTip: function(infoTip)
+ {
+ if (infoTip)
+ infoTip.removeAttribute("active");
+ },
+
+ onMouseOut: function(event, browser)
+ {
+ if (!event.relatedTarget)
+ this.hideInfoTip(browser.infoTip);
+ },
+
+ onMouseMove: function(event, browser)
+ {
+ // Ignore if the mouse is moving over the existing info tip.
+ if (getAncestorByClass(event.target, "infoTip"))
+ return;
+
+ if (browser.currentPanel)
+ {
+ var x = event.clientX, y = event.clientY, target = event.target || event.srcElement;
+ this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset);
+ }
+ else
+ this.hideInfoTip(browser.infoTip);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ populateColorInfoTip: function(infoTip, color)
+ {
+ this.tags.colorTag.replace({rgbValue: color}, infoTip);
+ return true;
+ },
+
+ populateImageInfoTip: function(infoTip, url, repeat)
+ {
+ if (!repeat)
+ repeat = "no-repeat";
+
+ this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip);
+
+ return true;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Module
+
+ disable: function()
+ {
+ // XXXjoe For each browser, call uninitializeBrowser
+ },
+
+ showPanel: function(browser, panel)
+ {
+ if (panel)
+ {
+ var infoTip = panel.panelBrowser.infoTip;
+ if (!infoTip)
+ infoTip = this.initializeBrowser(panel.panelBrowser);
+ this.hideInfoTip(infoTip);
+ }
+
+ },
+
+ showSidePanel: function(browser, panel)
+ {
+ this.showPanel(browser, panel);
+ }
+});
+
+// ************************************************************************************************
+
+Firebug.registerModule(Firebug.InfoTip);
+
+// ************************************************************************************************
+
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+var CssParser = null;
+
+// ************************************************************************************************
+
+// Simple CSS stylesheet parser from:
+// https://github.com/sergeche/webkit-css
+
+/**
+ * Simple CSS stylesheet parser that remembers rule's lines in file
+ * @author Sergey Chikuyonok (serge.che@gmail.com)
+ * @link http://chikuyonok.ru
+ */
+CssParser = (function(){
+ /**
+ * Returns rule object
+ * @param {Number} start Character index where CSS rule definition starts
+ * @param {Number} body_start Character index where CSS rule's body starts
+ * @param {Number} end Character index where CSS rule definition ends
+ */
+ function rule(start, body_start, end) {
+ return {
+ start: start || 0,
+ body_start: body_start || 0,
+ end: end || 0,
+ line: -1,
+ selector: null,
+ parent: null,
+
+ /** @type {rule[]} */
+ children: [],
+
+ addChild: function(start, body_start, end) {
+ var r = rule(start, body_start, end);
+ r.parent = this;
+ this.children.push(r);
+ return r;
+ },
+ /**
+ * Returns last child element
+ * @return {rule}
+ */
+ lastChild: function() {
+ return this.children[this.children.length - 1];
+ }
+ };
+ }
+
+ /**
+ * Replaces all occurances of substring defined by regexp
+ * @param {String} str
+ * @return {RegExp} re
+ * @return {String}
+ */
+ function removeAll(str, re) {
+ var m;
+ while (m = str.match(re)) {
+ str = str.substring(m[0].length);
+ }
+
+ return str;
+ }
+
+ /**
+ * Trims whitespace from the beginning and the end of string
+ * @param {String} str
+ * @return {String}
+ */
+ function trim(str) {
+ return str.replace(/^\s+|\s+$/g, '');
+ }
+
+ /**
+ * Normalizes CSS rules selector
+ * @param {String} selector
+ */
+ function normalizeSelector(selector) {
+ // remove newlines
+ selector = selector.replace(/[\n\r]/g, ' ');
+
+ selector = trim(selector);
+
+ // remove spaces after commas
+ selector = selector.replace(/\s*,\s*/g, ',');
+
+ return selector;
+ }
+
+ /**
+ * Preprocesses parsed rules: adjusts char indexes, skipping whitespace and
+ * newlines, saves rule selector, removes comments, etc.
+ * @param {String} text CSS stylesheet
+ * @param {rule} rule_node CSS rule node
+ * @return {rule[]}
+ */
+ function preprocessRules(text, rule_node) {
+ for (var i = 0, il = rule_node.children.length; i < il; i++) {
+ var r = rule_node.children[i],
+ rule_start = text.substring(r.start, r.body_start),
+ cur_len = rule_start.length;
+
+ // remove newlines for better regexp matching
+ rule_start = rule_start.replace(/[\n\r]/g, ' ');
+
+ // remove @import rules
+// rule_start = removeAll(rule_start, /^\s*@import\s*url\((['"])?.+?\1?\)\;?/g);
+
+ // remove comments
+ rule_start = removeAll(rule_start, /^\s*\/\*.*?\*\/[\s\t]*/);
+
+ // remove whitespace
+ rule_start = rule_start.replace(/^[\s\t]+/, '');
+
+ r.start += (cur_len - rule_start.length);
+ r.selector = normalizeSelector(rule_start);
+ }
+
+ return rule_node;
+ }
+
+ /**
+ * Saves all lise starting indexes for faster search
+ * @param {String} text CSS stylesheet
+ * @return {Number[]}
+ */
+ function saveLineIndexes(text) {
+ var result = [0],
+ i = 0,
+ il = text.length,
+ ch, ch2;
+
+ while (i < il) {
+ ch = text.charAt(i);
+
+ if (ch == '\n' || ch == '\r') {
+ if (ch == '\r' && i < il - 1 && text.charAt(i + 1) == '\n') {
+ // windows line ending: CRLF. Skip next character
+ i++;
+ }
+
+ result.push(i + 1);
+ }
+
+ i++;
+ }
+
+ return result;
+ }
+
+ /**
+ * Saves line number for parsed rules
+ * @param {String} text CSS stylesheet
+ * @param {rule} rule_node Rule node
+ * @return {rule[]}
+ */
+ function saveLineNumbers(text, rule_node, line_indexes, startLine) {
+ preprocessRules(text, rule_node);
+
+ startLine = startLine || 0;
+
+ // remember lines start indexes, preserving line ending characters
+ if (!line_indexes)
+ var line_indexes = saveLineIndexes(text);
+
+ // now find each rule's line
+ for (var i = 0, il = rule_node.children.length; i < il; i++) {
+ var r = rule_node.children[i];
+ r.line = line_indexes.length + startLine;
+ for (var j = 0, jl = line_indexes.length - 1; j < jl; j++) {
+ var line_ix = line_indexes[j];
+ if (r.start >= line_indexes[j] && r.start < line_indexes[j + 1]) {
+ r.line = j + 1 + startLine;
+ break;
+ }
+ }
+
+ saveLineNumbers(text, r, line_indexes);
+ }
+
+ return rule_node;
+ }
+
+ return {
+ /**
+ * Parses text as CSS stylesheet, remembring each rule position inside
+ * text
+ * @param {String} text CSS stylesheet to parse
+ */
+ read: function(text, startLine) {
+ var rule_start = [],
+ rule_body_start = [],
+ rules = [],
+ in_comment = 0,
+ root = rule(),
+ cur_parent = root,
+ last_rule = null,
+ stack = [],
+ ch, ch2;
+
+ stack.last = function() {
+ return this[this.length - 1];
+ };
+
+ function hasStr(pos, substr) {
+ return text.substr(pos, substr.length) == substr;
+ }
+
+ for (var i = 0, il = text.length; i < il; i++) {
+ ch = text.charAt(i);
+ ch2 = i < il - 1 ? text.charAt(i + 1) : '';
+
+ if (!rule_start.length)
+ rule_start.push(i);
+
+ switch (ch) {
+ case '@':
+ if (!in_comment) {
+ if (hasStr(i, '@import')) {
+ var m = text.substr(i).match(/^@import\s*url\((['"])?.+?\1?\)\;?/);
+ if (m) {
+ cur_parent.addChild(i, i + 7, i + m[0].length);
+ i += m[0].length;
+ rule_start.pop();
+ }
+ break;
+ }
+ }
+ case '/':
+ // xxxpedro allowing comment inside comment
+ if (!in_comment && ch2 == '*') { // comment start
+ in_comment++;
+ }
+ break;
+
+ case '*':
+ if (ch2 == '/') { // comment end
+ in_comment--;
+ }
+ break;
+
+ case '{':
+ if (!in_comment) {
+ rule_body_start.push(i);
+
+ cur_parent = cur_parent.addChild(rule_start.pop());
+ stack.push(cur_parent);
+ }
+ break;
+
+ case '}':
+ // found the end of the rule
+ if (!in_comment) {
+ /** @type {rule} */
+ var last_rule = stack.pop();
+ rule_start.pop();
+ last_rule.body_start = rule_body_start.pop();
+ last_rule.end = i;
+ cur_parent = last_rule.parent || root;
+ }
+ break;
+ }
+
+ }
+
+ return saveLineNumbers(text, root, null, startLine);
+ },
+
+ normalizeSelector: normalizeSelector,
+
+ /**
+ * Find matched rule by selector.
+ * @param {rule} rule_node Parsed rule node
+ * @param {String} selector CSS selector
+ * @param {String} source CSS stylesheet source code
+ *
+ * @return {rule[]|null} Array of matched rules, sorted by priority (most
+ * recent on top)
+ */
+ findBySelector: function(rule_node, selector, source) {
+ var selector = normalizeSelector(selector),
+ result = [];
+
+ if (rule_node) {
+ for (var i = 0, il = rule_node.children.length; i < il; i++) {
+ /** @type {rule} */
+ var r = rule_node.children[i];
+ if (r.selector == selector) {
+ result.push(r);
+ }
+ }
+ }
+
+ if (result.length) {
+ return result;
+ } else {
+ return null;
+ }
+ }
+ };
+})();
+
+
+// ************************************************************************************************
+
+FBL.CssParser = CssParser;
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// StyleSheet Parser
+
+var CssAnalyzer = {};
+
+// ************************************************************************************************
+// Locals
+
+var CSSRuleMap = {};
+var ElementCSSRulesMap = {};
+
+var internalStyleSheetIndex = -1;
+
+var reSelectorTag = /(^|\s)(?:\w+)/g;
+var reSelectorClass = /\.[\w\d_-]+/g;
+var reSelectorId = /#[\w\d_-]+/g;
+
+var globalCSSRuleIndex;
+
+var processAllStyleSheetsTimeout = null;
+
+var externalStyleSheetURLs = [];
+
+var ElementCache = Firebug.Lite.Cache.Element;
+var StyleSheetCache = Firebug.Lite.Cache.StyleSheet;
+
+//************************************************************************************************
+// CSS Analyzer templates
+
+CssAnalyzer.externalStyleSheetWarning = domplate(Firebug.Rep,
+{
+ tag:
+ DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'},
+ SPAN("$object|STR"),
+ A({"href": "$href", target:"_blank"}, "$link|STR")
+ )
+});
+
+// ************************************************************************************************
+// CSS Analyzer methods
+
+CssAnalyzer.processAllStyleSheets = function(doc, styleSheetIterator)
+{
+ try
+ {
+ processAllStyleSheets(doc, styleSheetIterator);
+ }
+ catch(e)
+ {
+ // TODO: FBTrace condition
+ FBTrace.sysout("CssAnalyzer.processAllStyleSheets fails: ", e);
+ }
+};
+
+/**
+ *
+ * @param element
+ * @returns {String[]} Array of IDs of CSS Rules
+ */
+CssAnalyzer.getElementCSSRules = function(element)
+{
+ try
+ {
+ return getElementCSSRules(element);
+ }
+ catch(e)
+ {
+ // TODO: FBTrace condition
+ FBTrace.sysout("CssAnalyzer.getElementCSSRules fails: ", e);
+ }
+};
+
+CssAnalyzer.getRuleData = function(ruleId)
+{
+ return CSSRuleMap[ruleId];
+};
+
+// TODO: do we need this?
+CssAnalyzer.getRuleLine = function()
+{
+};
+
+CssAnalyzer.hasExternalStyleSheet = function()
+{
+ return externalStyleSheetURLs.length > 0;
+};
+
+CssAnalyzer.parseStyleSheet = function(href)
+{
+ var sourceData = extractSourceData(href);
+ var parsedObj = CssParser.read(sourceData.source, sourceData.startLine);
+ var parsedRules = parsedObj.children;
+
+ // See: Issue 4776: [Firebug lite] CSS Media Types
+ //
+ // Ignore all special selectors like @media and @page
+ for(var i=0; i < parsedRules.length; )
+ {
+ if (parsedRules[i].selector.indexOf("@") != -1)
+ {
+ parsedRules.splice(i, 1);
+ }
+ else
+ i++;
+ }
+
+ return parsedRules;
+};
+
+//************************************************************************************************
+// Internals
+//************************************************************************************************
+
+// ************************************************************************************************
+// StyleSheet processing
+
+var processAllStyleSheets = function(doc, styleSheetIterator)
+{
+ styleSheetIterator = styleSheetIterator || processStyleSheet;
+
+ globalCSSRuleIndex = -1;
+
+ var styleSheets = doc.styleSheets;
+ var importedStyleSheets = [];
+
+ if (FBTrace.DBG_CSS)
+ var start = new Date().getTime();
+
+ for(var i=0, length=styleSheets.length; i<length; i++)
+ {
+ try
+ {
+ var styleSheet = styleSheets[i];
+
+ if ("firebugIgnore" in styleSheet) continue;
+
+ // we must read the length to make sure we have permission to read
+ // the stylesheet's content. If an error occurs here, we cannot
+ // read the stylesheet due to access restriction policy
+ var rules = isIE ? styleSheet.rules : styleSheet.cssRules;
+ rules.length;
+ }
+ catch(e)
+ {
+ externalStyleSheetURLs.push(styleSheet.href);
+ styleSheet.restricted = true;
+ var ssid = StyleSheetCache(styleSheet);
+
+ /// TODO: xxxpedro external css
+ //loadExternalStylesheet(doc, styleSheetIterator, styleSheet);
+ }
+
+ // process internal and external styleSheets
+ styleSheetIterator(doc, styleSheet);
+
+ var importedStyleSheet, importedRules;
+
+ // process imported styleSheets in IE
+ if (isIE)
+ {
+ var imports = styleSheet.imports;
+
+ for(var j=0, importsLength=imports.length; j<importsLength; j++)
+ {
+ try
+ {
+ importedStyleSheet = imports[j];
+ // we must read the length to make sure we have permission
+ // to read the imported stylesheet's content.
+ importedRules = importedStyleSheet.rules;
+ importedRules.length;
+ }
+ catch(e)
+ {
+ externalStyleSheetURLs.push(styleSheet.href);
+ importedStyleSheet.restricted = true;
+ var ssid = StyleSheetCache(importedStyleSheet);
+ }
+
+ styleSheetIterator(doc, importedStyleSheet);
+ }
+ }
+ // process imported styleSheets in other browsers
+ else if (rules)
+ {
+ for(var j=0, rulesLength=rules.length; j<rulesLength; j++)
+ {
+ try
+ {
+ var rule = rules[j];
+
+ importedStyleSheet = rule.styleSheet;
+
+ if (importedStyleSheet)
+ {
+ // we must read the length to make sure we have permission
+ // to read the imported stylesheet's content.
+ importedRules = importedStyleSheet.cssRules;
+ importedRules.length;
+ }
+ else
+ break;
+ }
+ catch(e)
+ {
+ externalStyleSheetURLs.push(styleSheet.href);
+ importedStyleSheet.restricted = true;
+ var ssid = StyleSheetCache(importedStyleSheet);
+ }
+
+ styleSheetIterator(doc, importedStyleSheet);
+ }
+ }
+ };
+
+ if (FBTrace.DBG_CSS)
+ {
+ FBTrace.sysout("FBL.processAllStyleSheets", "all stylesheet rules processed in " + (new Date().getTime() - start) + "ms");
+ }
+};
+
+// ************************************************************************************************
+
+var processStyleSheet = function(doc, styleSheet)
+{
+ if (styleSheet.restricted)
+ return;
+
+ var rules = isIE ? styleSheet.rules : styleSheet.cssRules;
+
+ var ssid = StyleSheetCache(styleSheet);
+
+ var href = styleSheet.href;
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // CSS Parser
+ var shouldParseCSS = typeof CssParser != "undefined" && !Firebug.disableResourceFetching;
+ if (shouldParseCSS)
+ {
+ try
+ {
+ var parsedRules = CssAnalyzer.parseStyleSheet(href);
+ }
+ catch(e)
+ {
+ if (FBTrace.DBG_ERRORS) FBTrace.sysout("processStyleSheet FAILS", e.message || e);
+ shouldParseCSS = false;
+ }
+ finally
+ {
+ var parsedRulesIndex = 0;
+
+ var dontSupportGroupedRules = isIE && browserVersion < 9;
+ var group = [];
+ var groupItem;
+ }
+ }
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ for (var i=0, length=rules.length; i<length; i++)
+ {
+ // TODO: xxxpedro is there a better way to cache CSS Rules? The problem is that
+ // we cannot add expando properties in the rule object in IE
+ var rid = ssid + ":" + i;
+ var rule = rules[i];
+ var selector = rule.selectorText || "";
+ var lineNo = null;
+
+ // See: Issue 4776: [Firebug lite] CSS Media Types
+ //
+ // Ignore all special selectors like @media and @page
+ if (!selector || selector.indexOf("@") != -1)
+ continue;
+
+ if (isIE)
+ selector = selector.replace(reSelectorTag, function(s){return s.toLowerCase();});
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // CSS Parser
+ if (shouldParseCSS)
+ {
+ var parsedRule = parsedRules[parsedRulesIndex];
+ var parsedSelector = parsedRule.selector;
+
+ if (dontSupportGroupedRules && parsedSelector.indexOf(",") != -1 && group.length == 0)
+ group = parsedSelector.split(",");
+
+ if (dontSupportGroupedRules && group.length > 0)
+ {
+ groupItem = group.shift();
+
+ if (CssParser.normalizeSelector(selector) == groupItem)
+ lineNo = parsedRule.line;
+
+ if (group.length == 0)
+ parsedRulesIndex++;
+ }
+ else if (CssParser.normalizeSelector(selector) == parsedRule.selector)
+ {
+ lineNo = parsedRule.line;
+ parsedRulesIndex++;
+ }
+ }
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ CSSRuleMap[rid] =
+ {
+ styleSheetId: ssid,
+ styleSheetIndex: i,
+ order: ++globalCSSRuleIndex,
+ specificity:
+ // See: Issue 4777: [Firebug lite] Specificity of CSS Rules
+ //
+ // if it is a normal selector then calculate the specificity
+ selector && selector.indexOf(",") == -1 ?
+ getCSSRuleSpecificity(selector) :
+ // See: Issue 3262: [Firebug lite] Specificity of grouped CSS Rules
+ //
+ // if it is a grouped selector, do not calculate the specificity
+ // because the correct value will depend of the matched element.
+ // The proper specificity value for grouped selectors are calculated
+ // via getElementCSSRules(element)
+ 0,
+
+ rule: rule,
+ lineNo: lineNo,
+ selector: selector,
+ cssText: rule.style ? rule.style.cssText : rule.cssText ? rule.cssText : ""
+ };
+
+ // TODO: what happens with elements added after this? Need to create a test case.
+ // Maybe we should place this at getElementCSSRules() but it will make the function
+ // a lot more expensive.
+ //
+ // Maybe add a "refresh" button?
+ var elements = Firebug.Selector(selector, doc);
+
+ for (var j=0, elementsLength=elements.length; j<elementsLength; j++)
+ {
+ var element = elements[j];
+ var eid = ElementCache(element);
+
+ if (!ElementCSSRulesMap[eid])
+ ElementCSSRulesMap[eid] = [];
+
+ ElementCSSRulesMap[eid].push(rid);
+ }
+
+ //console.log(selector, elements);
+ }
+};
+
+// ************************************************************************************************
+// External StyleSheet Loader
+
+var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet)
+{
+ var url = styleSheet.href;
+ styleSheet.firebugIgnore = true;
+
+ var source = Firebug.Lite.Proxy.load(url);
+
+ // TODO: check for null and error responses
+
+ // remove comments
+ //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g;
+ //source = source.replace(reMultiComment, "");
+
+ // convert relative addresses to absolute ones
+ source = source.replace(/url\(([^\)]+)\)/g, function(a,name){
+
+ var hasDomain = /\w+:\/\/./.test(name);
+
+ if (!hasDomain)
+ {
+ name = name.replace(/^(["'])(.+)\1$/, "$2");
+ var first = name.charAt(0);
+
+ // relative path, based on root
+ if (first == "/")
+ {
+ // TODO: xxxpedro move to lib or Firebug.Lite.something
+ // getURLRoot
+ var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url);
+
+ return m ?
+ "url(" + m[1] + name + ")" :
+ "url(" + name + ")";
+ }
+ // relative path, based on current location
+ else
+ {
+ // TODO: xxxpedro move to lib or Firebug.Lite.something
+ // getURLPath
+ var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, "");
+
+ path = path + name;
+
+ var reBack = /[^\/]+\/\.\.\//;
+ while(reBack.test(path))
+ {
+ path = path.replace(reBack, "");
+ }
+
+ //console.log("url(" + path + ")");
+
+ return "url(" + path + ")";
+ }
+ }
+
+ // if it is an absolute path, there is nothing to do
+ return a;
+ });
+
+ var oldStyle = styleSheet.ownerNode;
+
+ if (!oldStyle) return;
+
+ if (!oldStyle.parentNode) return;
+
+ var style = createGlobalElement("style");
+ style.setAttribute("charset","utf-8");
+ style.setAttribute("type", "text/css");
+ style.innerHTML = source;
+
+ //debugger;
+ oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling);
+ oldStyle.parentNode.removeChild(oldStyle);
+
+ doc.styleSheets[doc.styleSheets.length-1].externalURL = url;
+
+ console.log(url, "call " + externalStyleSheetURLs.length, source);
+
+ externalStyleSheetURLs.pop();
+
+ if (processAllStyleSheetsTimeout)
+ {
+ clearTimeout(processAllStyleSheetsTimeout);
+ }
+
+ processAllStyleSheetsTimeout = setTimeout(function(){
+ console.log("processing");
+ FBL.processAllStyleSheets(doc, styleSheetIterator);
+ processAllStyleSheetsTimeout = null;
+ },200);
+
+};
+
+//************************************************************************************************
+// getElementCSSRules
+
+var getElementCSSRules = function(element)
+{
+ var eid = ElementCache(element);
+ var rules = ElementCSSRulesMap[eid];
+
+ if (!rules) return;
+
+ var arr = [element];
+ var Selector = Firebug.Selector;
+ var ruleId, rule;
+
+ // for the case of grouped selectors, we need to calculate the highest
+ // specificity within the selectors of the group that matches the element,
+ // so we can sort the rules properly without over estimating the specificity
+ // of grouped selectors
+ for (var i = 0, length = rules.length; i < length; i++)
+ {
+ ruleId = rules[i];
+ rule = CSSRuleMap[ruleId];
+
+ // check if it is a grouped selector
+ if (rule.selector.indexOf(",") != -1)
+ {
+ var selectors = rule.selector.split(",");
+ var maxSpecificity = -1;
+ var sel, spec, mostSpecificSelector;
+
+ // loop over all selectors in the group
+ for (var j, len = selectors.length; j < len; j++)
+ {
+ sel = selectors[j];
+
+ // find if the selector matches the element
+ if (Selector.matches(sel, arr).length == 1)
+ {
+ spec = getCSSRuleSpecificity(sel);
+
+ // find the most specific selector that macthes the element
+ if (spec > maxSpecificity)
+ {
+ maxSpecificity = spec;
+ mostSpecificSelector = sel;
+ }
+ }
+ }
+
+ rule.specificity = maxSpecificity;
+ }
+ }
+
+ rules.sort(sortElementRules);
+ //rules.sort(solveRulesTied);
+
+ return rules;
+};
+
+// ************************************************************************************************
+// Rule Specificity
+
+var sortElementRules = function(a, b)
+{
+ var ruleA = CSSRuleMap[a];
+ var ruleB = CSSRuleMap[b];
+
+ var specificityA = ruleA.specificity;
+ var specificityB = ruleB.specificity;
+
+ if (specificityA > specificityB)
+ return 1;
+
+ else if (specificityA < specificityB)
+ return -1;
+
+ else
+ return ruleA.order > ruleB.order ? 1 : -1;
+};
+
+var solveRulesTied = function(a, b)
+{
+ var ruleA = CSSRuleMap[a];
+ var ruleB = CSSRuleMap[b];
+
+ if (ruleA.specificity == ruleB.specificity)
+ return ruleA.order > ruleB.order ? 1 : -1;
+
+ return null;
+};
+
+var getCSSRuleSpecificity = function(selector)
+{
+ var match = selector.match(reSelectorTag);
+ var tagCount = match ? match.length : 0;
+
+ match = selector.match(reSelectorClass);
+ var classCount = match ? match.length : 0;
+
+ match = selector.match(reSelectorId);
+ var idCount = match ? match.length : 0;
+
+ return tagCount + 10*classCount + 100*idCount;
+};
+
+// ************************************************************************************************
+// StyleSheet data
+
+var extractSourceData = function(href)
+{
+ var sourceData =
+ {
+ source: null,
+ startLine: 0
+ };
+
+ if (href)
+ {
+ sourceData.source = Firebug.Lite.Proxy.load(href);
+ }
+ else
+ {
+ // TODO: create extractInternalSourceData(index)
+ // TODO: pre process the position of the inline styles so this will happen only once
+ // in case of having multiple inline styles
+ var index = 0;
+ var ssIndex = ++internalStyleSheetIndex;
+ var reStyleTag = /\<\s*style.*\>/gi;
+ var reEndStyleTag = /\<\/\s*style.*\>/gi;
+
+ var source = Firebug.Lite.Proxy.load(Env.browser.location.href);
+ source = source.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks
+
+ var startLine = 0;
+
+ do
+ {
+ var matchStyleTag = source.match(reStyleTag);
+ var i0 = source.indexOf(matchStyleTag[0]) + matchStyleTag[0].length;
+
+ for (var i=0; i < i0; i++)
+ {
+ if (source.charAt(i) == "\n")
+ startLine++;
+ }
+
+ source = source.substr(i0);
+
+ index++;
+ }
+ while (index <= ssIndex);
+
+ var matchEndStyleTag = source.match(reEndStyleTag);
+ var i1 = source.indexOf(matchEndStyleTag[0]);
+
+ var extractedSource = source.substr(0, i1);
+
+ sourceData.source = extractedSource;
+ sourceData.startLine = startLine;
+ }
+
+ return sourceData;
+};
+
+// ************************************************************************************************
+// Registration
+
+FBL.CssAnalyzer = CssAnalyzer;
+
+// ************************************************************************************************
+}});
+
+
+/* See license.txt for terms of usage */
+
+// move to FBL
+(function() {
+
+// ************************************************************************************************
+// XPath
+
+/**
+ * Gets an XPath for an element which describes its hierarchical location.
+ */
+this.getElementXPath = function(element)
+{
+ try
+ {
+ if (element && element.id)
+ return '//*[@id="' + element.id + '"]';
+ else
+ return this.getElementTreeXPath(element);
+ }
+ catch(E)
+ {
+ // xxxpedro: trying to detect the mysterious error:
+ // Security error" code: "1000
+ //debugger;
+ }
+};
+
+this.getElementTreeXPath = function(element)
+{
+ var paths = [];
+
+ for (; element && element.nodeType == 1; element = element.parentNode)
+ {
+ var index = 0;
+ var nodeName = element.nodeName;
+
+ for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling)
+ {
+ if (sibling.nodeType != 1) continue;
+
+ if (sibling.nodeName == nodeName)
+ ++index;
+ }
+
+ var tagName = element.nodeName.toLowerCase();
+ var pathIndex = (index ? "[" + (index+1) + "]" : "");
+ paths.splice(0, 0, tagName + pathIndex);
+ }
+
+ return paths.length ? "/" + paths.join("/") : null;
+};
+
+this.getElementsByXPath = function(doc, xpath)
+{
+ var nodes = [];
+
+ try {
+ var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null);
+ for (var item = result.iterateNext(); item; item = result.iterateNext())
+ nodes.push(item);
+ }
+ catch (exc)
+ {
+ // Invalid xpath expressions make their way here sometimes. If that happens,
+ // we still want to return an empty set without an exception.
+ }
+
+ return nodes;
+};
+
+this.getRuleMatchingElements = function(rule, doc)
+{
+ var css = rule.selectorText;
+ var xpath = this.cssToXPath(css);
+ return this.getElementsByXPath(doc, xpath);
+};
+
+
+}).call(FBL);
+
+
+
+
+FBL.ns(function() { with (FBL) {
+
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+
+var toCamelCase = function toCamelCase(s)
+{
+ return s.replace(reSelectorCase, toCamelCaseReplaceFn);
+};
+
+var toSelectorCase = function toSelectorCase(s)
+{
+ return s.replace(reCamelCase, "-$1").toLowerCase();
+
+};
+
+var reCamelCase = /([A-Z])/g;
+var reSelectorCase = /\-(.)/g;
+var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g)
+{
+ return g.toUpperCase();
+};
+
+// ************************************************************************************************
+
+var ElementCache = Firebug.Lite.Cache.Element;
+var StyleSheetCache = Firebug.Lite.Cache.StyleSheet;
+
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+// ************************************************************************************************
+
+
+// ************************************************************************************************
+// Constants
+
+//const Cc = Components.classes;
+//const Ci = Components.interfaces;
+//const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule;
+//const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor;
+//const nsISelectionDisplay = Ci.nsISelectionDisplay;
+//const nsISelectionController = Ci.nsISelectionController;
+
+// See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153
+//const STATE_ACTIVE = 0x01;
+//const STATE_FOCUS = 0x02;
+//const STATE_HOVER = 0x04;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+Firebug.SourceBoxPanel = Firebug.Panel;
+
+var reSelectorTag = /(^|\s)(?:\w+)/g;
+
+var domUtils = null;
+
+var textContent = isIE ? "innerText" : "textContent";
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var CSSDomplateBase = {
+ isEditable: function(rule)
+ {
+ return !rule.isSystemSheet;
+ },
+ isSelectorEditable: function(rule)
+ {
+ return rule.isSelectorEditable && this.isEditable(rule);
+ }
+};
+
+var CSSPropTag = domplate(CSSDomplateBase, {
+ tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled",
+ $editGroup: "$rule|isEditable",
+ $cssOverridden: "$prop.overridden", role : "option"},
+ A({"class": "cssPropDisable"}, "&nbsp;&nbsp;"),
+ SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"),
+ SPAN({"class": "cssColon"}, ":"),
+ SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"),
+ SPAN({"class": "cssSemi"}, ";")
+ )
+});
+
+var CSSRuleTag =
+ TAG("$rule.tag", {rule: "$rule"});
+
+var CSSImportRuleTag = domplate({
+ tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"},
+ "@import &quot;",
+ A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"),
+ "&quot;;"
+ )
+});
+
+var CSSStyleRuleTag = domplate(CSSDomplateBase, {
+ tag: DIV({"class": "cssRule insertInto",
+ $cssEditableRule: "$rule|isEditable",
+ $editGroup: "$rule|isSelectorEditable",
+ _repObject: "$rule.rule",
+ "ruleId": "$rule.id", role : 'presentation'},
+ DIV({"class": "cssHead focusRow", role : 'listitem'},
+ SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {"
+ ),
+ DIV({role : 'group'},
+ DIV({"class": "cssPropertyListBox", role : 'listbox'},
+ FOR("prop", "$rule.props",
+ TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"})
+ )
+ )
+ ),
+ DIV({"class": "editable insertBefore", role:"presentation"}, "}")
+ )
+});
+
+var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/;
+
+var reURL = /url\("?([^"\)]+)?"?\)/;
+
+var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/;
+
+//const sothinkInstalled = !!$("swfcatcherKey_sidebar");
+var sothinkInstalled = false;
+var styleGroups =
+{
+ text: [
+ "font-family",
+ "font-size",
+ "font-weight",
+ "font-style",
+ "color",
+ "text-transform",
+ "text-decoration",
+ "letter-spacing",
+ "word-spacing",
+ "line-height",
+ "text-align",
+ "vertical-align",
+ "direction",
+ "column-count",
+ "column-gap",
+ "column-width"
+ ],
+
+ background: [
+ "background-color",
+ "background-image",
+ "background-repeat",
+ "background-position",
+ "background-attachment",
+ "opacity"
+ ],
+
+ box: [
+ "width",
+ "height",
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "margin-top",
+ "margin-right",
+ "margin-bottom",
+ "margin-left",
+ "padding-top",
+ "padding-right",
+ "padding-bottom",
+ "padding-left",
+ "border-top-width",
+ "border-right-width",
+ "border-bottom-width",
+ "border-left-width",
+ "border-top-color",
+ "border-right-color",
+ "border-bottom-color",
+ "border-left-color",
+ "border-top-style",
+ "border-right-style",
+ "border-bottom-style",
+ "border-left-style",
+ "-moz-border-top-radius",
+ "-moz-border-right-radius",
+ "-moz-border-bottom-radius",
+ "-moz-border-left-radius",
+ "outline-top-width",
+ "outline-right-width",
+ "outline-bottom-width",
+ "outline-left-width",
+ "outline-top-color",
+ "outline-right-color",
+ "outline-bottom-color",
+ "outline-left-color",
+ "outline-top-style",
+ "outline-right-style",
+ "outline-bottom-style",
+ "outline-left-style"
+ ],
+
+ layout: [
+ "position",
+ "display",
+ "visibility",
+ "z-index",
+ "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow
+ "overflow-y",
+ "overflow-clip",
+ "white-space",
+ "clip",
+ "float",
+ "clear",
+ "-moz-box-sizing"
+ ],
+
+ other: [
+ "cursor",
+ "list-style-image",
+ "list-style-position",
+ "list-style-type",
+ "marker-offset",
+ "user-focus",
+ "user-select",
+ "user-modify",
+ "user-input"
+ ]
+};
+
+var styleGroupTitles =
+{
+ text: "Text",
+ background: "Background",
+ box: "Box Model",
+ layout: "Layout",
+ other: "Other"
+};
+
+Firebug.CSSModule = extend(Firebug.Module,
+{
+ freeEdit: function(styleSheet, value)
+ {
+ if (!styleSheet.editStyleSheet)
+ {
+ var ownerNode = getStyleSheetOwnerNode(styleSheet);
+ styleSheet.disabled = true;
+
+ var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL);
+ url.spec = styleSheet.href;
+
+ var editStyleSheet = ownerNode.ownerDocument.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "style");
+ unwrapObject(editStyleSheet).firebugIgnore = true;
+ editStyleSheet.setAttribute("type", "text/css");
+ editStyleSheet.setAttributeNS(
+ "http://www.w3.org/XML/1998/namespace",
+ "base",
+ url.directory);
+ if (ownerNode.hasAttribute("media"))
+ {
+ editStyleSheet.setAttribute("media", ownerNode.getAttribute("media"));
+ }
+
+ // Insert the edited stylesheet directly after the old one to ensure the styles
+ // cascade properly.
+ ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling);
+
+ styleSheet.editStyleSheet = editStyleSheet;
+ }
+
+ styleSheet.editStyleSheet.innerHTML = value;
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n");
+
+ dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]);
+ },
+
+ insertRule: function(styleSheet, cssText, ruleIndex)
+ {
+ if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText);
+ var insertIndex = styleSheet.insertRule(cssText, ruleIndex);
+
+ dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]);
+
+ return insertIndex;
+ },
+
+ deleteRule: function(styleSheet, ruleIndex)
+ {
+ if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules);
+ dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]);
+
+ styleSheet.deleteRule(ruleIndex);
+ },
+
+ setProperty: function(rule, propName, propValue, propPriority)
+ {
+ var style = rule.style || rule;
+
+ // Record the original CSS text for the inline case so we can reconstruct at a later
+ // point for diffing purposes
+ var baseText = style.cssText;
+
+ // good browsers
+ if (style.getPropertyValue)
+ {
+ var prevValue = style.getPropertyValue(propName);
+ var prevPriority = style.getPropertyPriority(propName);
+
+ // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect
+ // unless we remove the property first
+ style.removeProperty(propName);
+
+ style.setProperty(propName, propValue, propPriority);
+ }
+ // sad browsers
+ else
+ {
+ // TODO: xxxpedro parse CSS rule to find property priority in IE?
+ //console.log(propName, propValue);
+ style[toCamelCase(propName)] = propValue;
+ }
+
+ if (propName) {
+ dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]);
+ }
+ },
+
+ removeProperty: function(rule, propName, parent)
+ {
+ var style = rule.style || rule;
+
+ // Record the original CSS text for the inline case so we can reconstruct at a later
+ // point for diffing purposes
+ var baseText = style.cssText;
+
+ if (style.getPropertyValue)
+ {
+
+ var prevValue = style.getPropertyValue(propName);
+ var prevPriority = style.getPropertyPriority(propName);
+
+ style.removeProperty(propName);
+ }
+ else
+ {
+ style[toCamelCase(propName)] = "";
+ }
+
+ if (propName) {
+ dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]);
+ }
+ }/*,
+
+ cleanupSheets: function(doc, context)
+ {
+ // Due to the manner in which the layout engine handles multiple
+ // references to the same sheet we need to kick it a little bit.
+ // The injecting a simple stylesheet then removing it will force
+ // Firefox to regenerate it's CSS hierarchy.
+ //
+ // WARN: This behavior was determined anecdotally.
+ // See http://code.google.com/p/fbug/issues/detail?id=2440
+ var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
+ style.setAttribute("charset","utf-8");
+ unwrapObject(style).firebugIgnore = true;
+ style.setAttribute("type", "text/css");
+ style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}";
+ addStyleSheet(doc, style);
+ style.parentNode.removeChild(style);
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=500365
+ // This voodoo touches each style sheet to force some Firefox internal change to allow edits.
+ var styleSheets = getAllStyleSheets(context);
+ for(var i = 0; i < styleSheets.length; i++)
+ {
+ try
+ {
+ var rules = styleSheets[i].cssRules;
+ if (rules.length > 0)
+ var touch = rules[0];
+ if (FBTrace.DBG_CSS && touch)
+ FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName()));
+ }
+ catch(e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e);
+ }
+ }
+ },
+ cleanupSheetHandler: function(event, context)
+ {
+ var target = event.target || event.srcElement,
+ tagName = (target.tagName || "").toLowerCase();
+ if (tagName == "link")
+ {
+ this.cleanupSheets(target.ownerDocument, context);
+ }
+ },
+ watchWindow: function(context, win)
+ {
+ var cleanupSheets = bind(this.cleanupSheets, this),
+ cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context),
+ doc = win.document;
+
+ //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false);
+ //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false);
+ },
+ loadedContext: function(context)
+ {
+ var self = this;
+ iterateWindows(context.browser.contentWindow, function(subwin)
+ {
+ self.cleanupSheets(subwin.document, context);
+ });
+ }
+ /**/
+});
+
+// ************************************************************************************************
+
+Firebug.CSSStyleSheetPanel = function() {};
+
+Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel,
+{
+ template: domplate(
+ {
+ tag:
+ DIV({"class": "cssSheet insertInto a11yCSSView"},
+ FOR("rule", "$rules",
+ CSSRuleTag
+ ),
+ DIV({"class": "cssSheet editable insertBefore"}, "")
+ )
+ }),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ refresh: function()
+ {
+ if (this.location)
+ this.updateLocation(this.location);
+ else if (this.selection)
+ this.updateSelection(this.selection);
+ },
+
+ toggleEditing: function()
+ {
+ if (!this.stylesheetEditor)
+ this.stylesheetEditor = new StyleSheetEditor(this.document);
+
+ if (this.editing)
+ Firebug.Editor.stopEditing();
+ else
+ {
+ if (!this.location)
+ return;
+
+ var styleSheet = this.location.editStyleSheet
+ ? this.location.editStyleSheet.sheet
+ : this.location;
+
+ var css = getStyleSheetCSS(styleSheet, this.context);
+ //var topmost = getTopmostRuleLine(this.panelNode);
+
+ this.stylesheetEditor.styleSheet = this.location;
+ Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor);
+ //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset);
+ }
+ },
+
+ getStylesheetURL: function(rule)
+ {
+ if (this.location.href)
+ return this.location.href;
+ else
+ return this.context.window.location.href;
+ },
+
+ getRuleByLine: function(styleSheet, line)
+ {
+ if (!domUtils)
+ return null;
+
+ var cssRules = styleSheet.cssRules;
+ for (var i = 0; i < cssRules.length; ++i)
+ {
+ var rule = cssRules[i];
+ if (rule instanceof CSSStyleRule)
+ {
+ var ruleLine = domUtils.getRuleLine(rule);
+ if (ruleLine >= line)
+ return rule;
+ }
+ }
+ },
+
+ highlightRule: function(rule)
+ {
+ var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule);
+ if (ruleElement)
+ {
+ scrollIntoCenterView(ruleElement, this.panelNode);
+ setClassTimed(ruleElement, "jumpHighlight", this.context);
+ }
+ },
+
+ getStyleSheetRules: function(context, styleSheet)
+ {
+ var isSystemSheet = isSystemStyleSheet(styleSheet);
+
+ function appendRules(cssRules)
+ {
+ for (var i = 0; i < cssRules.length; ++i)
+ {
+ var rule = cssRules[i];
+
+ // TODO: xxxpedro opera instanceof stylesheet remove the following comments when
+ // the issue with opera and style sheet Classes has been solved.
+
+ //if (rule instanceof CSSStyleRule)
+ if (instanceOf(rule, "CSSStyleRule"))
+ {
+ var props = this.getRuleProperties(context, rule);
+ //var line = domUtils.getRuleLine(rule);
+ var line = null;
+
+ var selector = rule.selectorText;
+
+ if (isIE)
+ {
+ selector = selector.replace(reSelectorTag,
+ function(s){return s.toLowerCase();});
+ }
+
+ var ruleId = rule.selectorText+"/"+line;
+ rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId,
+ selector: selector, props: props,
+ isSystemSheet: isSystemSheet,
+ isSelectorEditable: true});
+ }
+ //else if (rule instanceof CSSImportRule)
+ else if (instanceOf(rule, "CSSImportRule"))
+ rules.push({tag: CSSImportRuleTag.tag, rule: rule});
+ //else if (rule instanceof CSSMediaRule)
+ else if (instanceOf(rule, "CSSMediaRule"))
+ appendRules.apply(this, [rule.cssRules]);
+ else
+ {
+ if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS)
+ FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule);
+ }
+ }
+ }
+
+ var rules = [];
+ appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]);
+ return rules;
+ },
+
+ parseCSSProps: function(style, inheritMode)
+ {
+ var props = [];
+
+ if (Firebug.expandShorthandProps)
+ {
+ var count = style.length-1,
+ index = style.length;
+ while (index--)
+ {
+ var propName = style.item(count - index);
+ this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props);
+ }
+ }
+ else
+ {
+ var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g);
+ var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/;
+ var line,i=0;
+ // TODO: xxxpedro port to firebug: variable leaked into global namespace
+ var m;
+
+ while(line=lines[i++]){
+ m = propRE.exec(line);
+ if(!m)
+ continue;
+ //var name = m[1], value = m[2], important = !!m[3];
+ if (m[2])
+ this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props);
+ };
+ }
+
+ return props;
+ },
+
+ getRuleProperties: function(context, rule, inheritMode)
+ {
+ var props = this.parseCSSProps(rule.style, inheritMode);
+
+ // TODO: xxxpedro port to firebug: variable leaked into global namespace
+ //var line = domUtils.getRuleLine(rule);
+ var line;
+ var ruleId = rule.selectorText+"/"+line;
+ this.addOldProperties(context, ruleId, inheritMode, props);
+ sortProperties(props);
+
+ return props;
+ },
+
+ addOldProperties: function(context, ruleId, inheritMode, props)
+ {
+ if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) )
+ {
+ var moreProps = context.selectorMap[ruleId];
+ for (var i = 0; i < moreProps.length; ++i)
+ {
+ var prop = moreProps[i];
+ this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props);
+ }
+ }
+ },
+
+ addProperty: function(name, value, important, disabled, inheritMode, props)
+ {
+ name = name.toLowerCase();
+
+ if (inheritMode && !inheritedStyleNames[name])
+ return;
+
+ name = this.translateName(name, value);
+ if (name)
+ {
+ value = stripUnits(rgbToHex(value));
+ important = important ? " !important" : "";
+
+ var prop = {name: name, value: value, important: important, disabled: disabled};
+ props.push(prop);
+ }
+ },
+
+ translateName: function(name, value)
+ {
+ // Don't show these proprietary Mozilla properties
+ if ((value == "-moz-initial"
+ && (name == "-moz-background-clip" || name == "-moz-background-origin"
+ || name == "-moz-background-inline-policy"))
+ || (value == "physical"
+ && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source"
+ || name == "margin-right-ltr-source" || name == "margin-right-rtl-source"))
+ || (value == "physical"
+ && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source"
+ || name == "padding-right-ltr-source" || name == "padding-right-rtl-source")))
+ return null;
+
+ // Translate these back to the form the user probably expects
+ if (name == "margin-left-value")
+ return "margin-left";
+ else if (name == "margin-right-value")
+ return "margin-right";
+ else if (name == "margin-top-value")
+ return "margin-top";
+ else if (name == "margin-bottom-value")
+ return "margin-bottom";
+ else if (name == "padding-left-value")
+ return "padding-left";
+ else if (name == "padding-right-value")
+ return "padding-right";
+ else if (name == "padding-top-value")
+ return "padding-top";
+ else if (name == "padding-bottom-value")
+ return "padding-bottom";
+ // XXXjoe What about border!
+ else
+ return name;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ editElementStyle: function()
+ {
+ ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0];
+ var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0];
+ var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection);
+ if (!styleRuleBox)
+ {
+ var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []};
+ if (!rulesBox)
+ {
+ // The element did not have any displayed styles. We need to create the whole tree and remove
+ // the no styles message
+ styleRuleBox = this.template.cascadedTag.replace({
+ rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom")
+ }, this.panelNode);
+
+ ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0];
+ styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0];
+ }
+ else
+ styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox);
+
+ ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0];
+ styleRuleBox = $$(".insertInto", styleRuleBox)[0];
+ }
+
+ Firebug.Editor.insertRowForObject(styleRuleBox);
+ },
+
+ insertPropertyRow: function(row)
+ {
+ Firebug.Editor.insertRowForObject(row);
+ },
+
+ insertRule: function(row)
+ {
+ var location = getAncestorByClass(row, "cssRule");
+ if (!location)
+ {
+ location = getChildByClass(this.panelNode, "cssSheet");
+ Firebug.Editor.insertRowForObject(location);
+ }
+ else
+ {
+ Firebug.Editor.insertRow(location, "before");
+ }
+ },
+
+ editPropertyRow: function(row)
+ {
+ var propValueBox = getChildByClass(row, "cssPropValue");
+ Firebug.Editor.startEditing(propValueBox);
+ },
+
+ deletePropertyRow: function(row)
+ {
+ var rule = Firebug.getRepObject(row);
+ var propName = getChildByClass(row, "cssPropName")[textContent];
+ Firebug.CSSModule.removeProperty(rule, propName);
+
+ // Remove the property from the selector map, if it was disabled
+ var ruleId = Firebug.getRepNode(row).getAttribute("ruleId");
+ if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) )
+ {
+ var map = this.context.selectorMap[ruleId];
+ for (var i = 0; i < map.length; ++i)
+ {
+ if (map[i].name == propName)
+ {
+ map.splice(i, 1);
+ break;
+ }
+ }
+ }
+ if (this.name == "stylesheet")
+ dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]);
+ row.parentNode.removeChild(row);
+
+ this.markChange(this.name == "stylesheet");
+ },
+
+ disablePropertyRow: function(row)
+ {
+ toggleClass(row, "disabledStyle");
+
+ var rule = Firebug.getRepObject(row);
+ var propName = getChildByClass(row, "cssPropName")[textContent];
+
+ if (!this.context.selectorMap)
+ this.context.selectorMap = {};
+
+ // XXXjoe Generate unique key for elements too
+ var ruleId = Firebug.getRepNode(row).getAttribute("ruleId");
+ if (!(this.context.selectorMap.hasOwnProperty(ruleId)))
+ this.context.selectorMap[ruleId] = [];
+
+ var map = this.context.selectorMap[ruleId];
+ var propValue = getChildByClass(row, "cssPropValue")[textContent];
+ var parsedValue = parsePriority(propValue);
+ if (hasClass(row, "disabledStyle"))
+ {
+ Firebug.CSSModule.removeProperty(rule, propName);
+
+ map.push({"name": propName, "value": parsedValue.value,
+ "important": parsedValue.priority});
+ }
+ else
+ {
+ Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);
+
+ var index = findPropByName(map, propName);
+ map.splice(index, 1);
+ }
+
+ this.markChange(this.name == "stylesheet");
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onMouseDown: function(event)
+ {
+ //console.log("onMouseDown", event.target || event.srcElement, event);
+
+ // xxxpedro adjusting coordinates because the panel isn't a window yet
+ var offset = event.clientX - this.panelNode.parentNode.offsetLeft;
+
+ // XXjoe Hack to only allow clicking on the checkbox
+ if (!isLeftClick(event) || offset > 20)
+ return;
+
+ var target = event.target || event.srcElement;
+ if (hasClass(target, "textEditor"))
+ return;
+
+ var row = getAncestorByClass(target, "cssProp");
+ if (row && hasClass(row, "editGroup"))
+ {
+ this.disablePropertyRow(row);
+ cancelEvent(event);
+ }
+ },
+
+ onDoubleClick: function(event)
+ {
+ //console.log("onDoubleClick", event.target || event.srcElement, event);
+
+ // xxxpedro adjusting coordinates because the panel isn't a window yet
+ var offset = event.clientX - this.panelNode.parentNode.offsetLeft;
+
+ if (!isLeftClick(event) || offset <= 20)
+ return;
+
+ var target = event.target || event.srcElement;
+
+ //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20);
+
+ // if the inline editor was clicked, don't insert a new rule
+ if (hasClass(target, "textEditorInner"))
+ return;
+
+ var row = getAncestorByClass(target, "cssRule");
+ if (row && !getAncestorByClass(target, "cssPropName")
+ && !getAncestorByClass(target, "cssPropValue"))
+ {
+ this.insertPropertyRow(row);
+ cancelEvent(event);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "stylesheet",
+ title: "CSS",
+ parentPanel: null,
+ searchable: true,
+ dependents: ["css", "stylesheet", "dom", "domSide", "layout"],
+
+ options:
+ {
+ hasToolButtons: true
+ },
+
+ create: function()
+ {
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.onMouseDown = bind(this.onMouseDown, this);
+ this.onDoubleClick = bind(this.onDoubleClick, this);
+
+ if (this.name == "stylesheet")
+ {
+ this.onChangeSelect = bind(this.onChangeSelect, this);
+
+ var doc = Firebug.browser.document;
+ var selectNode = this.selectNode = createElement("select");
+
+ CssAnalyzer.processAllStyleSheets(doc, function(doc, styleSheet)
+ {
+ var key = StyleSheetCache.key(styleSheet);
+ var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href);
+ var option = createElement("option", {value: key});
+
+ option.appendChild(Firebug.chrome.document.createTextNode(fileName));
+ selectNode.appendChild(option);
+ });
+
+ this.toolButtonsNode.appendChild(selectNode);
+ }
+ /**/
+ },
+
+ onChangeSelect: function(event)
+ {
+ event = event || window.event;
+ var target = event.srcElement || event.currentTarget;
+ var key = target.value;
+ var styleSheet = StyleSheetCache.get(key);
+
+ this.updateLocation(styleSheet);
+ },
+
+ initialize: function()
+ {
+ Firebug.Panel.initialize.apply(this, arguments);
+
+ //if (!domUtils)
+ //{
+ // try {
+ // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
+ // } catch (exc) {
+ // if (FBTrace.DBG_ERRORS)
+ // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc);
+ // }
+ //}
+
+ //TODO: xxxpedro
+ this.context = Firebug.chrome; // TODO: xxxpedro css2
+ this.document = Firebug.chrome.document; // TODO: xxxpedro css2
+
+ this.initializeNode();
+
+ if (this.name == "stylesheet")
+ {
+ var styleSheets = Firebug.browser.document.styleSheets;
+
+ if (styleSheets.length > 0)
+ {
+ addEvent(this.selectNode, "change", this.onChangeSelect);
+
+ this.updateLocation(styleSheets[0]);
+ }
+ }
+
+ //Firebug.SourceBoxPanel.initialize.apply(this, arguments);
+ },
+
+ shutdown: function()
+ {
+ // must destroy the editor when we leave the panel to avoid problems (Issue 2981)
+ Firebug.Editor.stopEditing();
+
+ if (this.name == "stylesheet")
+ {
+ removeEvent(this.selectNode, "change", this.onChangeSelect);
+ }
+
+ this.destroyNode();
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+ },
+
+ destroy: function(state)
+ {
+ //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop;
+
+ //persistObjects(this, state);
+
+ // xxxpedro we are stopping the editor in the shutdown method already
+ //Firebug.Editor.stopEditing();
+ Firebug.Panel.destroy.apply(this, arguments);
+ },
+
+ initializeNode: function(oldPanelNode)
+ {
+ addEvent(this.panelNode, "mousedown", this.onMouseDown);
+ addEvent(this.panelNode, "dblclick", this.onDoubleClick);
+ //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments);
+ //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']);
+ },
+
+ destroyNode: function()
+ {
+ removeEvent(this.panelNode, "mousedown", this.onMouseDown);
+ removeEvent(this.panelNode, "dblclick", this.onDoubleClick);
+ //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments);
+ //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']);
+ },
+
+ ishow: function(state)
+ {
+ Firebug.Inspector.stopInspecting(true);
+
+ this.showToolbarButtons("fbCSSButtons", true);
+
+ if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel
+ {
+ restoreObjects(this, state);
+
+ if (!this.location)
+ this.location = this.getDefaultLocation();
+
+ if (state && state.scrollTop)
+ this.panelNode.scrollTop = state.scrollTop;
+ }
+ },
+
+ ihide: function()
+ {
+ this.showToolbarButtons("fbCSSButtons", false);
+
+ this.lastScrollTop = this.panelNode.scrollTop;
+ },
+
+ supportsObject: function(object)
+ {
+ if (object instanceof CSSStyleSheet)
+ return 1;
+ else if (object instanceof CSSStyleRule)
+ return 2;
+ else if (object instanceof CSSStyleDeclaration)
+ return 2;
+ else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href))
+ return 2;
+ else
+ return 0;
+ },
+
+ updateLocation: function(styleSheet)
+ {
+ if (!styleSheet)
+ return;
+ if (styleSheet.editStyleSheet)
+ styleSheet = styleSheet.editStyleSheet.sheet;
+
+ // if it is a restricted stylesheet, show the warning message and abort the update process
+ if (styleSheet.restricted)
+ {
+ FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode);
+
+ // TODO: xxxpedro remove when there the external resource problem is fixed
+ CssAnalyzer.externalStyleSheetWarning.tag.append({
+ object: "The stylesheet could not be loaded due to access restrictions. ",
+ link: "more...",
+ href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22"
+ }, this.panelNode);
+
+ return;
+ }
+
+ var rules = this.getStyleSheetRules(this.context, styleSheet);
+
+ var result;
+ if (rules.length)
+ // FIXME xxxpedro chromenew this is making iPad's Safari to crash
+ result = this.template.tag.replace({rules: rules}, this.panelNode);
+ else
+ result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode);
+
+ // TODO: xxxpedro need to fix showToolbarButtons function
+ //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location));
+
+ //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]);
+ },
+
+ updateSelection: function(object)
+ {
+ this.selection = null;
+
+ if (object instanceof CSSStyleDeclaration) {
+ object = object.parentRule;
+ }
+
+ if (object instanceof CSSStyleRule)
+ {
+ this.navigate(object.parentStyleSheet);
+ this.highlightRule(object);
+ }
+ else if (object instanceof CSSStyleSheet)
+ {
+ this.navigate(object);
+ }
+ else if (object instanceof SourceLink)
+ {
+ try
+ {
+ var sourceLink = object;
+
+ var sourceFile = getSourceFileByHref(sourceLink.href, this.context);
+ if (sourceFile)
+ {
+ clearNode(this.panelNode); // replace rendered stylesheets
+ this.showSourceFile(sourceFile);
+
+ var lineNo = object.line;
+ if (lineNo)
+ this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context));
+ }
+ else // XXXjjb we should not be taking this path
+ {
+ var stylesheet = getStyleSheetByHref(sourceLink.href, this.context);
+ if (stylesheet)
+ this.navigate(stylesheet);
+ else
+ {
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink);
+ }
+ }
+ }
+ catch(exc) {
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("css.upDateSelection FAILS "+exc, exc);
+ }
+ }
+ },
+
+ updateOption: function(name, value)
+ {
+ if (name == "expandShorthandProps")
+ this.refresh();
+ },
+
+ getLocationList: function()
+ {
+ var styleSheets = getAllStyleSheets(this.context);
+ return styleSheets;
+ },
+
+ getOptionsMenuItems: function()
+ {
+ return [
+ {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps,
+ command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") },
+ "-",
+ {label: "Refresh", command: bind(this.refresh, this) }
+ ];
+ },
+
+ getContextMenuItems: function(style, target)
+ {
+ var items = [];
+
+ if (this.infoTipType == "color")
+ {
+ items.push(
+ {label: "CopyColor",
+ command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }
+ );
+ }
+ else if (this.infoTipType == "image")
+ {
+ items.push(
+ {label: "CopyImageLocation",
+ command: bindFixed(copyToClipboard, FBL, this.infoTipObject) },
+ {label: "OpenImageInNewTab",
+ command: bindFixed(openNewTab, FBL, this.infoTipObject) }
+ );
+ }
+
+ ///if (this.selection instanceof Element)
+ if (isElement(this.selection))
+ {
+ items.push(
+ //"-",
+ {label: "EditStyle",
+ command: bindFixed(this.editElementStyle, this) }
+ );
+ }
+ else if (!isSystemStyleSheet(this.selection))
+ {
+ items.push(
+ //"-",
+ {label: "NewRule",
+ command: bindFixed(this.insertRule, this, target) }
+ );
+ }
+
+ var cssRule = getAncestorByClass(target, "cssRule");
+ if (cssRule && hasClass(cssRule, "cssEditableRule"))
+ {
+ items.push(
+ "-",
+ {label: "NewProp",
+ command: bindFixed(this.insertPropertyRow, this, target) }
+ );
+
+ var propRow = getAncestorByClass(target, "cssProp");
+ if (propRow)
+ {
+ var propName = getChildByClass(propRow, "cssPropName")[textContent];
+ var isDisabled = hasClass(propRow, "disabledStyle");
+
+ items.push(
+ {label: $STRF("EditProp", [propName]), nol10n: true,
+ command: bindFixed(this.editPropertyRow, this, propRow) },
+ {label: $STRF("DeleteProp", [propName]), nol10n: true,
+ command: bindFixed(this.deletePropertyRow, this, propRow) },
+ {label: $STRF("DisableProp", [propName]), nol10n: true,
+ type: "checkbox", checked: isDisabled,
+ command: bindFixed(this.disablePropertyRow, this, propRow) }
+ );
+ }
+ }
+
+ items.push(
+ "-",
+ {label: "Refresh", command: bind(this.refresh, this) }
+ );
+
+ return items;
+ },
+
+ browseObject: function(object)
+ {
+ if (this.infoTipType == "image")
+ {
+ openNewTab(this.infoTipObject);
+ return true;
+ }
+ },
+
+ showInfoTip: function(infoTip, target, x, y)
+ {
+ var propValue = getAncestorByClass(target, "cssPropValue");
+ if (propValue)
+ {
+ var offset = getClientOffset(propValue);
+ var offsetX = x-offset.x;
+
+ var text = propValue[textContent];
+ var charWidth = propValue.offsetWidth/text.length;
+ var charOffset = Math.floor(offsetX/charWidth);
+
+ var cssValue = parseCSSValue(text, charOffset);
+ if (cssValue)
+ {
+ if (cssValue.value == this.infoTipValue)
+ return true;
+
+ this.infoTipValue = cssValue.value;
+
+ if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value)))
+ {
+ this.infoTipType = "color";
+ this.infoTipObject = cssValue.value;
+
+ return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value);
+ }
+ else if (cssValue.type == "url")
+ {
+ ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0);
+ var propNameNode = getElementByClass(target.parentNode, "cssPropName");
+ if (propNameNode && isImageRule(propNameNode[textContent]))
+ {
+ var rule = Firebug.getRepObject(target);
+ var baseURL = this.getStylesheetURL(rule);
+ var relURL = parseURLValue(cssValue.value);
+ var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL);
+ var repeat = parseRepeatValue(text);
+
+ this.infoTipType = "image";
+ this.infoTipObject = absURL;
+
+ return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat);
+ }
+ }
+ }
+ }
+
+ delete this.infoTipType;
+ delete this.infoTipValue;
+ delete this.infoTipObject;
+ },
+
+ getEditor: function(target, value)
+ {
+ if (target == this.panelNode
+ || hasClass(target, "cssSelector") || hasClass(target, "cssRule")
+ || hasClass(target, "cssSheet"))
+ {
+ if (!this.ruleEditor)
+ this.ruleEditor = new CSSRuleEditor(this.document);
+
+ return this.ruleEditor;
+ }
+ else
+ {
+ if (!this.editor)
+ this.editor = new CSSEditor(this.document);
+
+ return this.editor;
+ }
+ },
+
+ getDefaultLocation: function()
+ {
+ try
+ {
+ var styleSheets = this.context.window.document.styleSheets;
+ if (styleSheets.length)
+ {
+ var sheet = styleSheets[0];
+ return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet;
+ }
+ }
+ catch (exc)
+ {
+ if (FBTrace.DBG_LOCATIONS)
+ FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc);
+ }
+ },
+
+ getObjectDescription: function(styleSheet)
+ {
+ var url = getURLForStyleSheet(styleSheet);
+ var instance = getInstanceForStyleSheet(styleSheet);
+
+ var baseDescription = splitURLBase(url);
+ if (instance) {
+ baseDescription.name = baseDescription.name + " #" + (instance + 1);
+ }
+ return baseDescription;
+ },
+
+ search: function(text, reverse)
+ {
+ var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse);
+ if (!curDoc && Firebug.searchGlobal)
+ {
+ return this.searchOtherDocs(text, reverse);
+ }
+ return curDoc;
+ },
+
+ searchOtherDocs: function(text, reverse)
+ {
+ var scanRE = Firebug.Search.getTestingRegex(text);
+ function scanDoc(styleSheet) {
+ // we don't care about reverse here as we are just looking for existence,
+ // if we do have a result we will handle the reverse logic on display
+ for (var i = 0; i < styleSheet.cssRules.length; i++)
+ {
+ if (scanRE.test(styleSheet.cssRules[i].cssText))
+ {
+ return true;
+ }
+ }
+ }
+
+ if (this.navigateToNextDocument(scanDoc, reverse))
+ {
+ return this.searchCurrentDoc(true, text, reverse);
+ }
+ },
+
+ searchCurrentDoc: function(wrapSearch, text, reverse)
+ {
+ if (!text)
+ {
+ delete this.currentSearch;
+ return false;
+ }
+
+ var row;
+ if (this.currentSearch && text == this.currentSearch.text)
+ {
+ row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text));
+ }
+ else
+ {
+ if (this.editing)
+ {
+ this.currentSearch = new TextSearch(this.stylesheetEditor.box);
+ row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text));
+
+ if (row)
+ {
+ var sel = this.document.defaultView.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(this.currentSearch.range);
+ scrollSelectionIntoView(this);
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; }
+ this.currentSearch = new TextSearch(this.panelNode, findRow);
+ row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text));
+ }
+ }
+
+ if (row)
+ {
+ this.document.defaultView.getSelection().selectAllChildren(row);
+ scrollIntoCenterView(row, this.panelNode);
+ dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]);
+ return true;
+ }
+ else
+ {
+ dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]);
+ return false;
+ }
+ },
+
+ getSearchOptionsMenuItems: function()
+ {
+ return [
+ Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"),
+ Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal")
+ ];
+ }
+});
+/**/
+// ************************************************************************************************
+
+function CSSElementPanel() {}
+
+CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype,
+{
+ template: domplate(
+ {
+ cascadedTag:
+ DIV({"class": "a11yCSSView", role : 'presentation'},
+ DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') },
+ FOR("rule", "$rules",
+ TAG("$ruleTag", {rule: "$rule"})
+ )
+ ),
+ DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')},
+ FOR("section", "$inherited",
+ H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' },
+ SPAN({"class": "cssInheritLabel"}, "$inheritLabel"),
+ TAG(FirebugReps.Element.shortTag, {object: "$section.element"})
+ ),
+ DIV({role : 'group'},
+ FOR("rule", "$section.rules",
+ TAG("$ruleTag", {rule: "$rule"})
+ )
+ )
+ )
+ )
+ ),
+
+ ruleTag:
+ isIE ?
+ // IE needs the sourceLink first, otherwise it will be rendered outside the panel
+ DIV({"class": "cssElementRuleContainer"},
+ TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}),
+ TAG(CSSStyleRuleTag.tag, {rule: "$rule"})
+ )
+ :
+ // other browsers need the sourceLink last, otherwise it will cause an extra space
+ // before the rule representation
+ DIV({"class": "cssElementRuleContainer"},
+ TAG(CSSStyleRuleTag.tag, {rule: "$rule"}),
+ TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"})
+ )
+ }),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ updateCascadeView: function(element)
+ {
+ //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]);
+ var rules = [], sections = [], usedProps = {};
+ this.getInheritedRules(element, sections, usedProps);
+ this.getElementRules(element, rules, usedProps);
+
+ if (rules.length || sections.length)
+ {
+ var inheritLabel = "Inherited from"; // $STR("InheritedFrom");
+ var result = this.template.cascadedTag.replace({rules: rules, inherited: sections,
+ inheritLabel: inheritLabel}, this.panelNode);
+ //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
+ }
+ else
+ {
+ var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode);
+ //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
+ }
+
+ // TODO: xxxpedro remove when there the external resource problem is fixed
+ if (CssAnalyzer.hasExternalStyleSheet())
+ CssAnalyzer.externalStyleSheetWarning.tag.append({
+ object: "The results here may be inaccurate because some " +
+ "stylesheets could not be loaded due to access restrictions. ",
+ link: "more...",
+ href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22"
+ }, this.panelNode);
+ },
+
+ getStylesheetURL: function(rule)
+ {
+ // if the parentStyleSheet.href is null, CSS std says its inline style.
+ // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location
+ if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href)
+ return rule.parentStyleSheet.href;
+ else
+ return this.selection.ownerDocument.location.href;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getInheritedRules: function(element, sections, usedProps)
+ {
+ var parent = element.parentNode;
+ if (parent && parent.nodeType == 1)
+ {
+ this.getInheritedRules(parent, sections, usedProps);
+
+ var rules = [];
+ this.getElementRules(parent, rules, usedProps, true);
+
+ if (rules.length)
+ sections.splice(0, 0, {element: parent, rules: rules});
+ }
+ },
+
+ getElementRules: function(element, rules, usedProps, inheritMode)
+ {
+ var inspectedRules, displayedRules = {};
+
+ inspectedRules = CssAnalyzer.getElementCSSRules(element);
+
+ if (inspectedRules)
+ {
+ for (var i = 0, length=inspectedRules.length; i < length; ++i)
+ {
+ var ruleId = inspectedRules[i];
+ var ruleData = CssAnalyzer.getRuleData(ruleId);
+ var rule = ruleData.rule;
+
+ var ssid = ruleData.styleSheetId;
+ var parentStyleSheet = StyleSheetCache.get(ssid);
+
+ var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline
+
+ var instance = null;
+ //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument);
+
+ var isSystemSheet = false;
+ //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet);
+
+ if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules
+ continue;
+
+ if (!href)
+ href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452
+
+ var props = this.getRuleProperties(this.context, rule, inheritMode);
+ if (inheritMode && !props.length)
+ continue;
+
+ //
+ //var line = domUtils.getRuleLine(rule);
+ // TODO: xxxpedro CSS line number
+ var line = ruleData.lineNo;
+
+ var ruleId = rule.selectorText+"/"+line;
+ var sourceLink = new SourceLink(href, line, "css", rule, instance);
+
+ this.markOverridenProps(props, usedProps, inheritMode);
+
+ rules.splice(0, 0, {rule: rule, id: ruleId,
+ selector: ruleData.selector, sourceLink: sourceLink,
+ props: props, inherited: inheritMode,
+ isSystemSheet: isSystemSheet});
+ }
+ }
+
+ if (element.style)
+ this.getStyleProperties(element, rules, usedProps, inheritMode);
+
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules);
+ },
+ /*
+ getElementRules: function(element, rules, usedProps, inheritMode)
+ {
+ var inspectedRules, displayedRules = {};
+ try
+ {
+ inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null;
+ } catch (exc) {}
+
+ if (inspectedRules)
+ {
+ for (var i = 0; i < inspectedRules.Count(); ++i)
+ {
+ var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule);
+
+ var href = rule.parentStyleSheet.href; // Null means inline
+
+ var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument);
+
+ var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet);
+ if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules
+ continue;
+ if (!href)
+ href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452
+
+ var props = this.getRuleProperties(this.context, rule, inheritMode);
+ if (inheritMode && !props.length)
+ continue;
+
+ var line = domUtils.getRuleLine(rule);
+ var ruleId = rule.selectorText+"/"+line;
+ var sourceLink = new SourceLink(href, line, "css", rule, instance);
+
+ this.markOverridenProps(props, usedProps, inheritMode);
+
+ rules.splice(0, 0, {rule: rule, id: ruleId,
+ selector: rule.selectorText, sourceLink: sourceLink,
+ props: props, inherited: inheritMode,
+ isSystemSheet: isSystemSheet});
+ }
+ }
+
+ if (element.style)
+ this.getStyleProperties(element, rules, usedProps, inheritMode);
+
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules);
+ },
+ /**/
+ markOverridenProps: function(props, usedProps, inheritMode)
+ {
+ for (var i = 0; i < props.length; ++i)
+ {
+ var prop = props[i];
+ if ( usedProps.hasOwnProperty(prop.name) )
+ {
+ var deadProps = usedProps[prop.name]; // all previous occurrences of this property
+ for (var j = 0; j < deadProps.length; ++j)
+ {
+ var deadProp = deadProps[j];
+ if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important)
+ prop.overridden = true; // new occurrence overridden
+ else if (!prop.disabled)
+ deadProp.overridden = true; // previous occurrences overridden
+ }
+ }
+ else
+ usedProps[prop.name] = [];
+
+ prop.wasInherited = inheritMode ? true : false;
+ usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name
+ }
+ },
+
+ getStyleProperties: function(element, rules, usedProps, inheritMode)
+ {
+ var props = this.parseCSSProps(element.style, inheritMode);
+ this.addOldProperties(this.context, getElementXPath(element), inheritMode, props);
+
+ sortProperties(props);
+ this.markOverridenProps(props, usedProps, inheritMode);
+
+ if (props.length)
+ rules.splice(0, 0,
+ {rule: element, id: getElementXPath(element),
+ selector: "element.style", props: props, inherited: inheritMode});
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "css",
+ title: "Style",
+ parentPanel: "HTML",
+ order: 0,
+
+ initialize: function()
+ {
+ this.context = Firebug.chrome; // TODO: xxxpedro css2
+ this.document = Firebug.chrome.document; // TODO: xxxpedro css2
+
+ Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments);
+
+ // TODO: xxxpedro css2
+ var selection = ElementCache.get(Firebug.context.persistedState.selectedHTMLElementId);
+ if (selection)
+ this.select(selection, true);
+
+ //this.updateCascadeView(document.getElementsByTagName("h1")[0]);
+ //this.updateCascadeView(document.getElementById("build"));
+
+ /*
+ this.onStateChange = bindFixed(this.contentStateCheck, this);
+ this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER);
+ this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE);
+ /**/
+ },
+
+ ishow: function(state)
+ {
+ },
+
+ watchWindow: function(win)
+ {
+ if (domUtils)
+ {
+ // Normally these would not be required, but in order to update after the state is set
+ // using the options menu we need to monitor these global events as well
+ var doc = win.document;
+ ///addEvent(doc, "mouseover", this.onHoverChange);
+ ///addEvent(doc, "mousedown", this.onActiveChange);
+ }
+ },
+ unwatchWindow: function(win)
+ {
+ var doc = win.document;
+ ///removeEvent(doc, "mouseover", this.onHoverChange);
+ ///removeEvent(doc, "mousedown", this.onActiveChange);
+
+ if (isAncestor(this.stateChangeEl, doc))
+ {
+ this.removeStateChangeHandlers();
+ }
+ },
+
+ supportsObject: function(object)
+ {
+ return object instanceof Element ? 1 : 0;
+ },
+
+ updateView: function(element)
+ {
+ this.updateCascadeView(element);
+ if (domUtils)
+ {
+ this.contentState = safeGetContentState(element);
+ this.addStateChangeHandlers(element);
+ }
+ },
+
+ updateSelection: function(element)
+ {
+ if ( !instanceOf(element , "Element") ) // html supports SourceLink
+ return;
+
+ if (sothinkInstalled)
+ {
+ FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode);
+ return;
+ }
+
+ /*
+ if (!domUtils)
+ {
+ FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode);
+ return;
+ }
+ /**/
+
+ if (!element)
+ return;
+
+ this.updateView(element);
+ },
+
+ updateOption: function(name, value)
+ {
+ if (name == "showUserAgentCSS" || name == "expandShorthandProps")
+ this.refresh();
+ },
+
+ getOptionsMenuItems: function()
+ {
+ var ret = [
+ {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS,
+ command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") },
+ {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps,
+ command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }
+ ];
+ if (domUtils && this.selection)
+ {
+ var state = safeGetContentState(this.selection);
+
+ ret.push("-");
+ ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE,
+ command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)});
+ ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER,
+ command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)});
+ }
+ return ret;
+ },
+
+ updateContentState: function(state, remove)
+ {
+ domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state);
+ this.refresh();
+ },
+
+ addStateChangeHandlers: function(el)
+ {
+ this.removeStateChangeHandlers();
+
+ /*
+ addEvent(el, "focus", this.onStateChange);
+ addEvent(el, "blur", this.onStateChange);
+ addEvent(el, "mouseup", this.onStateChange);
+ addEvent(el, "mousedown", this.onStateChange);
+ addEvent(el, "mouseover", this.onStateChange);
+ addEvent(el, "mouseout", this.onStateChange);
+ /**/
+
+ this.stateChangeEl = el;
+ },
+
+ removeStateChangeHandlers: function()
+ {
+ var sel = this.stateChangeEl;
+ if (sel)
+ {
+ /*
+ removeEvent(sel, "focus", this.onStateChange);
+ removeEvent(sel, "blur", this.onStateChange);
+ removeEvent(sel, "mouseup", this.onStateChange);
+ removeEvent(sel, "mousedown", this.onStateChange);
+ removeEvent(sel, "mouseover", this.onStateChange);
+ removeEvent(sel, "mouseout", this.onStateChange);
+ /**/
+ }
+ },
+
+ contentStateCheck: function(state)
+ {
+ if (!state || this.contentState & state)
+ {
+ var timeoutRunner = bindFixed(function()
+ {
+ var newState = safeGetContentState(this.selection);
+ if (newState != this.contentState)
+ {
+ this.context.invalidatePanels(this.name);
+ }
+ }, this);
+
+ // Delay exec until after the event has processed and the state has been updated
+ setTimeout(timeoutRunner, 0);
+ }
+ }
+});
+
+function safeGetContentState(selection)
+{
+ try
+ {
+ return domUtils.getContentState(selection);
+ }
+ catch (e)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("css.safeGetContentState; EXCEPTION", e);
+ }
+}
+
+// ************************************************************************************************
+
+function CSSComputedElementPanel() {}
+
+CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype,
+{
+ template: domplate(
+ {
+ computedTag:
+ DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')},
+ FOR("group", "$groups",
+ H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"},
+ SPAN({"class": "cssInheritLabel"}, "$group.title")
+ ),
+ TABLE({width: "100%", role : 'group'},
+ TBODY({role : 'presentation'},
+ FOR("prop", "$group.props",
+ TR({"class": 'focusRow computedStyleRow', role : 'listitem'},
+ TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"),
+ TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value")
+ )
+ )
+ )
+ )
+ )
+ )
+ }),
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ updateComputedView: function(element)
+ {
+ var win = isIE ?
+ element.ownerDocument.parentWindow :
+ element.ownerDocument.defaultView;
+
+ var style = isIE ?
+ element.currentStyle :
+ win.getComputedStyle(element, "");
+
+ var groups = [];
+
+ for (var groupName in styleGroups)
+ {
+ // TODO: xxxpedro i18n $STR
+ //var title = $STR("StyleGroup-" + groupName);
+ var title = styleGroupTitles[groupName];
+ var group = {title: title, props: []};
+ groups.push(group);
+
+ var props = styleGroups[groupName];
+ for (var i = 0; i < props.length; ++i)
+ {
+ var propName = props[i];
+ var propValue = style.getPropertyValue ?
+ style.getPropertyValue(propName) :
+ ""+style[toCamelCase(propName)];
+
+ if (propValue === undefined || propValue === null)
+ continue;
+
+ propValue = stripUnits(rgbToHex(propValue));
+ if (propValue)
+ group.props.push({name: propName, value: propValue});
+ }
+ }
+
+ var result = this.template.computedTag.replace({groups: groups}, this.panelNode);
+ //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "computed",
+ title: "Computed",
+ parentPanel: "HTML",
+ order: 1,
+
+ updateView: function(element)
+ {
+ this.updateComputedView(element);
+ },
+
+ getOptionsMenuItems: function()
+ {
+ return [
+ {label: "Refresh", command: bind(this.refresh, this) }
+ ];
+ }
+});
+
+// ************************************************************************************************
+// CSSEditor
+
+function CSSEditor(doc)
+{
+ this.initializeInline(doc);
+}
+
+CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype,
+{
+ insertNewRow: function(target, insertWhere)
+ {
+ var rule = Firebug.getRepObject(target);
+ var emptyProp =
+ {
+ // TODO: xxxpedro - uses charCode(255) to force the element being rendered,
+ // allowing webkit to get the correct position of the property name "span",
+ // when inserting a new CSS rule?
+ name: "",
+ value: "",
+ important: ""
+ };
+
+ if (insertWhere == "before")
+ return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target);
+ else
+ return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target);
+ },
+
+ saveEdit: function(target, value, previousValue)
+ {
+ // We need to check the value first in order to avoid a problem in IE8
+ // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite
+ if (!value) return;
+
+ target.innerHTML = escapeForCss(value);
+
+ var row = getAncestorByClass(target, "cssProp");
+ if (hasClass(row, "disabledStyle"))
+ toggleClass(row, "disabledStyle");
+
+ var rule = Firebug.getRepObject(target);
+
+ if (hasClass(target, "cssPropName"))
+ {
+ if (value && previousValue != value) // name of property has changed.
+ {
+ var propValue = getChildByClass(row, "cssPropValue")[textContent];
+ var parsedValue = parsePriority(propValue);
+
+ if (propValue && propValue != "undefined") {
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n");
+ if (previousValue)
+ Firebug.CSSModule.removeProperty(rule, previousValue);
+ Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority);
+ }
+ }
+ else if (!value) // name of the property has been deleted, so remove the property.
+ Firebug.CSSModule.removeProperty(rule, previousValue);
+ }
+ else if (getAncestorByClass(target, "cssPropValue"))
+ {
+ var propName = getChildByClass(row, "cssPropName")[textContent];
+ var propValue = getChildByClass(row, "cssPropValue")[textContent];
+
+ if (FBTrace.DBG_CSS)
+ {
+ FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n");
+ // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style);
+ }
+
+ if (value && value != "null")
+ {
+ var parsedValue = parsePriority(value);
+ Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);
+ }
+ else if (previousValue && previousValue != "null")
+ Firebug.CSSModule.removeProperty(rule, propName);
+ }
+
+ this.panel.markChange(this.panel.name == "stylesheet");
+ },
+
+ advanceToNext: function(target, charCode)
+ {
+ if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName"))
+ return true;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ getAutoCompleteRange: function(value, offset)
+ {
+ if (hasClass(this.target, "cssPropName"))
+ return {start: 0, end: value.length-1};
+ else
+ return parseCSSValue(value, offset);
+ },
+
+ getAutoCompleteList: function(preExpr, expr, postExpr)
+ {
+ if (hasClass(this.target, "cssPropName"))
+ {
+ return getCSSPropertyNames();
+ }
+ else
+ {
+ var row = getAncestorByClass(this.target, "cssProp");
+ var propName = getChildByClass(row, "cssPropName")[textContent];
+ return getCSSKeywordsByProperty(propName);
+ }
+ }
+});
+
+//************************************************************************************************
+//CSSRuleEditor
+
+function CSSRuleEditor(doc)
+{
+ this.initializeInline(doc);
+ this.completeAsYouType = false;
+}
+CSSRuleEditor.uniquifier = 0;
+CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype,
+{
+ insertNewRow: function(target, insertWhere)
+ {
+ var emptyRule = {
+ selector: "",
+ id: "",
+ props: [],
+ isSelectorEditable: true
+ };
+
+ if (insertWhere == "before")
+ return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target);
+ else
+ return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target);
+ },
+
+ saveEdit: function(target, value, previousValue)
+ {
+ if (FBTrace.DBG_CSS)
+ FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target);
+
+ target.innerHTML = escapeForCss(value);
+
+ if (value === previousValue) return;
+
+ var row = getAncestorByClass(target, "cssRule");
+ var styleSheet = this.panel.location;
+ styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet;
+
+ var cssRules = styleSheet.cssRules;
+ var rule = Firebug.getRepObject(target), oldRule = rule;
+ var ruleIndex = cssRules.length;
+ if (rule || Firebug.getRepObject(row.nextSibling))
+ {
+ var searchRule = rule || Firebug.getRepObject(row.nextSibling);
+ for (ruleIndex=0; ruleIndex<cssRules.length && searchRule!=cssRules[ruleIndex]; ruleIndex++) {}
+ }
+
+ // Delete in all cases except for new add
+ // We want to do this before the insert to ease change tracking
+ if (oldRule)
+ {
+ Firebug.CSSModule.deleteRule(styleSheet, ruleIndex);
+ }
+
+ // Firefox does not follow the spec for the update selector text case.
+ // When attempting to update the value, firefox will silently fail.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=37468 for the quite
+ // old discussion of this bug.
+ // As a result we need to recreate the style every time the selector
+ // changes.
+ if (value)
+ {
+ var cssText = [ value, "{" ];
+ var props = row.getElementsByClassName("cssProp");
+ for (var i = 0; i < props.length; i++) {
+ var propEl = props[i];
+ if (!hasClass(propEl, "disabledStyle")) {
+ cssText.push(getChildByClass(propEl, "cssPropName")[textContent]);
+ cssText.push(":");
+ cssText.push(getChildByClass(propEl, "cssPropValue")[textContent]);
+ cssText.push(";");
+ }
+ }
+ cssText.push("}");
+ cssText = cssText.join("");
+
+ try
+ {
+ var insertLoc = Firebug.CSSModule.insertRule(styleSheet, cssText, ruleIndex);
+ rule = cssRules[insertLoc];
+ ruleIndex++;
+ }
+ catch (err)
+ {
+ if (FBTrace.DBG_CSS || FBTrace.DBG_ERRORS)
+ FBTrace.sysout("CSS Insert Error: "+err, err);
+
+ target.innerHTML = escapeForCss(previousValue);
+ row.repObject = undefined;
+ return;
+ }
+ } else {
+ rule = undefined;
+ }
+
+ // Update the rep object
+ row.repObject = rule;
+ if (!oldRule)
+ {
+ // Who knows what the domutils will return for rule line
+ // for a recently created rule. To be safe we just generate
+ // a unique value as this is only used as an internal key.
+ var ruleId = "new/"+value+"/"+(++CSSRuleEditor.uniquifier);
+ row.setAttribute("ruleId", ruleId);
+ }
+
+ this.panel.markChange(this.panel.name == "stylesheet");
+ }
+});
+
+// ************************************************************************************************
+// StyleSheetEditor
+
+function StyleSheetEditor(doc)
+{
+ this.box = this.tag.replace({}, doc, this);
+ this.input = this.box.firstChild;
+}
+
+StyleSheetEditor.prototype = domplate(Firebug.BaseEditor,
+{
+ multiLine: true,
+
+ tag: DIV(
+ TEXTAREA({"class": "styleSheetEditor fullPanelEditor", oninput: "$onInput"})
+ ),
+
+ getValue: function()
+ {
+ return this.input.value;
+ },
+
+ setValue: function(value)
+ {
+ return this.input.value = value;
+ },
+
+ show: function(target, panel, value, textSize, targetSize)
+ {
+ this.target = target;
+ this.panel = panel;
+
+ this.panel.panelNode.appendChild(this.box);
+
+ this.input.value = value;
+ this.input.focus();
+
+ var command = Firebug.chrome.$("cmd_toggleCSSEditing");
+ command.setAttribute("checked", true);
+ },
+
+ hide: function()
+ {
+ var command = Firebug.chrome.$("cmd_toggleCSSEditing");
+ command.setAttribute("checked", false);
+
+ if (this.box.parentNode == this.panel.panelNode)
+ this.panel.panelNode.removeChild(this.box);
+
+ delete this.target;
+ delete this.panel;
+ delete this.styleSheet;
+ },
+
+ saveEdit: function(target, value, previousValue)
+ {
+ Firebug.CSSModule.freeEdit(this.styleSheet, value);
+ },
+
+ endEditing: function()
+ {
+ this.panel.refresh();
+ return true;
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onInput: function()
+ {
+ Firebug.Editor.update();
+ },
+
+ scrollToLine: function(line, offset)
+ {
+ this.startMeasuring(this.input);
+ var lineHeight = this.measureText().height;
+ this.stopMeasuring();
+
+ this.input.scrollTop = (line * lineHeight) + offset;
+ }
+});
+
+// ************************************************************************************************
+// Local Helpers
+
+var rgbToHex = function rgbToHex(value)
+{
+ return value.replace(/\brgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)/gi, rgbToHexReplacer);
+};
+
+var rgbToHexReplacer = function(_, r, g, b) {
+ return '#' + ((1 << 24) + (r << 16) + (g << 8) + (b << 0)).toString(16).substr(-6).toUpperCase();
+};
+
+var stripUnits = function stripUnits(value)
+{
+ // remove units from '0px', '0em' etc. leave non-zero units in-tact.
+ return value.replace(/(url\(.*?\)|[^0]\S*\s*)|0(%|em|ex|px|in|cm|mm|pt|pc)(\s|$)/gi, stripUnitsReplacer);
+};
+
+var stripUnitsReplacer = function(_, skip, remove, whitespace) {
+ return skip || ('0' + whitespace);
+};
+
+function parsePriority(value)
+{
+ var rePriority = /(.*?)\s*(!important)?$/;
+ var m = rePriority.exec(value);
+ var propValue = m ? m[1] : "";
+ var priority = m && m[2] ? "important" : "";
+ return {value: propValue, priority: priority};
+}
+
+function parseURLValue(value)
+{
+ var m = reURL.exec(value);
+ return m ? m[1] : "";
+}
+
+function parseRepeatValue(value)
+{
+ var m = reRepeat.exec(value);
+ return m ? m[0] : "";
+}
+
+function parseCSSValue(value, offset)
+{
+ var start = 0;
+ var m;
+ while (1)
+ {
+ m = reSplitCSS.exec(value);
+ if (m && m.index+m[0].length < offset)
+ {
+ value = value.substr(m.index+m[0].length);
+ start += m.index+m[0].length;
+ offset -= m.index+m[0].length;
+ }
+ else
+ break;
+ }
+
+ if (m)
+ {
+ var type;
+ if (m[1])
+ type = "url";
+ else if (m[2] || m[3])
+ type = "rgb";
+ else if (m[4])
+ type = "int";
+
+ return {value: m[0], start: start+m.index, end: start+m.index+(m[0].length-1), type: type};
+ }
+}
+
+function findPropByName(props, name)
+{
+ for (var i = 0; i < props.length; ++i)
+ {
+ if (props[i].name == name)
+ return i;
+ }
+}
+
+function sortProperties(props)
+{
+ props.sort(function(a, b)
+ {
+ return a.name > b.name ? 1 : -1;
+ });
+}
+
+function getTopmostRuleLine(panelNode)
+{
+ for (var child = panelNode.firstChild; child; child = child.nextSibling)
+ {
+ if (child.offsetTop+child.offsetHeight > panelNode.scrollTop)
+ {
+ var rule = child.repObject;
+ if (rule)
+ return {
+ line: domUtils.getRuleLine(rule),
+ offset: panelNode.scrollTop-child.offsetTop
+ };
+ }
+ }
+ return 0;
+}
+
+function getStyleSheetCSS(sheet, context)
+{
+ if (sheet.ownerNode instanceof HTMLStyleElement)
+ return sheet.ownerNode.innerHTML;
+ else
+ return context.sourceCache.load(sheet.href).join("");
+}
+
+function getStyleSheetOwnerNode(sheet) {
+ for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet);
+
+ return sheet.ownerNode;
+}
+
+function scrollSelectionIntoView(panel)
+{
+ var selCon = getSelectionController(panel);
+ selCon.scrollSelectionIntoView(
+ nsISelectionController.SELECTION_NORMAL,
+ nsISelectionController.SELECTION_FOCUS_REGION, true);
+}
+
+function getSelectionController(panel)
+{
+ var browser = Firebug.chrome.getPanelBrowser(panel);
+ return browser.docShell.QueryInterface(nsIInterfaceRequestor)
+ .getInterface(nsISelectionDisplay)
+ .QueryInterface(nsISelectionController);
+}
+
+// ************************************************************************************************
+
+Firebug.registerModule(Firebug.CSSModule);
+Firebug.registerPanel(Firebug.CSSStyleSheetPanel);
+Firebug.registerPanel(CSSElementPanel);
+Firebug.registerPanel(CSSComputedElementPanel);
+
+// ************************************************************************************************
+
+}});
+
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Script Module
+
+Firebug.Script = extend(Firebug.Module,
+{
+ getPanel: function()
+ {
+ return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null;
+ },
+
+ selectSourceCode: function(index)
+ {
+ this.getPanel().selectSourceCode(index);
+ }
+});
+
+Firebug.registerModule(Firebug.Script);
+
+
+// ************************************************************************************************
+// Script Panel
+
+function ScriptPanel(){};
+
+ScriptPanel.prototype = extend(Firebug.Panel,
+{
+ name: "Script",
+ title: "Script",
+
+ selectIndex: 0, // index of the current selectNode's option
+ sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script")
+
+ options: {
+ hasToolButtons: true
+ },
+
+ create: function()
+ {
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.onChangeSelect = bind(this.onChangeSelect, this);
+
+ var doc = Firebug.browser.document;
+ var scripts = doc.getElementsByTagName("script");
+ var selectNode = this.selectNode = createElement("select");
+
+ for(var i=0, script; script=scripts[i]; i++)
+ {
+ // Don't show Firebug Lite source code in the list of options
+ if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore"))
+ continue;
+
+ var fileName = getFileName(script.src) || getFileName(doc.location.href);
+ var option = createElement("option", {value:i});
+
+ option.appendChild(Firebug.chrome.document.createTextNode(fileName));
+ selectNode.appendChild(option);
+ };
+
+ this.toolButtonsNode.appendChild(selectNode);
+ },
+
+ initialize: function()
+ {
+ // we must render the code first, so the persistent state can be restore
+ this.selectSourceCode(this.selectIndex);
+
+ Firebug.Panel.initialize.apply(this, arguments);
+
+ addEvent(this.selectNode, "change", this.onChangeSelect);
+ },
+
+ shutdown: function()
+ {
+ removeEvent(this.selectNode, "change", this.onChangeSelect);
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+ },
+
+ detach: function(oldChrome, newChrome)
+ {
+ Firebug.Panel.detach.apply(this, arguments);
+
+ var oldPanel = oldChrome.getPanel("Script");
+ var index = oldPanel.selectIndex;
+
+ this.selectNode.selectedIndex = index;
+ this.selectIndex = index;
+ this.sourceIndex = -1;
+ },
+
+ onChangeSelect: function(event)
+ {
+ var select = this.selectNode;
+
+ this.selectIndex = select.selectedIndex;
+
+ var option = select.options[select.selectedIndex];
+ if (!option)
+ return;
+
+ var selectedSourceIndex = parseInt(option.value);
+
+ this.renderSourceCode(selectedSourceIndex);
+ },
+
+ selectSourceCode: function(index)
+ {
+ var select = this.selectNode;
+ select.selectedIndex = index;
+
+ var option = select.options[index];
+ if (!option)
+ return;
+
+ var selectedSourceIndex = parseInt(option.value);
+
+ this.renderSourceCode(selectedSourceIndex);
+ },
+
+ renderSourceCode: function(index)
+ {
+ if (this.sourceIndex != index)
+ {
+ var renderProcess = function renderProcess(src)
+ {
+ var html = [],
+ hl = 0;
+
+ src = isIE && !isExternal ?
+ src+'\n' : // IE put an extra line when reading source of local resources
+ '\n'+src;
+
+ // find the number of lines of code
+ src = src.replace(/\n\r|\r\n/g, "\n");
+ var match = src.match(/[\n]/g);
+ var lines=match ? match.length : 0;
+
+ // render the full source code + line numbers html
+ html[hl++] = '<div><div class="sourceBox" style="left:';
+ html[hl++] = 35 + 7*(lines+'').length;
+ html[hl++] = 'px;"><pre class="sourceCode">';
+ html[hl++] = escapeHTML(src);
+ html[hl++] = '</pre></div><div class="lineNo">';
+
+ // render the line number divs
+ for(var l=1, lines; l<=lines; l++)
+ {
+ html[hl++] = '<div line="';
+ html[hl++] = l;
+ html[hl++] = '">';
+ html[hl++] = l;
+ html[hl++] = '</div>';
+ }
+
+ html[hl++] = '</div></div>';
+
+ updatePanel(html);
+ };
+
+ var updatePanel = function(html)
+ {
+ self.panelNode.innerHTML = html.join("");
+
+ // IE needs this timeout, otherwise the panel won't scroll
+ setTimeout(function(){
+ self.synchronizeUI();
+ },0);
+ };
+
+ var onFailure = function()
+ {
+ FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode);
+ };
+
+ var self = this;
+
+ var doc = Firebug.browser.document;
+ var script = doc.getElementsByTagName("script")[index];
+ var url = getScriptURL(script);
+ var isExternal = url && url != doc.location.href;
+
+ try
+ {
+ if (Firebug.disableResourceFetching)
+ {
+ renderProcess(Firebug.Lite.Proxy.fetchResourceDisabledMessage);
+ }
+ else if (isExternal)
+ {
+ Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure});
+ }
+ else
+ {
+ var src = script.innerHTML;
+ renderProcess(src);
+ }
+ }
+ catch(e)
+ {
+ onFailure();
+ }
+
+ this.sourceIndex = index;
+ }
+ }
+});
+
+Firebug.registerPanel(ScriptPanel);
+
+
+// ************************************************************************************************
+
+
+var getScriptURL = function getScriptURL(script)
+{
+ var reFile = /([^\/\?#]+)(#.+)?$/;
+ var rePath = /^(.*\/)/;
+ var reProtocol = /^\w+:\/\//;
+ var path = null;
+ var doc = Firebug.browser.document;
+
+ var file = reFile.exec(script.src);
+
+ if (file)
+ {
+ var fileName = file[1];
+ var fileOptions = file[2];
+
+ // absolute path
+ if (reProtocol.test(script.src)) {
+ path = rePath.exec(script.src)[1];
+
+ }
+ // relative path
+ else
+ {
+ var r = rePath.exec(script.src);
+ var src = r ? r[1] : script.src;
+ var backDir = /^((?:\.\.\/)+)(.*)/.exec(src);
+ var reLastDir = /^(.*\/)[^\/]+\/$/;
+ path = rePath.exec(doc.location.href)[1];
+
+ // "../some/path"
+ if (backDir)
+ {
+ var j = backDir[1].length/3;
+ var p;
+ while (j-- > 0)
+ path = reLastDir.exec(path)[1];
+
+ path += backDir[2];
+ }
+
+ else if(src.indexOf("/") != -1)
+ {
+ // "./some/path"
+ if(/^\.\/./.test(src))
+ {
+ path += src.substring(2);
+ }
+ // "/some/path"
+ else if(/^\/./.test(src))
+ {
+ var domain = /^(\w+:\/\/[^\/]+)/.exec(path);
+ path = domain[1] + src;
+ }
+ // "some/path"
+ else
+ {
+ path += src;
+ }
+ }
+ }
+ }
+
+ var m = path && path.match(/([^\/]+)\/$/) || null;
+
+ if (path && m)
+ {
+ return path + fileName;
+ }
+};
+
+var getFileName = function getFileName(path)
+{
+ if (!path) return "";
+
+ var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/);
+
+ return match && match[0] || path;
+};
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var ElementCache = Firebug.Lite.Cache.Element;
+
+var insertSliceSize = 18;
+var insertInterval = 40;
+
+var ignoreVars =
+{
+ "__firebug__": 1,
+ "eval": 1,
+
+ // We are forced to ignore Java-related variables, because
+ // trying to access them causes browser freeze
+ "java": 1,
+ "sun": 1,
+ "Packages": 1,
+ "JavaArray": 1,
+ "JavaMember": 1,
+ "JavaObject": 1,
+ "JavaClass": 1,
+ "JavaPackage": 1,
+ "_firebug": 1,
+ "_FirebugConsole": 1,
+ "_FirebugCommandLine": 1
+};
+
+if (Firebug.ignoreFirebugElements)
+ ignoreVars[Firebug.Lite.Cache.ID] = 1;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+var memberPanelRep =
+ isIE6 ?
+ {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"}
+ :
+ {"class": "memberLabel $member.type\\Label"};
+
+var RowTag =
+ TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation',
+ level: "$member.level"},
+ TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'},
+ A(memberPanelRep,
+ SPAN({}, "$member.name")
+ )
+ ),
+ TD({"class": "memberValueCell", role : 'presentation'},
+ TAG("$member.tag", {object: "$member.value"})
+ )
+ );
+
+var WatchRowTag =
+ TR({"class": "watchNewRow", level: 0},
+ TD({"class": "watchEditCell", colspan: 2},
+ DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0',
+ 'aria-label' : $STR('press enter to add new watch expression')},
+ $STR("NewWatch")
+ )
+ )
+ );
+
+var SizerRow =
+ TR({role : 'presentation'},
+ TD({width: "30%"}),
+ TD({width: "70%"})
+ );
+
+var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable";
+var DirTablePlate = domplate(Firebug.Rep,
+{
+ tag:
+ TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"},
+ TBODY({role: 'presentation'},
+ SizerRow,
+ FOR("member", "$object|memberIterator", RowTag)
+ )
+ ),
+
+ watchTag:
+ TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0,
+ _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'},
+ TBODY({role : 'presentation'},
+ SizerRow,
+ WatchRowTag
+ )
+ ),
+
+ tableTag:
+ TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0,
+ _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'},
+ TBODY({role : 'presentation'},
+ SizerRow
+ )
+ ),
+
+ rowTag:
+ FOR("member", "$members", RowTag),
+
+ memberIterator: function(object, level)
+ {
+ return getMembers(object, level);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onClick: function(event)
+ {
+ if (!isLeftClick(event))
+ return;
+
+ var target = event.target || event.srcElement;
+
+ var row = getAncestorByClass(target, "memberRow");
+ var label = getAncestorByClass(target, "memberLabel");
+ if (label && hasClass(row, "hasChildren"))
+ {
+ var row = label.parentNode.parentNode;
+ this.toggleRow(row);
+ }
+ else
+ {
+ var object = Firebug.getRepObject(target);
+ if (typeof(object) == "function")
+ {
+ Firebug.chrome.select(object, "script");
+ cancelEvent(event);
+ }
+ else if (event.detail == 2 && !object)
+ {
+ var panel = row.parentNode.parentNode.domPanel;
+ if (panel)
+ {
+ var rowValue = panel.getRowPropertyValue(row);
+ if (typeof(rowValue) == "boolean")
+ panel.setPropertyValue(row, !rowValue);
+ else
+ panel.editProperty(row);
+
+ cancelEvent(event);
+ }
+ }
+ }
+
+ return false;
+ },
+
+ toggleRow: function(row)
+ {
+ var level = parseInt(row.getAttribute("level"));
+ var toggles = row.parentNode.parentNode.toggles;
+
+ if (hasClass(row, "opened"))
+ {
+ removeClass(row, "opened");
+
+ if (toggles)
+ {
+ var path = getPath(row);
+
+ // Remove the path from the toggle tree
+ for (var i = 0; i < path.length; ++i)
+ {
+ if (i == path.length-1)
+ delete toggles[path[i]];
+ else
+ toggles = toggles[path[i]];
+ }
+ }
+
+ var rowTag = this.rowTag;
+ var tbody = row.parentNode;
+
+ setTimeout(function()
+ {
+ for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling)
+ {
+ if (parseInt(firstRow.getAttribute("level")) <= level)
+ break;
+
+ tbody.removeChild(firstRow);
+ }
+ }, row.insertTimeout ? row.insertTimeout : 0);
+ }
+ else
+ {
+ setClass(row, "opened");
+
+ if (toggles)
+ {
+ var path = getPath(row);
+
+ // Mark the path in the toggle tree
+ for (var i = 0; i < path.length; ++i)
+ {
+ var name = path[i];
+ if (toggles.hasOwnProperty(name))
+ toggles = toggles[name];
+ else
+ toggles = toggles[name] = {};
+ }
+ }
+
+ var value = row.lastChild.firstChild.repObject;
+ var members = getMembers(value, level+1);
+
+ var rowTag = this.rowTag;
+ var lastRow = row;
+
+ var delay = 0;
+ //var setSize = members.length;
+ //var rowCount = 1;
+ while (members.length)
+ {
+ with({slice: members.splice(0, insertSliceSize), isLast: !members.length})
+ {
+ setTimeout(function()
+ {
+ if (lastRow.parentNode)
+ {
+ var result = rowTag.insertRows({members: slice}, lastRow);
+ lastRow = result[1];
+ //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]);
+ //rowCount += insertSliceSize;
+ }
+ if (isLast)
+ row.removeAttribute("insertTimeout");
+ }, delay);
+ }
+
+ delay += insertInterval;
+ }
+
+ row.insertTimeout = delay;
+ }
+ }
+});
+
+
+
+// ************************************************************************************************
+
+Firebug.DOMBasePanel = function() {};
+
+Firebug.DOMBasePanel.prototype = extend(Firebug.Panel,
+{
+ tag: DirTablePlate.tableTag,
+
+ getRealObject: function(object)
+ {
+ // TODO: Move this to some global location
+ // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc.
+ // TODO: We might be able to make this check more authoritative with QueryInterface.
+ if (!object) return object;
+ if (object.wrappedJSObject) return object.wrappedJSObject;
+ return object;
+ },
+
+ rebuild: function(update, scrollTop)
+ {
+ //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]);
+ var members = getMembers(this.selection);
+ expandMembers(members, this.toggles, 0, 0);
+
+ this.showMembers(members, update, scrollTop);
+
+ //TODO: xxxpedro statusbar
+ if (!this.parentPanel)
+ updateStatusBar(this);
+ },
+
+ showMembers: function(members, update, scrollTop)
+ {
+ // If we are still in the midst of inserting rows, cancel all pending
+ // insertions here - this is a big speedup when stepping in the debugger
+ if (this.timeouts)
+ {
+ for (var i = 0; i < this.timeouts.length; ++i)
+ this.context.clearTimeout(this.timeouts[i]);
+ delete this.timeouts;
+ }
+
+ if (!members.length)
+ return this.showEmptyMembers();
+
+ var panelNode = this.panelNode;
+ var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop;
+
+ // If we are asked to "update" the current view, then build the new table
+ // offscreen and swap it in when it's done
+ var offscreen = update && panelNode.firstChild;
+ var dest = offscreen ? panelNode.ownerDocument : panelNode;
+
+ var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest);
+ var tbody = table.lastChild;
+ var rowTag = DirTablePlate.rowTag;
+
+ // Insert the first slice immediately
+ //var slice = members.splice(0, insertSliceSize);
+ //var result = rowTag.insertRows({members: slice}, tbody.lastChild);
+
+ //var setSize = members.length;
+ //var rowCount = 1;
+
+ var panel = this;
+ var result;
+
+ //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
+ var timeouts = [];
+
+ var delay = 0;
+
+ // enable to measure rendering performance
+ var renderStart = new Date().getTime();
+ while (members.length)
+ {
+ with({slice: members.splice(0, insertSliceSize), isLast: !members.length})
+ {
+ timeouts.push(this.context.setTimeout(function()
+ {
+ // TODO: xxxpedro can this be a timing error related to the
+ // "iteration number" approach insted of "duration time"?
+ // avoid error in IE8
+ if (!tbody.lastChild) return;
+
+ result = rowTag.insertRows({members: slice}, tbody.lastChild);
+
+ //rowCount += insertSliceSize;
+ //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
+
+ if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop)
+ panelNode.scrollTop = priorScrollTop;
+
+
+ // enable to measure rendering performance
+ //if (isLast) alert(new Date().getTime() - renderStart + "ms");
+
+
+ }, delay));
+
+ delay += insertInterval;
+ }
+ }
+
+ if (offscreen)
+ {
+ timeouts.push(this.context.setTimeout(function()
+ {
+ if (panelNode.firstChild)
+ panelNode.replaceChild(table, panelNode.firstChild);
+ else
+ panelNode.appendChild(table);
+
+ // Scroll back to where we were before
+ panelNode.scrollTop = priorScrollTop;
+ }, delay));
+ }
+ else
+ {
+ timeouts.push(this.context.setTimeout(function()
+ {
+ panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop;
+ }, delay));
+ }
+ this.timeouts = timeouts;
+ },
+
+ /*
+ // new
+ showMembers: function(members, update, scrollTop)
+ {
+ // If we are still in the midst of inserting rows, cancel all pending
+ // insertions here - this is a big speedup when stepping in the debugger
+ if (this.timeouts)
+ {
+ for (var i = 0; i < this.timeouts.length; ++i)
+ this.context.clearTimeout(this.timeouts[i]);
+ delete this.timeouts;
+ }
+
+ if (!members.length)
+ return this.showEmptyMembers();
+
+ var panelNode = this.panelNode;
+ var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop;
+
+ // If we are asked to "update" the current view, then build the new table
+ // offscreen and swap it in when it's done
+ var offscreen = update && panelNode.firstChild;
+ var dest = offscreen ? panelNode.ownerDocument : panelNode;
+
+ var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest);
+ var tbody = table.lastChild;
+ var rowTag = DirTablePlate.rowTag;
+
+ // Insert the first slice immediately
+ //var slice = members.splice(0, insertSliceSize);
+ //var result = rowTag.insertRows({members: slice}, tbody.lastChild);
+
+ //var setSize = members.length;
+ //var rowCount = 1;
+
+ var panel = this;
+ var result;
+
+ //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
+ var timeouts = [];
+
+ var delay = 0;
+ var _insertSliceSize = insertSliceSize;
+ var _insertInterval = insertInterval;
+
+ // enable to measure rendering performance
+ var renderStart = new Date().getTime();
+ var lastSkip = renderStart, now;
+
+ while (members.length)
+ {
+ with({slice: members.splice(0, _insertSliceSize), isLast: !members.length})
+ {
+ var _tbody = tbody;
+ var _rowTag = rowTag;
+ var _panelNode = panelNode;
+ var _priorScrollTop = priorScrollTop;
+
+ timeouts.push(this.context.setTimeout(function()
+ {
+ // TODO: xxxpedro can this be a timing error related to the
+ // "iteration number" approach insted of "duration time"?
+ // avoid error in IE8
+ if (!_tbody.lastChild) return;
+
+ result = _rowTag.insertRows({members: slice}, _tbody.lastChild);
+
+ //rowCount += _insertSliceSize;
+ //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
+
+ if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop)
+ _panelNode.scrollTop = _priorScrollTop;
+
+
+ // enable to measure rendering performance
+ //alert("gap: " + (new Date().getTime() - lastSkip));
+ //lastSkip = new Date().getTime();
+
+ //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms");
+
+ }, delay));
+
+ delay += _insertInterval;
+ }
+ }
+
+ if (offscreen)
+ {
+ timeouts.push(this.context.setTimeout(function()
+ {
+ if (panelNode.firstChild)
+ panelNode.replaceChild(table, panelNode.firstChild);
+ else
+ panelNode.appendChild(table);
+
+ // Scroll back to where we were before
+ panelNode.scrollTop = priorScrollTop;
+ }, delay));
+ }
+ else
+ {
+ timeouts.push(this.context.setTimeout(function()
+ {
+ panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop;
+ }, delay));
+ }
+ this.timeouts = timeouts;
+ },
+ /**/
+
+ showEmptyMembers: function()
+ {
+ FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode);
+ },
+
+ findPathObject: function(object)
+ {
+ var pathIndex = -1;
+ for (var i = 0; i < this.objectPath.length; ++i)
+ {
+ // IE needs === instead of == or otherwise some objects will
+ // be considered equal to different objects, returning the
+ // wrong index of the objectPath array
+ if (this.getPathObject(i) === object)
+ return i;
+ }
+
+ return -1;
+ },
+
+ getPathObject: function(index)
+ {
+ var object = this.objectPath[index];
+
+ if (object instanceof Property)
+ return object.getObject();
+ else
+ return object;
+ },
+
+ getRowObject: function(row)
+ {
+ var object = getRowOwnerObject(row);
+ return object ? object : this.selection;
+ },
+
+ getRowPropertyValue: function(row)
+ {
+ var object = this.getRowObject(row);
+ object = this.getRealObject(object);
+ if (object)
+ {
+ var propName = getRowName(row);
+
+ if (object instanceof jsdIStackFrame)
+ return Firebug.Debugger.evaluate(propName, this.context);
+ else
+ return object[propName];
+ }
+ },
+ /*
+ copyProperty: function(row)
+ {
+ var value = this.getRowPropertyValue(row);
+ copyToClipboard(value);
+ },
+
+ editProperty: function(row, editValue)
+ {
+ if (hasClass(row, "watchNewRow"))
+ {
+ if (this.context.stopped)
+ Firebug.Editor.startEditing(row, "");
+ else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line
+ {
+ if (Firebug.CommandLine.onCommandLineFocus())
+ Firebug.Editor.startEditing(row, "");
+ else
+ row.innerHTML = $STR("warning.Command line blocked?");
+ }
+ else
+ row.innerHTML = $STR("warning.Console must be enabled");
+ }
+ else if (hasClass(row, "watchRow"))
+ Firebug.Editor.startEditing(row, getRowName(row));
+ else
+ {
+ var object = this.getRowObject(row);
+ this.context.thisValue = object;
+
+ if (!editValue)
+ {
+ var propValue = this.getRowPropertyValue(row);
+
+ var type = typeof(propValue);
+ if (type == "undefined" || type == "number" || type == "boolean")
+ editValue = propValue;
+ else if (type == "string")
+ editValue = "\"" + escapeJS(propValue) + "\"";
+ else if (propValue == null)
+ editValue = "null";
+ else if (object instanceof Window || object instanceof jsdIStackFrame)
+ editValue = getRowName(row);
+ else
+ editValue = "this." + getRowName(row);
+ }
+
+
+ Firebug.Editor.startEditing(row, editValue);
+ }
+ },
+
+ deleteProperty: function(row)
+ {
+ if (hasClass(row, "watchRow"))
+ this.deleteWatch(row);
+ else
+ {
+ var object = getRowOwnerObject(row);
+ if (!object)
+ object = this.selection;
+ object = this.getRealObject(object);
+
+ if (object)
+ {
+ var name = getRowName(row);
+ try
+ {
+ delete object[name];
+ }
+ catch (exc)
+ {
+ return;
+ }
+
+ this.rebuild(true);
+ this.markChange();
+ }
+ }
+ },
+
+ setPropertyValue: function(row, value) // value must be string
+ {
+ if(FBTrace.DBG_DOM)
+ {
+ FBTrace.sysout("row: "+row);
+ FBTrace.sysout("value: "+value+" type "+typeof(value), value);
+ }
+
+ var name = getRowName(row);
+ if (name == "this")
+ return;
+
+ var object = this.getRowObject(row);
+ object = this.getRealObject(object);
+ if (object && !(object instanceof jsdIStackFrame))
+ {
+ // unwrappedJSObject.property = unwrappedJSObject
+ Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(),
+ function success(result, context)
+ {
+ if (FBTrace.DBG_DOM)
+ FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result);
+ object[name] = result;
+ },
+ function failed(exc, context)
+ {
+ try
+ {
+ if (FBTrace.DBG_DOM)
+ FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc);
+ // If the value doesn't parse, then just store it as a string. Some users will
+ // not realize they're supposed to enter a JavaScript expression and just type
+ // literal text
+ object[name] = String(value); // unwrappedJSobject.property = string
+ }
+ catch (exc)
+ {
+ return;
+ }
+ }
+ );
+ }
+ else if (this.context.stopped)
+ {
+ try
+ {
+ Firebug.CommandLine.evaluate(name+"="+value, this.context);
+ }
+ catch (exc)
+ {
+ try
+ {
+ // See catch block above...
+ object[name] = String(value); // unwrappedJSobject.property = string
+ }
+ catch (exc)
+ {
+ return;
+ }
+ }
+ }
+
+ this.rebuild(true);
+ this.markChange();
+ },
+
+ highlightRow: function(row)
+ {
+ if (this.highlightedRow)
+ cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context);
+
+ this.highlightedRow = row;
+
+ if (row)
+ setClassTimed(row, "jumpHighlight", this.context);
+ },/**/
+
+ onMouseMove: function(event)
+ {
+ var target = event.srcElement || event.target;
+
+ var object = getAncestorByClass(target, "objectLink-element");
+ object = object ? object.repObject : null;
+
+ if(object && instanceOf(object, "Element") && object.nodeType == 1)
+ {
+ if(object != lastHighlightedObject)
+ {
+ Firebug.Inspector.drawBoxModel(object);
+ object = lastHighlightedObject;
+ }
+ }
+ else
+ Firebug.Inspector.hideBoxModel();
+
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ create: function()
+ {
+ // TODO: xxxpedro
+ this.context = Firebug.browser;
+
+ this.objectPath = [];
+ this.propertyPath = [];
+ this.viewPath = [];
+ this.pathIndex = -1;
+ this.toggles = {};
+
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.panelNode.style.padding = "0 1px";
+ },
+
+ initialize: function(){
+ Firebug.Panel.initialize.apply(this, arguments);
+
+ addEvent(this.panelNode, "mousemove", this.onMouseMove);
+ },
+
+ shutdown: function()
+ {
+ removeEvent(this.panelNode, "mousemove", this.onMouseMove);
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+ },
+
+ /*
+ destroy: function(state)
+ {
+ var view = this.viewPath[this.pathIndex];
+ if (view && this.panelNode.scrollTop)
+ view.scrollTop = this.panelNode.scrollTop;
+
+ if (this.pathIndex)
+ state.pathIndex = this.pathIndex;
+ if (this.viewPath)
+ state.viewPath = this.viewPath;
+ if (this.propertyPath)
+ state.propertyPath = this.propertyPath;
+
+ if (this.propertyPath.length > 0 && !this.propertyPath[1])
+ state.firstSelection = persistObject(this.getPathObject(1), this.context);
+
+ Firebug.Panel.destroy.apply(this, arguments);
+ },
+ /**/
+
+ ishow: function(state)
+ {
+ if (this.context.loaded && !this.selection)
+ {
+ if (!state)
+ {
+ this.select(null);
+ return;
+ }
+ if (state.viewPath)
+ this.viewPath = state.viewPath;
+ if (state.propertyPath)
+ this.propertyPath = state.propertyPath;
+
+ var defaultObject = this.getDefaultSelection(this.context);
+ var selectObject = defaultObject;
+
+ if (state.firstSelection)
+ {
+ var restored = state.firstSelection(this.context);
+ if (restored)
+ {
+ selectObject = restored;
+ this.objectPath = [defaultObject, restored];
+ }
+ else
+ this.objectPath = [defaultObject];
+ }
+ else
+ this.objectPath = [defaultObject];
+
+ if (this.propertyPath.length > 1)
+ {
+ for (var i = 1; i < this.propertyPath.length; ++i)
+ {
+ var name = this.propertyPath[i];
+ if (!name)
+ continue;
+
+ var object = selectObject;
+ try
+ {
+ selectObject = object[name];
+ }
+ catch (exc)
+ {
+ selectObject = null;
+ }
+
+ if (selectObject)
+ {
+ this.objectPath.push(new Property(object, name));
+ }
+ else
+ {
+ // If we can't access a property, just stop
+ this.viewPath.splice(i);
+ this.propertyPath.splice(i);
+ this.objectPath.splice(i);
+ selectObject = this.getPathObject(this.objectPath.length-1);
+ break;
+ }
+ }
+ }
+
+ var selection = state.pathIndex <= this.objectPath.length-1
+ ? this.getPathObject(state.pathIndex)
+ : this.getPathObject(this.objectPath.length-1);
+
+ this.select(selection);
+ }
+ },
+ /*
+ hide: function()
+ {
+ var view = this.viewPath[this.pathIndex];
+ if (view && this.panelNode.scrollTop)
+ view.scrollTop = this.panelNode.scrollTop;
+ },
+ /**/
+
+ supportsObject: function(object)
+ {
+ if (object == null)
+ return 1000;
+
+ if (typeof(object) == "undefined")
+ return 1000;
+ else if (object instanceof SourceLink)
+ return 0;
+ else
+ return 1; // just agree to support everything but not agressively.
+ },
+
+ refresh: function()
+ {
+ this.rebuild(true);
+ },
+
+ updateSelection: function(object)
+ {
+ var previousIndex = this.pathIndex;
+ var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex];
+
+ var newPath = this.pathToAppend;
+ delete this.pathToAppend;
+
+ var pathIndex = this.findPathObject(object);
+ if (newPath || pathIndex == -1)
+ {
+ this.toggles = {};
+
+ if (newPath)
+ {
+ // Remove everything after the point where we are inserting, so we
+ // essentially replace it with the new path
+ if (previousView)
+ {
+ if (this.panelNode.scrollTop)
+ previousView.scrollTop = this.panelNode.scrollTop;
+
+ var start = previousIndex + 1,
+ // Opera needs the length argument in splice(), otherwise
+ // it will consider that only one element should be removed
+ length = this.objectPath.length - start;
+
+ this.objectPath.splice(start, length);
+ this.propertyPath.splice(start, length);
+ this.viewPath.splice(start, length);
+ }
+
+ var value = this.getPathObject(previousIndex);
+ if (!value)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n");
+ return;
+ }
+
+ for (var i = 0, length = newPath.length; i < length; ++i)
+ {
+ var name = newPath[i];
+ var object = value;
+ try
+ {
+ value = value[name];
+ }
+ catch(exc)
+ {
+ if (FBTrace.DBG_ERRORS)
+ FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n");
+ return;
+ }
+
+ ++this.pathIndex;
+ this.objectPath.push(new Property(object, name));
+ this.propertyPath.push(name);
+ this.viewPath.push({toggles: this.toggles, scrollTop: 0});
+ }
+ }
+ else
+ {
+ this.toggles = {};
+
+ var win = Firebug.browser.window;
+ //var win = this.context.getGlobalScope();
+ if (object === win)
+ {
+ this.pathIndex = 0;
+ this.objectPath = [win];
+ this.propertyPath = [null];
+ this.viewPath = [{toggles: this.toggles, scrollTop: 0}];
+ }
+ else
+ {
+ this.pathIndex = 1;
+ this.objectPath = [win, object];
+ this.propertyPath = [null, null];
+ this.viewPath = [
+ {toggles: {}, scrollTop: 0},
+ {toggles: this.toggles, scrollTop: 0}
+ ];
+ }
+ }
+
+ this.panelNode.scrollTop = 0;
+ this.rebuild();
+ }
+ else
+ {
+ this.pathIndex = pathIndex;
+
+ var view = this.viewPath[pathIndex];
+ this.toggles = view.toggles;
+
+ // Persist the current scroll location
+ if (previousView && this.panelNode.scrollTop)
+ previousView.scrollTop = this.panelNode.scrollTop;
+
+ this.rebuild(false, view.scrollTop);
+ }
+ },
+
+ getObjectPath: function(object)
+ {
+ return this.objectPath;
+ },
+
+ getDefaultSelection: function()
+ {
+ return Firebug.browser.window;
+ //return this.context.getGlobalScope();
+ }/*,
+
+ updateOption: function(name, value)
+ {
+ const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1,
+ showDOMFuncs: 1, showDOMConstants: 1};
+ if ( optionMap.hasOwnProperty(name) )
+ this.rebuild(true);
+ },
+
+ getOptionsMenuItems: function()
+ {
+ return [
+ optionMenu("ShowUserProps", "showUserProps"),
+ optionMenu("ShowUserFuncs", "showUserFuncs"),
+ optionMenu("ShowDOMProps", "showDOMProps"),
+ optionMenu("ShowDOMFuncs", "showDOMFuncs"),
+ optionMenu("ShowDOMConstants", "showDOMConstants"),
+ "-",
+ {label: "Refresh", command: bindFixed(this.rebuild, this, true) }
+ ];
+ },
+
+ getContextMenuItems: function(object, target)
+ {
+ var row = getAncestorByClass(target, "memberRow");
+
+ var items = [];
+
+ if (row)
+ {
+ var rowName = getRowName(row);
+ var rowObject = this.getRowObject(row);
+ var rowValue = this.getRowPropertyValue(row);
+
+ var isWatch = hasClass(row, "watchRow");
+ var isStackFrame = rowObject instanceof jsdIStackFrame;
+
+ if (typeof(rowValue) == "string" || typeof(rowValue) == "number")
+ {
+ // Functions already have a copy item in their context menu
+ items.push(
+ "-",
+ {label: "CopyValue",
+ command: bindFixed(this.copyProperty, this, row) }
+ );
+ }
+
+ items.push(
+ "-",
+ {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"),
+ command: bindFixed(this.editProperty, this, row) }
+ );
+
+ if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName)))
+ {
+ items.push(
+ {label: isWatch ? "DeleteWatch" : "DeleteProperty",
+ command: bindFixed(this.deleteProperty, this, row) }
+ );
+ }
+ }
+
+ items.push(
+ "-",
+ {label: "Refresh", command: bindFixed(this.rebuild, this, true) }
+ );
+
+ return items;
+ },
+
+ getEditor: function(target, value)
+ {
+ if (!this.editor)
+ this.editor = new DOMEditor(this.document);
+
+ return this.editor;
+ }/**/
+});
+
+// ************************************************************************************************
+
+// TODO: xxxpedro statusbar
+var updateStatusBar = function(panel)
+{
+ var path = panel.propertyPath;
+ var index = panel.pathIndex;
+
+ var r = [];
+
+ for (var i=0, l=path.length; i<l; i++)
+ {
+ r.push(i==index ? '<a class="fbHover fbButton fbBtnSelected" ' : '<a class="fbHover fbButton" ');
+ r.push('pathIndex=');
+ r.push(i);
+
+ if(isIE6)
+ r.push(' href="javascript:void(0)"');
+
+ r.push('>');
+ r.push(i==0 ? "window" : path[i] || "Object");
+ r.push('</a>');
+
+ if(i < l-1)
+ r.push('<span class="fbStatusSeparator">&gt;</span>');
+ }
+ panel.statusBarNode.innerHTML = r.join("");
+};
+
+
+var DOMMainPanel = Firebug.DOMPanel = function () {};
+
+Firebug.DOMPanel.DirTable = DirTablePlate;
+
+DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype,
+{
+ onClickStatusBar: function(event)
+ {
+ var target = event.srcElement || event.target;
+ var element = getAncestorByClass(target, "fbHover");
+
+ if(element)
+ {
+ var pathIndex = element.getAttribute("pathIndex");
+
+ if(pathIndex)
+ {
+ this.select(this.getPathObject(pathIndex));
+ }
+ }
+ },
+
+ selectRow: function(row, target)
+ {
+ if (!target)
+ target = row.lastChild.firstChild;
+
+ if (!target || !target.repObject)
+ return;
+
+ this.pathToAppend = getPath(row);
+
+ // If the object is inside an array, look up its index
+ var valueBox = row.lastChild.firstChild;
+ if (hasClass(valueBox, "objectBox-array"))
+ {
+ var arrayIndex = FirebugReps.Arr.getItemIndex(target);
+ this.pathToAppend.push(arrayIndex);
+ }
+
+ // Make sure we get a fresh status path for the object, since otherwise
+ // it might find the object in the existing path and not refresh it
+ //Firebug.chrome.clearStatusPath();
+
+ this.select(target.repObject, true);
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onClick: function(event)
+ {
+ var target = event.srcElement || event.target;
+ var repNode = Firebug.getRepNode(target);
+ if (repNode)
+ {
+ var row = getAncestorByClass(target, "memberRow");
+ if (row)
+ {
+ this.selectRow(row, repNode);
+ cancelEvent(event);
+ }
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "DOM",
+ title: "DOM",
+ searchable: true,
+ statusSeparator: ">",
+
+ options: {
+ hasToolButtons: true,
+ hasStatusBar: true
+ },
+
+ create: function()
+ {
+ Firebug.DOMBasePanel.prototype.create.apply(this, arguments);
+
+ this.onClick = bind(this.onClick, this);
+
+ //TODO: xxxpedro
+ this.onClickStatusBar = bind(this.onClickStatusBar, this);
+
+ this.panelNode.style.padding = "0 1px";
+ },
+
+ initialize: function(oldPanelNode)
+ {
+ //this.panelNode.addEventListener("click", this.onClick, false);
+ //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']);
+
+ Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
+
+ addEvent(this.panelNode, "click", this.onClick);
+
+ // TODO: xxxpedro dom
+ this.ishow();
+
+ //TODO: xxxpedro
+ addEvent(this.statusBarNode, "click", this.onClickStatusBar);
+ },
+
+ shutdown: function()
+ {
+ //this.panelNode.removeEventListener("click", this.onClick, false);
+ //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']);
+
+ removeEvent(this.panelNode, "click", this.onClick);
+
+ Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments);
+ }/*,
+
+ search: function(text, reverse)
+ {
+ if (!text)
+ {
+ delete this.currentSearch;
+ this.highlightRow(null);
+ return false;
+ }
+
+ var row;
+ if (this.currentSearch && text == this.currentSearch.text)
+ row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive);
+ else
+ {
+ function findRow(node) { return getAncestorByClass(node, "memberRow"); }
+ this.currentSearch = new TextSearch(this.panelNode, findRow);
+ row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive);
+ }
+
+ if (row)
+ {
+ var sel = this.document.defaultView.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(this.currentSearch.range);
+
+ scrollIntoCenterView(row, this.panelNode);
+
+ this.highlightRow(row);
+ dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]);
+ return true;
+ }
+ else
+ {
+ dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]);
+ return false;
+ }
+ }/**/
+});
+
+Firebug.registerPanel(DOMMainPanel);
+
+
+// ************************************************************************************************
+
+
+
+// ************************************************************************************************
+// Local Helpers
+
+var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket
+{
+ if (!level)
+ level = 0;
+
+ var ordinals = [], userProps = [], userClasses = [], userFuncs = [],
+ domProps = [], domFuncs = [], domConstants = [];
+
+ try
+ {
+ var domMembers = getDOMMembers(object);
+ //var domMembers = {}; // TODO: xxxpedro
+ //var domConstantMap = {}; // TODO: xxxpedro
+
+ if (object.wrappedJSObject)
+ var insecureObject = object.wrappedJSObject;
+ else
+ var insecureObject = object;
+
+ // IE function prototype is not listed in (for..in)
+ if (isIE && isFunction(object))
+ addMember("user", userProps, "prototype", object.prototype, level);
+
+ for (var name in insecureObject) // enumeration is safe
+ {
+ if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined.
+ continue;
+
+ var val;
+ try
+ {
+ val = insecureObject[name]; // getter is safe
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions trying to access certain members
+ if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM)
+ FBTrace.sysout("dom.getMembers cannot access "+name, exc);
+ }
+
+ var ordinal = parseInt(name);
+ if (ordinal || ordinal == 0)
+ {
+ addMember("ordinal", ordinals, name, val, level);
+ }
+ else if (isFunction(val))
+ {
+ if (isClassFunction(val) && !(name in domMembers))
+ addMember("userClass", userClasses, name, val, level);
+ else if (name in domMembers)
+ addMember("domFunction", domFuncs, name, val, level, domMembers[name]);
+ else
+ addMember("userFunction", userFuncs, name, val, level);
+ }
+ else
+ {
+ //TODO: xxxpedro
+ /*
+ var getterFunction = insecureObject.__lookupGetter__(name),
+ setterFunction = insecureObject.__lookupSetter__(name),
+ prefix = "";
+
+ if(getterFunction && !setterFunction)
+ prefix = "get ";
+ /**/
+
+ var prefix = "";
+
+ if (name in domMembers && !(name in domConstantMap))
+ addMember("dom", domProps, (prefix+name), val, level, domMembers[name]);
+ else if (name in domConstantMap)
+ addMember("dom", domConstants, (prefix+name), val, level);
+ else
+ addMember("user", userProps, (prefix+name), val, level);
+ }
+ }
+ }
+ catch (exc)
+ {
+ // Sometimes we get exceptions just from trying to iterate the members
+ // of certain objects, like StorageList, but don't let that gum up the works
+ throw exc;
+ if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM)
+ FBTrace.sysout("dom.getMembers FAILS: ", exc);
+ //throw exc;
+ }
+
+ function sortName(a, b) { return a.name > b.name ? 1 : -1; }
+ function sortOrder(a, b) { return a.order > b.order ? 1 : -1; }
+
+ var members = [];
+
+ members.push.apply(members, ordinals);
+
+ Firebug.showUserProps = true; // TODO: xxxpedro
+ Firebug.showUserFuncs = true; // TODO: xxxpedro
+ Firebug.showDOMProps = true;
+ Firebug.showDOMFuncs = true;
+ Firebug.showDOMConstants = true;
+
+ if (Firebug.showUserProps)
+ {
+ userProps.sort(sortName);
+ members.push.apply(members, userProps);
+ }
+
+ if (Firebug.showUserFuncs)
+ {
+ userClasses.sort(sortName);
+ members.push.apply(members, userClasses);
+
+ userFuncs.sort(sortName);
+ members.push.apply(members, userFuncs);
+ }
+
+ if (Firebug.showDOMProps)
+ {
+ domProps.sort(sortName);
+ members.push.apply(members, domProps);
+ }
+
+ if (Firebug.showDOMFuncs)
+ {
+ domFuncs.sort(sortName);
+ members.push.apply(members, domFuncs);
+ }
+
+ if (Firebug.showDOMConstants)
+ members.push.apply(members, domConstants);
+
+ return members;
+};
+
+function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0
+{
+ var expanded = 0;
+ for (var i = offset; i < members.length; ++i)
+ {
+ var member = members[i];
+ if (member.level > level)
+ break;
+
+ if ( toggles.hasOwnProperty(member.name) )
+ {
+ member.open = "opened"; // member.level <= level && member.name in toggles.
+
+ var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1
+
+ var args = [i+1, 0];
+ args.push.apply(args, newMembers);
+ members.splice.apply(members, args);
+
+ /*
+ if (FBTrace.DBG_DOM)
+ {
+ FBTrace.sysout("expandMembers member.name", member.name);
+ FBTrace.sysout("expandMembers toggles", toggles);
+ FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]);
+ FBTrace.sysout("dom.expandedMembers level: "+level+" member", member);
+ }
+ /**/
+
+ expanded += newMembers.length;
+ i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1);
+ }
+ }
+
+ return expanded;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+
+function isClassFunction(fn)
+{
+ try
+ {
+ for (var name in fn.prototype)
+ return true;
+ } catch (exc) {}
+ return false;
+}
+
+// FIXME: xxxpedro This function is already defined in Lib. If we keep this definition here, it
+// will crash IE9 when not running the IE Developer Tool with JavaScript Debugging enabled!!!
+// Check if this function is in fact defined in Firebug for Firefox. If so, we should remove
+// this from here. The only difference of this function is the IE hack to show up the prototype
+// of functions, but Firebug no longer shows the prototype for simple functions.
+//var hasProperties = function hasProperties(ob)
+//{
+// try
+// {
+// for (var name in ob)
+// return true;
+// } catch (exc) {}
+//
+// // IE function prototype is not listed in (for..in)
+// if (isFunction(ob)) return true;
+//
+// return false;
+//};
+
+FBL.ErrorCopy = function(message)
+{
+ this.message = message;
+};
+
+var addMember = function addMember(type, props, name, value, level, order)
+{
+ var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents
+ var tag = rep.shortTag ? rep.shortTag : rep.tag;
+
+ var ErrorCopy = function(){}; //TODO: xxxpedro
+
+ var valueType = typeof(value);
+ var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) &&
+ (isFunction(value) || (valueType == "object" && value != null)
+ || (valueType == "string" && value.length > Firebug.stringCropLength));
+
+ props.push({
+ name: name,
+ value: value,
+ type: type,
+ rowClass: "memberRow-"+type,
+ open: "",
+ order: order,
+ level: level,
+ indent: level*16,
+ hasChildren: hasChildren,
+ tag: tag
+ });
+};
+
+var getWatchRowIndex = function getWatchRowIndex(row)
+{
+ var index = -1;
+ for (; row && hasClass(row, "watchRow"); row = row.previousSibling)
+ ++index;
+ return index;
+};
+
+var getRowName = function getRowName(row)
+{
+ var node = row.firstChild;
+ return node.textContent ? node.textContent : node.innerText;
+};
+
+var getRowValue = function getRowValue(row)
+{
+ return row.lastChild.firstChild.repObject;
+};
+
+var getRowOwnerObject = function getRowOwnerObject(row)
+{
+ var parentRow = getParentRow(row);
+ if (parentRow)
+ return getRowValue(parentRow);
+};
+
+var getParentRow = function getParentRow(row)
+{
+ var level = parseInt(row.getAttribute("level"))-1;
+ for (row = row.previousSibling; row; row = row.previousSibling)
+ {
+ if (parseInt(row.getAttribute("level")) == level)
+ return row;
+ }
+};
+
+var getPath = function getPath(row)
+{
+ var name = getRowName(row);
+ var path = [name];
+
+ var level = parseInt(row.getAttribute("level"))-1;
+ for (row = row.previousSibling; row; row = row.previousSibling)
+ {
+ if (parseInt(row.getAttribute("level")) == level)
+ {
+ var name = getRowName(row);
+ path.splice(0, 0, name);
+
+ --level;
+ }
+ }
+
+ return path;
+};
+
+// ************************************************************************************************
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+
+// ************************************************************************************************
+// DOM Module
+
+Firebug.DOM = extend(Firebug.Module,
+{
+ getPanel: function()
+ {
+ return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null;
+ }
+});
+
+Firebug.registerModule(Firebug.DOM);
+
+
+// ************************************************************************************************
+// DOM Panel
+
+var lastHighlightedObject;
+
+function DOMSidePanel(){};
+
+DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype,
+{
+ selectRow: function(row, target)
+ {
+ if (!target)
+ target = row.lastChild.firstChild;
+
+ if (!target || !target.repObject)
+ return;
+
+ this.pathToAppend = getPath(row);
+
+ // If the object is inside an array, look up its index
+ var valueBox = row.lastChild.firstChild;
+ if (hasClass(valueBox, "objectBox-array"))
+ {
+ var arrayIndex = FirebugReps.Arr.getItemIndex(target);
+ this.pathToAppend.push(arrayIndex);
+ }
+
+ // Make sure we get a fresh status path for the object, since otherwise
+ // it might find the object in the existing path and not refresh it
+ //Firebug.chrome.clearStatusPath();
+
+ var object = target.repObject;
+
+ if (instanceOf(object, "Element"))
+ {
+ Firebug.HTML.selectTreeNode(ElementCache(object));
+ }
+ else
+ {
+ Firebug.chrome.selectPanel("DOM");
+ Firebug.chrome.getPanel("DOM").select(object, true);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ onClick: function(event)
+ {
+ /*
+ var target = event.srcElement || event.target;
+
+ var object = getAncestorByClass(target, "objectLink");
+ object = object ? object.repObject : null;
+
+ if(!object) return;
+
+ if (instanceOf(object, "Element"))
+ {
+ Firebug.HTML.selectTreeNode(ElementCache(object));
+ }
+ else
+ {
+ Firebug.chrome.selectPanel("DOM");
+ Firebug.chrome.getPanel("DOM").select(object, true);
+ }
+ /**/
+
+
+ var target = event.srcElement || event.target;
+ var repNode = Firebug.getRepNode(target);
+ if (repNode)
+ {
+ var row = getAncestorByClass(target, "memberRow");
+ if (row)
+ {
+ this.selectRow(row, repNode);
+ cancelEvent(event);
+ }
+ }
+ /**/
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // extends Panel
+
+ name: "DOMSidePanel",
+ parentPanel: "HTML",
+ title: "DOM",
+
+ options: {
+ hasToolButtons: true
+ },
+
+ isInitialized: false,
+
+ create: function()
+ {
+ Firebug.DOMBasePanel.prototype.create.apply(this, arguments);
+
+ this.onClick = bind(this.onClick, this);
+ },
+
+ initialize: function(){
+ Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
+
+ addEvent(this.panelNode, "click", this.onClick);
+
+ // TODO: xxxpedro css2
+ var selection = ElementCache.get(Firebug.context.persistedState.selectedHTMLElementId);
+ if (selection)
+ this.select(selection, true);
+ },
+
+ shutdown: function()
+ {
+ removeEvent(this.panelNode, "click", this.onClick);
+
+ Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments);
+ },
+
+ reattach: function(oldChrome)
+ {
+ //this.isInitialized = oldChrome.getPanel("DOM").isInitialized;
+ this.toggles = oldChrome.getPanel("DOMSidePanel").toggles;
+ }
+
+});
+
+Firebug.registerPanel(DOMSidePanel);
+
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.FBTrace = {};
+
+(function() {
+// ************************************************************************************************
+
+var traceOptions = {
+ DBG_TIMESTAMP: 1,
+ DBG_INITIALIZE: 1,
+ DBG_CHROME: 1,
+ DBG_ERRORS: 1,
+ DBG_DISPATCH: 1,
+ DBG_CSS: 1
+};
+
+this.module = null;
+
+this.initialize = function()
+{
+ if (!this.messageQueue)
+ this.messageQueue = [];
+
+ for (var name in traceOptions)
+ this[name] = traceOptions[name];
+};
+
+// ************************************************************************************************
+// FBTrace API
+
+this.sysout = function()
+{
+ return this.logFormatted(arguments, "");
+};
+
+this.dumpProperties = function(title, object)
+{
+ return this.logFormatted("dumpProperties() not supported.", "warning");
+};
+
+this.dumpStack = function()
+{
+ return this.logFormatted("dumpStack() not supported.", "warning");
+};
+
+this.flush = function(module)
+{
+ this.module = module;
+
+ var queue = this.messageQueue;
+ this.messageQueue = [];
+
+ for (var i = 0; i < queue.length; ++i)
+ this.writeMessage(queue[i][0], queue[i][1], queue[i][2]);
+};
+
+this.getPanel = function()
+{
+ return this.module ? this.module.getPanel() : null;
+};
+
+//*************************************************************************************************
+
+this.logFormatted = function(objects, className)
+{
+ var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : [];
+ var length = objects.length;
+
+ for (var i = 0; i < length; ++i)
+ {
+ appendText(" ", html);
+
+ var object = objects[i];
+
+ if (i == 0)
+ {
+ html.push("<b>");
+ appendText(object, html);
+ html.push("</b>");
+ }
+ else
+ appendText(object, html);
+ }
+
+ return this.logRow(html, className);
+};
+
+this.logRow = function(message, className)
+{
+ var panel = this.getPanel();
+
+ if (panel && panel.panelNode)
+ this.writeMessage(message, className);
+ else
+ {
+ this.messageQueue.push([message, className]);
+ }
+
+ return this.LOG_COMMAND;
+};
+
+this.writeMessage = function(message, className)
+{
+ var container = this.getPanel().containerNode;
+ var isScrolledToBottom =
+ container.scrollTop + container.offsetHeight >= container.scrollHeight;
+
+ this.writeRow.call(this, message, className);
+
+ if (isScrolledToBottom)
+ container.scrollTop = container.scrollHeight - container.offsetHeight;
+};
+
+this.appendRow = function(row)
+{
+ var container = this.getPanel().panelNode;
+ container.appendChild(row);
+};
+
+this.writeRow = function(message, className)
+{
+ var row = this.getPanel().panelNode.ownerDocument.createElement("div");
+ row.className = "logRow" + (className ? " logRow-"+className : "");
+ row.innerHTML = message.join("");
+ this.appendRow(row);
+};
+
+//*************************************************************************************************
+
+function appendText(object, html)
+{
+ html.push(escapeHTML(objectToString(object)));
+};
+
+function getTimestamp()
+{
+ var now = new Date();
+ var ms = "" + (now.getMilliseconds() / 1000).toFixed(3);
+ ms = ms.substr(2);
+
+ return now.toLocaleTimeString() + "." + ms;
+};
+
+//*************************************************************************************************
+
+var HTMLtoEntity =
+{
+ "<": "&lt;",
+ ">": "&gt;",
+ "&": "&amp;",
+ "'": "&#39;",
+ '"': "&quot;"
+};
+
+function replaceChars(ch)
+{
+ return HTMLtoEntity[ch];
+};
+
+function escapeHTML(value)
+{
+ return (value+"").replace(/[<>&"']/g, replaceChars);
+};
+
+//*************************************************************************************************
+
+function objectToString(object)
+{
+ try
+ {
+ return object+"";
+ }
+ catch (exc)
+ {
+ return null;
+ }
+};
+
+// ************************************************************************************************
+}).apply(FBL.FBTrace);
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// If application isn't in trace mode, the FBTrace panel won't be loaded
+if (!Env.Options.enableTrace) return;
+
+// ************************************************************************************************
+// FBTrace Module
+
+Firebug.Trace = extend(Firebug.Module,
+{
+ getPanel: function()
+ {
+ return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null;
+ },
+
+ clear: function()
+ {
+ this.getPanel().panelNode.innerHTML = "";
+ }
+});
+
+Firebug.registerModule(Firebug.Trace);
+
+
+// ************************************************************************************************
+// FBTrace Panel
+
+function TracePanel(){};
+
+TracePanel.prototype = extend(Firebug.Panel,
+{
+ name: "Trace",
+ title: "Trace",
+
+ options: {
+ hasToolButtons: true,
+ innerHTMLSync: true
+ },
+
+ create: function(){
+ Firebug.Panel.create.apply(this, arguments);
+
+ this.clearButton = new Button({
+ caption: "Clear",
+ title: "Clear FBTrace logs",
+ owner: Firebug.Trace,
+ onClick: Firebug.Trace.clear
+ });
+ },
+
+ initialize: function(){
+ Firebug.Panel.initialize.apply(this, arguments);
+
+ this.clearButton.initialize();
+ },
+
+ shutdown: function()
+ {
+ this.clearButton.shutdown();
+
+ Firebug.Panel.shutdown.apply(this, arguments);
+ }
+
+});
+
+Firebug.registerPanel(TracePanel);
+
+// ************************************************************************************************
+}});
+
+/* See license.txt for terms of usage */
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+// ************************************************************************************************
+// Globals
+
+var modules = [];
+var panelTypes = [];
+var panelTypeMap = {};
+
+var parentPanelMap = {};
+
+
+var registerModule = Firebug.registerModule;
+var registerPanel = Firebug.registerPanel;
+
+// ************************************************************************************************
+append(Firebug,
+{
+ extend: function(fn)
+ {
+ if (Firebug.chrome && Firebug.chrome.addPanel)
+ {
+ var namespace = ns(fn);
+ fn.call(namespace, FBL);
+ }
+ else
+ {
+ setTimeout(function(){Firebug.extend(fn);},100);
+ }
+ },
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ // Registration
+
+ registerModule: function()
+ {
+ registerModule.apply(Firebug, arguments);
+
+ modules.push.apply(modules, arguments);
+
+ dispatch(modules, "initialize", []);
+
+ if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule");
+ },
+
+ registerPanel: function()
+ {
+ registerPanel.apply(Firebug, arguments);
+
+ panelTypes.push.apply(panelTypes, arguments);
+
+ for (var i = 0, panelType; panelType = arguments[i]; ++i)
+ {
+ // TODO: xxxpedro investigate why Dev Panel throws an error
+ if (panelType.prototype.name == "Dev") continue;
+
+ panelTypeMap[panelType.prototype.name] = arguments[i];
+
+ var parentPanelName = panelType.prototype.parentPanel;
+ if (parentPanelName)
+ {
+ parentPanelMap[parentPanelName] = 1;
+ }
+ else
+ {
+ var panelName = panelType.prototype.name;
+ var chrome = Firebug.chrome;
+ chrome.addPanel(panelName);
+
+ // tab click handler
+ var onTabClick = function onTabClick()
+ {
+ chrome.selectPanel(panelName);
+ return false;
+ };
+
+ chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]);
+ }
+ }
+
+ if (FBTrace.DBG_INITIALIZE)
+ for (var i = 0; i < arguments.length; ++i)
+ FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name);
+ }
+
+});
+
+
+
+
+// ************************************************************************************************
+}});
+
+FBL.ns(function() { with (FBL) {
+// ************************************************************************************************
+
+FirebugChrome.Skin =
+{
+ CSS: '.obscured{left:-999999px !important;}.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;line-height:13px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) no-repeat !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;line-height:13px;}#fbPanelBarBox{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;line-height:13px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em/1.4545em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}',
+ HTML: '<table id="fbChrome" cellpadding="0" cellspacing="0" border="0"><tbody><tr><td id="fbTop" colspan="2"><div id="fbWindowButtons"><a id="fbWindow_btDeactivate" class="fbSmallButton fbHover" title="Deactivate Firebug for this web page">&nbsp;</a><a id="fbWindow_btDetach" class="fbSmallButton fbHover" title="Open Firebug in popup window">&nbsp;</a><a id="fbWindow_btClose" class="fbSmallButton fbHover" title="Minimize Firebug">&nbsp;</a></div><div id="fbToolbar"><div id="fbToolbarContent"><span id="fbToolbarIcon"><a id="fbFirebugButton" class="fbIconButton" class="fbHover" target="_blank">&nbsp;</a></span><span id="fbToolbarButtons"><span id="fbFixedButtons"><a id="fbChrome_btInspect" class="fbButton fbHover" title="Click an element in the page to inspect">Inspect</a></span><span id="fbConsoleButtons" class="fbToolbarButtons"><a id="fbConsole_btClear" class="fbButton fbHover" title="Clear the console">Clear</a></span></span><span id="fbStatusBarBox"><span class="fbToolbarSeparator"></span></span></div></div><div id="fbPanelBarBox"><div id="fbPanelBar1" class="fbPanelBar"><a id="fbConsoleTab" class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">Console</span><span class="fbTabMenuTarget"></span><span class="fbTabR"></span></a><a id="fbHTMLTab" class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">HTML</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">CSS</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">Script</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">DOM</span><span class="fbTabR"></span></a></div><div id="fbPanelBar2Box" class="hide"><div id="fbPanelBar2" class="fbPanelBar"></div></div></div><div id="fbHSplitter">&nbsp;</div></td></tr><tr id="fbContent"><td id="fbPanelBox1"><div id="fbPanel1" class="fbFitHeight"><div id="fbConsole" class="fbPanel"></div><div id="fbHTML" class="fbPanel"></div></div></td><td id="fbPanelBox2" class="hide"><div id="fbVSplitter" class="fbVSplitter">&nbsp;</div><div id="fbPanel2" class="fbFitHeight"><div id="fbHTML_Style" class="fbPanel"></div><div id="fbHTML_Layout" class="fbPanel"></div><div id="fbHTML_DOM" class="fbPanel"></div></div><textarea id="fbLargeCommandLine" class="fbFitHeight"></textarea><div id="fbLargeCommandButtons"><a id="fbCommand_btRun" class="fbButton fbHover">Run</a><a id="fbCommand_btClear" class="fbButton fbHover">Clear</a><a id="fbSmallCommandLineIcon" class="fbSmallButton fbHover"></a></div></td></tr><tr id="fbBottom" class="hide"><td id="fbCommand" colspan="2"><div id="fbCommandBox"><div id="fbCommandIcon">&gt;&gt;&gt;</div><input id="fbCommandLine" name="fbCommandLine" type="text"/><a id="fbLargeCommandLineIcon" class="fbSmallButton fbHover"></a></div></td></tr></tbody></table><span id="fbMiniChrome"><span id="fbMiniContent"><span id="fbMiniIcon" title="Open Firebug Lite"></span><span id="fbMiniErrors" class="fbErrors"></span></span></span>'
+};
+
+// ************************************************************************************************
+}});
+
+// ************************************************************************************************
+FBL.initialize();
+// ************************************************************************************************
+
+})(); \ No newline at end of file