From bbe95f562e404dd6e1483cb31c8f99c79922cb70 Mon Sep 17 00:00:00 2001 From: Artem Butusov Date: Wed, 10 Oct 2018 00:15:24 -0400 Subject: [PATCH 01/12] Fix compatibility with IE6 for minified and beta builds --- build/firebug-lite-beta.js | 6 ++++-- build/firebug-lite.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/firebug-lite-beta.js b/build/firebug-lite-beta.js index 144e5e7a..22f7b846 100644 --- a/build/firebug-lite-beta.js +++ b/build/firebug-lite-beta.js @@ -10851,7 +10851,9 @@ var ChromeFrameBase = extend(ChromeBase, node.style.display = "block"; var main = $("fbChrome"); - main.style.display = "table"; + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; var self = this; /// TODO: xxxpedro FOUC @@ -37230,4 +37232,4 @@ FirebugChrome.Skin = FBL.initialize(); // ************************************************************************************************ -})(); \ No newline at end of file +})(); diff --git a/build/firebug-lite.js b/build/firebug-lite.js index b22436e4..33af7441 100644 --- a/build/firebug-lite.js +++ b/build/firebug-lite.js @@ -2653,7 +2653,7 @@ node.style.visibility="hidden"; if(Firebug.showIconWhenHidden){if(ChromeMini.isInitialized){ChromeMini.shutdown() }}else{node.style.display="block" }var main=$("fbChrome"); -main.style.display="table"; +main.style.display=""; var self=this; node.style.visibility="visible"; setTimeout(function(){self.initialize(); @@ -10942,4 +10942,4 @@ i .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;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;}#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;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 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:"undefined"} }}); FBL.initialize() -})(); \ No newline at end of file +})(); From 71bde4d80f14d97c05266d1c14b850bf60bd48e8 Mon Sep 17 00:00:00 2001 From: Artem Butusov Date: Wed, 10 Oct 2018 00:25:22 -0400 Subject: [PATCH 02/12] Add package.json to make npm happy --- package.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 00000000..f8ad1ff8 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "name": "firebug-lite", + "description": "Firebug Lite: doing the Firebug way, anywhere.", + "version": "1.5.1", + "license": "BSD", + "main": "build/firebug-lite.js", + "homepage": "https://getfirebug.com" +} From 89f103c4d867d18cc96ff5625f9844b27fde4123 Mon Sep 17 00:00:00 2001 From: Artem Butusov Date: Wed, 10 Oct 2018 00:26:05 -0400 Subject: [PATCH 03/12] Add README explaining how to install locally --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..cfe566e1 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Firebug Lite + +## Local Installation + +Install these files: + +- `build/firebug-lite.js` -> `/firebug-lite/firebug-lite.js` +- `build/firebug-lite-beta.js` -> `/firebug-lite/firebug-lite-beta.js` +- `build/firebug-lite-debug.js` -> `/firebug-lite/firebug-lite-debug.js` +- `skin/**` -> `/firebug-lite/skin/**` + +HTML: + +```html + + + +``` + +Available options: + +- saveCookies +- saveWindowPosition +- saveCommandLineHistory +- startOpened +- startInNewWindow +- showIconWhenHidden +- overrideConsole +- ignoreFirebugElements +- disableWhenFirebugActive +- enableTrace +- enablePersistent + +There are other options available... Search for `this.Env =`... From 913db19e9a39a337d5d54093239d80c65c4f25cb Mon Sep 17 00:00:00 2001 From: Artem Butusov Date: Mon, 22 Oct 2018 22:56:40 -0400 Subject: [PATCH 04/12] Added support for 204 http status code --- build/firebug-lite-debug.js | 47859 +++++++++++++++++----------------- 1 file changed, 23933 insertions(+), 23926 deletions(-) diff --git a/build/firebug-lite-debug.js b/build/firebug-lite-debug.js index 6754a99c..5838266c 100644 --- a/build/firebug-lite-debug.js +++ b/build/firebug-lite-debug.js @@ -1,23908 +1,23894 @@ (function(){ -/*!************************************************************* - * - * Firebug Lite 1.4.0a1 - * - * Copyright (c) 2007, Parakey Inc. - * Released under BSD license. - * More information: http://getfirebug.com/firebuglite - * - **************************************************************/ + /*!************************************************************* + * + * Firebug Lite 1.4.0a1 + * + * 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/ - */ + /*! + * 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 */ -var FBL = {}; + /** @namespace describe lib */ + var FBL = {}; -( /** @scope s_lib @this FBL */ function() { -// ************************************************************************************************ + ( /** @scope s_lib @this FBL */ function() { + // ************************************************************************************************ -// ************************************************************************************************ -// Constants + // ************************************************************************************************ + // Constants -var productionDir = "http://getfirebug.com/releases/lite/"; -var bookmarkletVersion = 4; + var productionDir = "http://getfirebug.com/releases/lite/"; + var bookmarkletVersion = 4; -// ************************************************************************************************ + // ************************************************************************************************ -var reNotWhitespace = /[^\s]/; -var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; + var reNotWhitespace = /[^\s]/; + var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; -// Globals -this.reJavascript = /\s*javascript:\s*(.*)/; -this.reChrome = /chrome:\/\/([^\/]*)\//; -this.reFile = /file:\/\/([^\/]*)\//; + // Globals + this.reJavascript = /\s*javascript:\s*(.*)/; + this.reChrome = /chrome:\/\/([^\/]*)\//; + this.reFile = /file:\/\/([^\/]*)\//; -// ************************************************************************************************ -// properties + // ************************************************************************************************ + // 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); + 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; + this.NS = null; + this.pixelsPerInch = null; -// ************************************************************************************************ -// Namespaces + // ************************************************************************************************ + // Namespaces -var namespaces = []; + var namespaces = []; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -this.ns = function(fn) -{ - var ns = {}; - namespaces.push(fn, ns); - return ns; -}; + this.ns = function(fn) + { + var ns = {}; + namespaces.push(fn, ns); + return ns; + }; -var FBTrace = null; + 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; + 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 + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize environment - // point the FBTrace object to the local variable - if (FBL.FBTrace) - FBTrace = FBL.FBTrace; - else - FBTrace = FBL.FBTrace = {}; + // point the FBTrace object to the local variable + if (FBL.FBTrace) + FBTrace = FBL.FBTrace; + else + FBTrace = FBL.FBTrace = {}; - FBL.Ajax.initialize(); + FBL.Ajax.initialize(); - // check if the actual window is a persisted chrome context - var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object"; + // 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; + // 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; + 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; - if (document.documentElement.getAttribute("debug") == "true") - FBL.Env.Options.startOpened = true; + // find the URL location of the loaded application + findLocation(); - // find the URL location of the loaded application - findLocation(); + // TODO: get preferences here... + var prefs = eval("(" + FBL.readCookie("FirebugLite") + ")"); + if (prefs) + { + FBL.Env.Options.startOpened = prefs.startOpened; + FBL.Env.Options.enableTrace = prefs.enableTrace; + FBL.Env.Options.enablePersistent = prefs.enablePersistent; + FBL.Env.Options.disableXHRListener = prefs.disableXHRListener; + } + + if (FBL.isFirefox && + typeof FBL.Env.browser.console == "object" && + FBL.Env.browser.console.firebug && + FBL.Env.Options.disableWhenFirebugActive) + return; + } - // TODO: get preferences here... - var prefs = eval("(" + FBL.readCookie("FirebugLite") + ")"); - if (prefs) + // exposes the FBL to the global namespace when in debug mode + if (FBL.Env.isDebugMode) { - FBL.Env.Options.startOpened = prefs.startOpened; - FBL.Env.Options.enableTrace = prefs.enableTrace; - FBL.Env.Options.enablePersistent = prefs.enablePersistent; - FBL.Env.Options.disableXHRListener = prefs.disableXHRListener; + FBL.Env.browser.FBL = FBL; } - if (FBL.isFirefox && - typeof FBL.Env.browser.console == "object" && - FBL.Env.browser.console.firebug && - FBL.Env.Options.disableWhenFirebugActive) - return; - } + // check browser compatibilities + this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; + this.isIEQuiksMode = this.isIE && this.isQuiksMode; + this.isIEStantandMode = this.isIE && !this.isQuiksMode; - // exposes the FBL to the global namespace when in debug mode - if (FBL.Env.isDebugMode) - { - FBL.Env.browser.FBL = FBL; - } + this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; + + // after creating/synchronizing the environment, initialize the FBTrace module + if (FBL.Env.Options.enableTrace) FBTrace.initialize(); - // check browser compatibilities - this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; - this.isIEQuiksMode = this.isIE && this.isQuiksMode; - this.isIEStantandMode = this.isIE && !this.isQuiksMode; + if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); - this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize namespaces - // after creating/synchronizing the environment, initialize the FBTrace module - if (FBL.Env.Options.enableTrace) FBTrace.initialize(); + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); - if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); + for (var i = 0; i < namespaces.length; i += 2) + { + var fn = namespaces[i]; + var ns = namespaces[i+1]; + fn.apply(ns); + } - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize namespaces + if (FBTrace.DBG_INITIALIZE) { + FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); + FBTrace.sysout("FBL waitForDocument", "waiting document load"); + } - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // finish environment initialization - for (var i = 0; i < namespaces.length; i += 2) - { - var fn = namespaces[i]; - var ns = namespaces[i+1]; - fn.apply(ns); - } + FBL.Firebug.loadPrefs(prefs); - if (FBTrace.DBG_INITIALIZE) { - FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); - FBTrace.sysout("FBL waitForDocument", "waiting document load"); - } + 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; + } + } - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // finish environment initialization + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // wait document load - FBL.Firebug.loadPrefs(prefs); + waitForDocument(); + }; - if (FBL.Env.Options.enablePersistent) + var waitForDocument = function waitForDocument() { - // TODO: xxxpedro persist - make a better synchronization - if (isChromeContext) + // document.body not available in XML+XSL documents in Firefox + var doc = FBL.Env.browser.document; + var body = doc.getElementsByTagName("body")[0]; + + if (body) { - FBL.FirebugChrome.clone(FBL.Env.FirebugChrome); + calculatePixelsPerInch(doc, body); + onDocumentLoad(); } 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]; + setTimeout(waitForDocument, 50); + }; - if (body) + var onDocumentLoad = function onDocumentLoad() { - calculatePixelsPerInch(doc, body); - onDocumentLoad(); - } - else - setTimeout(waitForDocument, 50); -}; + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded"); -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(); - // 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(); + // 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) + // 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 { - sharedEnv.destroy(); - sharedEnv = null; + FBL.FirebugChrome.create(); } - } - // non-persistent application - else - { - FBL.FirebugChrome.create(); - } -}; + }; -// ************************************************************************************************ -// Env + // ************************************************************************************************ + // Env -var sharedEnv; + var sharedEnv; -this.Env = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env Options (will be transported to Firebug options) - Options: + this.Env = { - saveCookies: false, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env Options (will be transported to Firebug options) + Options: + { + saveCookies: false, - saveWindowPosition: false, - saveCommandLineHistory: false, + saveWindowPosition: false, + saveCommandLineHistory: false, - startOpened: false, - startInNewWindow: false, - showIconWhenHidden: true, + startOpened: false, + startInNewWindow: false, + showIconWhenHidden: true, - overrideConsole: true, - ignoreFirebugElements: true, - disableWhenFirebugActive: true, + overrideConsole: true, + ignoreFirebugElements: true, + disableWhenFirebugActive: true, - disableXHRListener: false, + disableXHRListener: false, - enableTrace: false, - enablePersistent: false + enableTrace: false, + enablePersistent: false - }, + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Library location - Location: - { - sourceDir: null, - baseDir: null, - skinDir: null, - skin: null, - app: null - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Library location + Location: + { + sourceDir: null, + baseDir: null, + skinDir: null, + skin: null, + app: null + }, - skin: "xp", - useLocalSkin: false, + skin: "xp", + useLocalSkin: false, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env states - isDevelopmentMode: false, - isDebugMode: false, - isChromeContext: false, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env states + isDevelopmentMode: false, + isDebugMode: false, + isChromeContext: false, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env references - browser: null, - chrome: null -}; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Env references + browser: null, + chrome: null + }; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -var destroyEnvironment = function destroyEnvironment() -{ - setTimeout(function() + var destroyEnvironment = function destroyEnvironment() { - FBL = null; - }, 100); -}; + setTimeout(function() + { + FBL = null; + }, 100); + }; -// ************************************************************************************************ -// Library location + // ************************************************************************************************ + // Library location -var findLocation = function findLocation() -{ - var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; + var findLocation = function findLocation() + { + var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; - var rePath = /^(.*\/)/; - var reProtocol = /^\w+:\/\//; - var path = null; - var doc = document; + var rePath = /^(.*\/)/; + var reProtocol = /^\w+:\/\//; + var path = null; + var doc = document; - // Firebug Lite 1.3.0 bookmarklet identification - var script = doc.getElementById("FirebugLite"); + // Firebug Lite 1.3.0 bookmarklet identification + var script = doc.getElementById("FirebugLite"); - if (script) - { - file = reFirebugFile.exec(script.src); + if (script) + { + file = reFirebugFile.exec(script.src); - var version = script.getAttribute("FirebugLite"); - var number = version ? parseInt(version) : 0; + var version = script.getAttribute("FirebugLite"); + var number = version ? parseInt(version) : 0; - if (!version || !number || number < bookmarkletVersion) - { - FBL.Env.bookmarkletOutdated = true; + if (!version || !number || number < bookmarkletVersion) + { + FBL.Env.bookmarkletOutdated = true; + } } - } - else - { - for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) + else { - var file = null; - if ( si.nodeName.toLowerCase() == "script" && (file = reFirebugFile.exec(si.src)) ) + for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) { - script = si; - break; + var file = null; + if ( si.nodeName.toLowerCase() == "script" && (file = reFirebugFile.exec(si.src)) ) + { + script = si; + break; + } } } - } - - if (script) - script.firebugIgnore = true; - - if (file) - { - var fileName = file[1]; - var fileOptions = file[2]; - // absolute path - if (reProtocol.test(script.src)) { - path = rePath.exec(script.src)[1]; + if (script) + script.firebugIgnore = true; - } - // relative path - else + if (file) { - var r = rePath.exec(script.src); - var src = r ? r[1] : script.src; - var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); - var reLastDir = /^(.*\/)[^\/]+\/$/; - path = rePath.exec(location.href)[1]; + var fileName = file[1]; + var fileOptions = file[2]; - // "../some/path" - if (backDir) - { - var j = backDir[1].length/3; - var p; - while (j-- > 0) - path = reLastDir.exec(path)[1]; + // absolute path + if (reProtocol.test(script.src)) { + path = rePath.exec(script.src)[1]; - path += backDir[2]; } - - else if(src.indexOf("/") != -1) + // relative path + else { - // "./some/path" - if(/^\.\/./.test(src)) - { - path += src.substring(2); - } - // "/some/path" - else if(/^\/./.test(src)) + var r = rePath.exec(script.src); + var src = r ? r[1] : script.src; + var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); + var reLastDir = /^(.*\/)[^\/]+\/$/; + path = rePath.exec(location.href)[1]; + + // "../some/path" + if (backDir) { - var domain = /^(\w+:\/\/[^\/]+)/.exec(path); - path = domain[1] + src; + var j = backDir[1].length/3; + var p; + while (j-- > 0) + path = reLastDir.exec(path)[1]; + + path += backDir[2]; } - // "some/path" - else + + else if(src.indexOf("/") != -1) { - path += src; + // "./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}"}; - } - - 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; - - // 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") + FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; + if (FBL.Env.isChromeExtension) { - Env.isDebugMode = true; + path = productionDir; + FBL.Env.bookmarkletOutdated = false; + script = {innerHTML: "{showIconWhenHidden:false}"}; } - // process the - if (Env.browser.document.documentElement.getAttribute("debug") == "true") - { - Env.Options.startOpened = true; - } + var m = path && path.match(/([^\/]+)\/$/) || null; - // process the Script URL Options - if (fileOptions) + if (path && m) { - var options = fileOptions.split(","); + 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; - for (var i = 0, length = options.length; i < length; i++) + // detecting development and debug modes via file name + if (fileName == "firebug-lite-dev.js") { - var option = options[i]; - var name, value; + Env.isDevelopmentMode = true; + Env.isDebugMode = true; + } + else if (fileName == "firebug-lite-debug.js") + { + Env.isDebugMode = true; + } - if (option.indexOf("=") != -1) - { - var parts = option.split("="); - name = parts[0]; - value = eval(unescape(parts[1])); - } - else - { - name = option; - value = true; - } + // process the + if (Env.browser.document.documentElement.getAttribute("debug") == "true") + { + Env.Options.startOpened = true; + } - if (name == "debug") - { - Env.isDebugMode = !!value; - } - else if (name in Env.Options) - { - Env.Options[name] = value; - } - else + // process the Script URL Options + if (fileOptions) + { + var options = fileOptions.split(","); + + for (var i = 0, length = options.length; i < length; i++) { - Env[name] = value; + 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 - var innerOptions = FBL.trim(script.innerHTML); - if (innerOptions) - { - var innerOptionsObject = eval("(" + innerOptions + ")"); - for (var name in innerOptionsObject) + // process the Script JSON Options + var innerOptions = FBL.trim(script.innerHTML); + if (innerOptions) { - var value = innerOptionsObject[name]; + var innerOptionsObject = eval("(" + innerOptions + ")"); - if (name == "debug") - { - Env.isDebugMode = !!value; - } - else if (name in Env.Options) - { - Env.Options[name] = value; - } - else + for (var name in innerOptionsObject) { - Env[name] = value; + var value = innerOptionsObject[name]; + + if (name == "debug") + { + Env.isDebugMode = !!value; + } + else if (name in Env.Options) + { + Env.Options[name] = value; + } + else + { + Env[name] = value; + } } } - } - // process the Debug Mode - if (Env.isDebugMode) + // 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 { - Env.Options.startOpened = true; - Env.Options.enableTrace = true; - Env.Options.disableWhenFirebugActive = false; + throw new Error("Firebug Error: Library path not found"); } + }; - var loc = Env.Location; - var isProductionRelease = path.indexOf(productionDir) != -1; + // ************************************************************************************************ + // Basics - 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 + this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); { - 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) + 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); { - // Sometimes we get exceptions trying to iterate properties - } + var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); + return function() { return fn.apply(object, args); }; + }; - return keys; // return is safe -}; + 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.values = function(map) -{ - var values = []; - try + this.descend = function(prototypeParent, childProperties) { - 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); - } + function protoSetter() {}; + protoSetter.prototype = prototypeParent; + var newOb = new protoSetter(); + for (var n in childProperties) + newOb[n] = childProperties[n]; + return newOb; + }; - } - } - catch (exc) + this.append = function(l, r) { - // Sometimes we get exceptions trying to iterate properties - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.values FAILED ", exc); - } + for (var n in r) + l[n] = r[n]; - return values; -}; + return l; + }; -this.remove = function(list, item) -{ - for (var i = 0; i < list.length; ++i) + this.keys = function(map) // At least sometimes the keys will be on user-level window objects { - if (list[i] == item) + var keys = []; + try { - list.splice(i, 1); - break; + 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 } - } -}; - -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; + return keys; // return is safe + }; - 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 + this.values = function(map) { - // 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; -}; + 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.getStyle = this.isIE ? - function(el, name) + this.remove = function(list, item) { - return el.currentStyle[name] || el.style[name] || undefined; - } - : - function(el, name) + for (var i = 0; i < list.length; ++i) + { + if (list[i] == item) + { + list.splice(i, 1); + break; + } + } + }; + + this.sliceArray = function(array, index) { - return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] - || el.style[name] || undefined; + var slice = []; + for (var i = index; i < array.length; ++i) + slice.push(array[i]); + + return slice; }; + function cloneArray(array, fn) + { + var newArray = []; -// ************************************************************************************************ -// Whitespace and Entity conversions + 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]); -var entityConversionLists = this.entityConversionLists = { - normal : { - whitespace : { - '\t' : '\u200c\u2192', - '\n' : '\u200c\u00b6', - '\r' : '\u200c\u00ac', - ' ' : '\u200c\u00b7' - } - }, - reverse : { - whitespace : { - ' ' : '\t', - ' ' : '\n', - '\u200c\u2192' : '\t', - '\u200c\u00b6' : '\n', - '\u200c\u00ac' : '\r', - '\u200c\u00b7' : ' ' - } + return newArray; } -}; - -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) + + function extendArray(array, array2) { - var chars = []; - for ( var ch in list) - { - chars.push(ch); - } - return new RegExp('(' + chars.join('|') + ')', 'gm'); + var newArray = []; + newArray.push.apply(newArray, array); + newArray.push.apply(newArray, array2); + return newArray; } -}; -function getEscapeRegexp(direction, lists) -{ - var name = '', re; - var groups = [].concat(lists); - for (i = 0; i < groups.length; i++) + this.extendArray = extendArray; + this.cloneArray = cloneArray; + + function arrayInsert(array, index, other) { - name += groups[i].group; + for (var i = 0; i < other.length; ++i) + array.splice(i+index, 0, other[i]); + + return array; } - re = entityConversionRegexes[direction][name]; - if (!re) + + // ************************************************************************************************ + + this.createStyleSheet = function(doc, url) { - 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; -}; + //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); -this.escapeGroupsForEntities = escapeGroupsForEntities; + //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); + }; -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++) + this.appendStylesheet = function(doc, uri) { - 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) + // 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) { - switch (ch) + 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 { - case "&": - return "&"; - case "'": - return apos; - case '"': - return quot; + // See issue 1079, the svg test case gives this error + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.addScript doc has no documentElement:", doc); } - return "?"; + return element; }; - var apos = "'", 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) + // ************************************************************************************************ + + this.getStyle = this.isIE ? + function(el, name) { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "'": - return "'"; - case '"': - return """; + return el.currentStyle[name] || el.style[name] || undefined; } - return "?"; - }; - return String(value).replace(/[<>&"']/g, replaceChars); -} - -this.escapeHTML = escapeHTML; + : + function(el, name) + { + return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] + || el.style[name] || undefined; + }; -this.cropString = function(text, limit) -{ - text = text + ""; - if (!limit) - var halfLimit = 50; - else - var halfLimit = limit / 2; + // ************************************************************************************************ + // Whitespace and Entity conversions - if (text.length > limit) - return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); - else - return this.escapeNewLines(text); -}; + var entityConversionLists = this.entityConversionLists = { + normal : { + whitespace : { + '\t' : '\u200c\u2192', + '\n' : '\u200c\u00b6', + '\r' : '\u200c\u00ac', + ' ' : '\u200c\u00b7' + } + }, + reverse : { + whitespace : { + ' ' : '\t', + ' ' : '\n', + '\u200c\u2192' : '\t', + '\u200c\u00b6' : '\n', + '\u200c\u00ac' : '\r', + '\u200c\u00b7' : ' ' + } + } + }; -this.isWhitespace = function(text) -{ - return !reNotWhitespace.exec(text); -}; + var normal = entityConversionLists.normal, + reverse = entityConversionLists.reverse; -this.splitLines = function(text) -{ - var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; - var lines; - if (text.match) - { - lines = text.match(reSplitLines2); - } - else + function addEntityMapToList(ccode, entity) { - var str = text+""; - lines = str.match(reSplitLines2); - } - lines.pop(); - return lines; -}; - + 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 : {} + }; -this.safeToString = function(ob) -{ - if (this.isIE) - return ob + ""; + 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'); + } + }; - try - { - if (ob && "toString" in ob && typeof ob.toString == "function") - return ob.toString(); - } - catch (exc) + function getEscapeRegexp(direction, lists) { - // xxxpedro it is not safe to use ob+""? - return ob + ""; - ///return "[an object with no toString() function]"; - } -}; - -// ************************************************************************************************ + 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; + }; -this.hasProperties = function(ob) -{ - try + function createSimpleEscape(name, direction) { - 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, ""); -}; + 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; + }; -// ************************************************************************************************ -// Empty + this.escapeGroupsForEntities = escapeGroupsForEntities; -this.emptyFn = function(){}; + 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('') || ''; + }; -// ************************************************************************************************ -// Visibility + // ************************************************************************************************ + // String escaping -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); - } - /**/ + 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'); - 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"); -}; + // 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); -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 = ""; -}; + var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); -this.eraseNode = function(node) -{ - while (node.lastChild) - node.removeChild(node.lastChild); -}; + var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); -// ************************************************************************************************ -// Window iteration + this.unescapeForTextNode = function(str) + { + if (Firebug.showTextNodesWithWhitespace) + str = unescapeWhitespace(str); + if (!Firebug.showTextNodesWithEntities) + str = escapeForElementAttribute(str); + return str; + }; -this.iterateWindows = function(win, handler) -{ - if (!win || !win.document) - return; + this.escapeNewLines = function(value) + { + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); + }; - handler(win); + this.stripNewLines = function(value) + { + return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; + }; - if (win == top || !win.frames) return; // XXXjjb hack for chromeBug + this.escapeJS = function(value) + { + return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); + }; - for (var i = 0; i < win.frames.length; ++i) + function escapeHTMLAttribute(value) { - var subWin = win.frames[i]; - if (subWin != win) - this.iterateWindows(subWin, handler); + function replaceChars(ch) + { + switch (ch) + { + case "&": + return "&"; + case "'": + return apos; + case '"': + return quot; + } + return "?"; + }; + var apos = "'", quot = """, around = '"'; + if( value.indexOf('"') == -1 ) { + quot = '"'; + apos = "'"; + } else if( value.indexOf("'") == -1 ) { + quot = '"'; + around = "'"; + } + return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; } -}; -this.getRootWindow = function(win) -{ - for (; win; win = win.parent) + + function escapeHTML(value) { - if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) - return win; + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); } - return null; -}; -// ************************************************************************************************ -// Graphics + this.escapeHTML = escapeHTML; -this.getClientOffset = function(elt) -{ - var addOffset = function addOffset(elt, coords, view) + this.cropString = function(text, limit) { - var p = elt.offsetParent; + text = text + ""; - ///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 (!limit) + var halfLimit = 50; + else + var halfLimit = limit / 2; - if (p) - { - if (p.nodeType == 1) - addOffset(p, coords, view); - } + if (text.length > limit) + return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); 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); - } + return this.escapeNewLines(text); }; - var isIE = this.isIE; - var coords = {x: 0, y: 0}; - if (elt) + this.isWhitespace = function(text) { - var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; - addOffset(elt, coords, view); - } - - return coords; -}; + return !reNotWhitespace.exec(text); + }; -this.getViewOffset = function(elt, singleFrame) -{ - function addOffset(elt, coords, view) + this.splitLines = function(text) { - var p = elt.offsetParent; - coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); - coords.y += elt.offsetTop - (p ? p.scrollTop : 0); - - if (p) + var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; + var lines; + if (text.match) { - 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); - } + lines = text.match(reSplitLines2); } 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 str = text+""; + lines = str.match(reSplitLines2); } + lines.pop(); + return lines; + }; - } - - 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) + this.safeToString = function(ob) { - bcrect = elt.getBoundingClientRect(); - dims.left = bcrect.left; - dims.top = bcrect.top; - dims.right = bcrect.right; - dims.bottom = bcrect.bottom; + if (this.isIE) + return ob + ""; - if(bcrect.width) + try { - dims.width = bcrect.width; - dims.height = bcrect.height; + if (ob && "toString" in ob && typeof ob.toString == "function") + return ob.toString(); } - else + catch (exc) { - dims.width = dims.right - dims.left; - dims.height = dims.bottom - dims.top; + // xxxpedro it is not safe to use ob+""? + return ob + ""; + ///return "[an object with no toString() function]"; } - } - 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') + this.hasProperties = function(ob) { - 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; + try + { + for (var name in ob) + return true; + } catch (exc) {} + return false; + }; - var offsetX = borderLeft + paddingLeft + marginLeft; - var offsetY = borderTop + paddingTop + marginTop; + // ************************************************************************************************ + // String Util - clientRect.left -= offsetX; - clientRect.top -= offsetY; - clientRect.right -= offsetX; - clientRect.bottom -= offsetY; - } + var reTrim = /^\s+|\s+$/g; + this.trim = function(s) + { + return s.replace(reTrim, ""); + }; - return clientRect; -}; -this.getOffsetSize = function(elt) -{ - return {width: elt.offsetWidth, height: elt.offsetHeight}; -}; + // ************************************************************************************************ + // Empty -this.getOverflowParent = function(element) -{ - for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) - { - if (scrollParent.scrollHeight > scrollParent.offsetHeight) - return scrollParent; - } -}; + this.emptyFn = function(){}; -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) + // ************************************************************************************************ + // Visibility + + this.isVisible = function(elt) + { + /* + if (elt instanceof XULElement) { - 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); + //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); + return (!elt.hidden && !elt.collapsed); } + /**/ - 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); + 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" ); + }; - if (!scrollBox) - return; + 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"); + }; - var offset = this.getClientOffset(element); + this.obscure = function(elt, obscured) + { + if (obscured) + this.setClass(elt, "obscured"); + else + this.removeClass(elt, "obscured"); + }; - var topSpace = offset.y - scrollBox.scrollTop; - var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - - (offset.y + element.offsetHeight); + this.hide = function(elt, hidden) + { + elt.style.visibility = hidden ? "hidden" : "visible"; + }; - if (topSpace < 0 || bottomSpace < 0) + this.clearNode = function(node) { - var split = (scrollBox.clientHeight/2); - var centerY = offset.y - split; - scrollBox.scrollTop = centerY; - topSpace = split; - bottomSpace = split - element.offsetHeight; - } + var nodeName = " " + node.nodeName.toLowerCase() + " "; + var ignoreTags = " table tbody thead tfoot th tr td "; - return {before: Math.round((topSpace/element.offsetHeight) + 0.5), - after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; -}; + // IE can't use innerHTML of table elements + if (this.isIE && ignoreTags.indexOf(nodeName) != -1) + this.eraseNode(node); + else + node.innerHTML = ""; + }; -this.scrollIntoCenterView = function(element, scrollBox, notX, notY) -{ - if (!element) - return; + this.eraseNode = function(node) + { + while (node.lastChild) + node.removeChild(node.lastChild); + }; - if (!scrollBox) - scrollBox = this.getOverflowParent(element); + // ************************************************************************************************ + // Window iteration - if (!scrollBox) - return; + this.iterateWindows = function(win, handler) + { + if (!win || !win.document) + return; - var offset = this.getClientOffset(element); + handler(win); - if (!notY) - { - var topSpace = offset.y - scrollBox.scrollTop; - var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - - (offset.y + element.offsetHeight); + if (win == top || !win.frames) return; // XXXjjb hack for chromeBug - if (topSpace < 0 || bottomSpace < 0) + for (var i = 0; i < win.frames.length; ++i) { - var centerY = offset.y - (scrollBox.clientHeight/2); - scrollBox.scrollTop = centerY; + var subWin = win.frames[i]; + if (subWin != win) + this.iterateWindows(subWin, handler); } - } + }; - if (!notX) + this.getRootWindow = function(win) { - var leftSpace = offset.x - scrollBox.scrollLeft; - var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) - - (offset.x + element.clientWidth); - - if (leftSpace < 0 || rightSpace < 0) + for (; win; win = win.parent) { - var centerX = offset.x - (scrollBox.clientWidth/2); - scrollBox.scrollLeft = centerX; + if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) + return win; } - } - if (FBTrace.DBG_SOURCEFILES) - FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); -}; - - -// ************************************************************************************************ -// CSS + return null; + }; -var cssKeywordMap = null; -var cssPropNames = null; -var cssColorNames = null; -var imageRules = null; + // ************************************************************************************************ + // Graphics -this.getCSSKeywordsByProperty = function(propName) -{ - if (!cssKeywordMap) + this.getClientOffset = function(elt) { - cssKeywordMap = {}; - - for (var name in this.cssInfo) + var addOffset = function addOffset(elt, coords, view) { - var list = []; + var p = elt.offsetParent; - 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); + ///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); } + }; - cssKeywordMap[name] = list; + 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 propName in cssKeywordMap ? cssKeywordMap[propName] : []; -}; + return coords; + }; -this.getCSSPropertyNames = function() -{ - if (!cssPropNames) + this.getViewOffset = function(elt, singleFrame) { - cssPropNames = []; + 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); - for (var name in this.cssInfo) - cssPropNames.push(name); - } + 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); - return cssPropNames; -}; + 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); + } -this.isColorKeyword = function(keyword) -{ - if (keyword == "transparent") - return false; + 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); - if (!cssColorNames) - { - cssColorNames = []; + var htmlStyle = view.getComputedStyle(elt.parentNode, ""); + coords.x -= parseInt(htmlStyle.paddingLeft); + coords.y -= parseInt(htmlStyle.paddingTop); + } - var colors = this.cssKeywords["color"]; - for (var i = 0; i < colors.length; ++i) - cssColorNames.push(colors[i].toLowerCase()); + if (elt.scrollLeft) + coords.x += elt.scrollLeft; + if (elt.scrollTop) + coords.y += elt.scrollTop; - var systemColors = this.cssKeywords["systemColor"]; - for (var i = 0; i < systemColors.length; ++i) - cssColorNames.push(systemColors[i].toLowerCase()); - } + 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 cssColorNames.indexOf ? // Array.indexOf is not available in IE - cssColorNames.indexOf(keyword.toLowerCase()) != -1 : - (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; -}; + return coords; + }; -this.isImageRule = function(rule) -{ - if (!imageRules) + this.getLTRBWH = function(elt) { - imageRules = []; + var bcrect, + dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; - for (var i in this.cssInfo) + if (elt) { - var r = i.toLowerCase(); - var suffix = "image"; - if (r.match(suffix + "$") == suffix || r == "background") - imageRules.push(r); + 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; + }; - return imageRules.indexOf ? // Array.indexOf is not available in IE - imageRules.indexOf(rule.toLowerCase()) != -1 : - (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; -}; + this.applyBodyOffsets = function(elt, clientRect) + { + var od = elt.ownerDocument; + if (!od.body) + return clientRect; -this.copyTextStyles = function(fromNode, toNode, style) -{ - var view = this.isIE ? - fromNode.ownerDocument.parentWindow : - fromNode.ownerDocument.defaultView; + var style = od.defaultView.getComputedStyle(od.body, null); - if (view) - { - if (!style) - style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + 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; - toNode.style.fontFamily = style.fontFamily; + var offsetX = borderLeft + paddingLeft + marginLeft; + var offsetY = borderTop + paddingTop + marginTop; - // 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; + clientRect.left -= offsetX; + clientRect.top -= offsetY; + clientRect.right -= offsetX; + clientRect.bottom -= offsetY; + } - return style; - } -}; + return clientRect; + }; -this.copyBoxStyles = function(fromNode, toNode, style) -{ - var view = this.isIE ? - fromNode.ownerDocument.parentWindow : - fromNode.ownerDocument.defaultView; + this.getOffsetSize = function(elt) + { + return {width: elt.offsetWidth, height: elt.offsetHeight}; + }; - if (view) + this.getOverflowParent = function(element) { - if (!style) - style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); + for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) + { + if (scrollParent.scrollHeight > scrollParent.offsetHeight) + return scrollParent; + } + }; - 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; + 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; + }; - 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; + this.scrollToBottom = function(element) + { + element.scrollTop = element.scrollHeight; - // 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)); -}; + 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.getElementHTML = function(element) -{ - var self=this; - function toHTML(elt) + this.move = function(element, x, y) { - if (elt.nodeType == Node.ELEMENT_NODE) - { - if (unwrapObject(elt).firebugIgnore) - return; + element.style.left = x + "px"; + element.style.top = y + "px"; + }; - html.push('<', elt.nodeName.toLowerCase()); + this.resize = function(element, w, h) + { + element.style.width = w + "px"; + element.style.height = h + "px"; + }; - for (var i = 0; i < elt.attributes.length; ++i) - { - var attr = elt.attributes[i]; + this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} + { + if (!scrollBox) + scrollBox = this.getOverflowParent(element); - // Hide attributes set by Firebug - if (attr.localName.indexOf("firebug-") == 0) - continue; + if (!scrollBox) + return; - // MathML - if (attr.localName.indexOf("-moz-math") == 0) - { - // just hide for now - continue; - } + var offset = this.getClientOffset(element); - html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); - } + var topSpace = offset.y - scrollBox.scrollTop; + var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) + - (offset.y + element.offsetHeight); - if (elt.firstChild) - { - html.push('>'); + if (topSpace < 0 || bottomSpace < 0) + { + var split = (scrollBox.clientHeight/2); + var centerY = offset.y - split; + scrollBox.scrollTop = centerY; + topSpace = split; + bottomSpace = split - element.offsetHeight; + } - var pureText=true; - for (var child = element.firstChild; child; child = child.nextSibling) - pureText=pureText && (child.nodeType == Node.TEXT_NODE); + return {before: Math.round((topSpace/element.offsetHeight) + 0.5), + after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; + }; - if (pureText) - html.push(escapeForHtmlEditor(elt.textContent)); - else { - for (var child = elt.firstChild; child; child = child.nextSibling) - toHTML(child); - } + this.scrollIntoCenterView = function(element, scrollBox, notX, notY) + { + if (!element) + return; - html.push(''); - } - else if (isElementSVG(elt) || isElementMathML(elt)) - { - html.push('/>'); - } - else if (self.isSelfClosing(elt)) + 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) { - html.push((isElementXHTML(elt))?'/>':'>'); + var centerY = offset.y - (scrollBox.clientHeight/2); + scrollBox.scrollTop = centerY; } - else + } + + if (!notX) + { + var leftSpace = offset.x - scrollBox.scrollLeft; + var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) + - (offset.x + element.clientWidth); + + if (leftSpace < 0 || rightSpace < 0) { - html.push('>'); + var centerX = offset.x - (scrollBox.clientWidth/2); + scrollBox.scrollLeft = centerX; } } - else if (elt.nodeType == Node.TEXT_NODE) - html.push(escapeForTextNode(elt.textContent)); - else if (elt.nodeType == Node.CDATA_SECTION_NODE) - html.push(''); - else if (elt.nodeType == Node.COMMENT_NODE) - html.push(''); - } + if (FBTrace.DBG_SOURCEFILES) + FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); + }; + + + // ************************************************************************************************ + // CSS - var html = []; - toHTML(element); - return html.join(""); -}; + var cssKeywordMap = null; + var cssPropNames = null; + var cssColorNames = null; + var imageRules = null; -this.getElementXML = function(element) -{ - function toXML(elt) + this.getCSSKeywordsByProperty = function(propName) { - if (elt.nodeType == Node.ELEMENT_NODE) + if (!cssKeywordMap) { - if (unwrapObject(elt).firebugIgnore) - return; - - xml.push('<', elt.nodeName.toLowerCase()); + cssKeywordMap = {}; - for (var i = 0; i < elt.attributes.length; ++i) + for (var name in this.cssInfo) { - var attr = elt.attributes[i]; - - // Hide attributes set by Firebug - if (attr.localName.indexOf("firebug-") == 0) - continue; + var list = []; - // MathML - if (attr.localName.indexOf("-moz-math") == 0) + var types = this.cssInfo[name]; + for (var i = 0; i < types.length; ++i) { - // just hide for now - continue; + var keywords = this.cssKeywords[types[i]]; + if (keywords) + list.push.apply(list, keywords); } - xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + cssKeywordMap[name] = list; } + } - if (elt.firstChild) - { - xml.push('>'); + return propName in cssKeywordMap ? cssKeywordMap[propName] : []; + }; - for (var child = elt.firstChild; child; child = child.nextSibling) - toXML(child); + this.getCSSPropertyNames = function() + { + if (!cssPropNames) + { + cssPropNames = []; - xml.push(''); - } - else - xml.push('/>'); - } - else if (elt.nodeType == Node.TEXT_NODE) - xml.push(elt.nodeValue); - else if (elt.nodeType == Node.CDATA_SECTION_NODE) - xml.push(''); - else if (elt.nodeType == Node.COMMENT_NODE) - xml.push(''); - } + for (var name in this.cssInfo) + cssPropNames.push(name); + } - var xml = []; - toXML(element); - return xml.join(""); -}; + return cssPropNames; + }; + this.isColorKeyword = function(keyword) + { + if (keyword == "transparent") + return false; -// ************************************************************************************************ -// CSS classes + if (!cssColorNames) + { + cssColorNames = []; -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; + var colors = this.cssKeywords["color"]; + for (var i = 0; i < colors.length; ++i) + cssColorNames.push(colors[i].toLowerCase()); - if (!node || node.nodeType != 1) - return false; - else - { - for (var i=1; i= 0) + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; + + if (view) { - var size = name.length; - node.className = node.className.substr(0,index-1) + node.className.substr(index+size); - } - } -}; + if (!style) + style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); -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); -}; + toNode.style.fontFamily = style.fontFamily; -this.setClassTimed = function(elt, name, context, timeout) -{ - if (!timeout) - timeout = 1300; + // 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; - if (elt.__setClassTimeout) - context.clearTimeout(elt.__setClassTimeout); - else - this.setClass(elt, name); + return style; + } + }; - elt.__setClassTimeout = context.setTimeout(function() + this.copyBoxStyles = function(fromNode, toNode, style) { - delete elt.__setClassTimeout; + var view = this.isIE ? + fromNode.ownerDocument.parentWindow : + fromNode.ownerDocument.defaultView; - 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; - } -}; + 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; -// ************************************************************************************************ -// DOM queries + return style; + } + }; -this.$ = function(id, doc) -{ - if (doc) - return doc.getElementById(id); - else + this.readBoxStyles = function(style) { - return FBL.Firebug.chrome.document.getElementById(id); - } -}; + 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" + }; -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); - } -}; + 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.getChildByClass = function(node) // ,classname, classname, classname... -{ - for (var i = 1; i < arguments.length; ++i) + this.getBoxFromStyles = function(style, element) { - 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; -}; + 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.getAncestorByClass = function(node, className) -{ - for (var parent = node; parent; parent = parent.parentNode) + this.getElementCSSSelector = function(element) { - if (this.hasClass(parent, className)) - return parent; - } - - return null; -}; + var label = element.localName.toLowerCase(); + if (element.id) + label += "#" + element.id; + if (element.hasAttribute("class")) + label += "." + element.getAttribute("class").split(" ")[0]; + return label; + }; -this.getElementsByClass = function(node, className) -{ - var result = []; - - for (var child = node.firstChild; child; child = child.nextSibling) + this.getURLForStyleSheet= function(styleSheet) { - if (this.hasClass(child, className)) - result.push(child); - } - - return result; -}; + //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.getElementByClass = function(node, className) // className, className, ... -{ - var args = cloneArray(arguments); args.splice(0, 1); - for (var child = node.firstChild; child; child = child.nextSibling) + this.getDocumentForStyleSheet = function(styleSheet) { - var args1 = cloneArray(args); args1.unshift(child); - if (FBL.hasClass.apply(null, args1)) - return child; - else + while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) { - var found = FBL.getElementByClass.apply(null, args1); - if (found) - return found; + styleSheet = styleSheet.parentStyleSheet; } - } - - return null; -}; + if (styleSheet.ownerNode) + return styleSheet.ownerNode.ownerDocument; + }; -this.isAncestor = function(node, potentialAncestor) -{ - for (var parent = node; parent; parent = parent.parentNode) + /** + * 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) { - 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; -}; + // System URLs are always unique (or at least we are making this assumption) + if (FBL.isSystemStyleSheet(styleSheet)) + return 0; -this.getBody = function(doc) -{ - if (doc.body) - return doc.body; + // 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 body = doc.getElementsByTagName("body")[0]; - if (body) - return body; + 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; + }; - return doc.firstChild; // For non-HTML docs -}; + // ************************************************************************************************ + // HTML and XML Serialization -this.findNextDown = function(node, criteria) -{ - if (!node) - return null; - for (var child = node.firstChild; child; child = child.nextSibling) + var getElementType = this.getElementType = function(node) { - if (criteria(child)) - return child; - - var next = this.findNextDown(child, criteria); - if (next) - return next; + 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'; } -}; - -this.findPreviousUp = function(node, criteria) -{ - if (!node) - return null; - for (var child = node.lastChild; child; child = child.previousSibling) + var getElementSimpleType = this.getElementSimpleType = function(node) { - var next = this.findPreviousUp(child, criteria); - if (next) - return next; - - if (criteria(child)) - return child; + if (isElementSVG(node)) + return 'svg'; + else if (isElementMathML(node)) + return 'mathml'; + else + return 'html'; } -}; - -this.findNext = function(node, criteria, upOnly, maxRoot) -{ - if (!node) - return null; - if (!upOnly) + var isElementHTML = this.isElementHTML = function(node) { - var next = this.findNextDown(node, criteria); - if (next) - return next; + return node.nodeName == node.nodeName.toUpperCase(); } - for (var sib = node.nextSibling; sib; sib = sib.nextSibling) + var isElementXHTML = this.isElementXHTML = function(node) { - if (criteria(sib)) - return sib; - - var next = this.findNextDown(sib, criteria); - if (next) - return next; + return node.nodeName == node.nodeName.toLowerCase(); } - 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 isElementMathML = this.isElementMathML = function(node) { - var prev = this.findPreviousUp(sib, criteria); - if (prev) - return prev; - - if (criteria(sib)) - return sib; + return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; } - if (!downOnly) + var isElementSVG = this.isElementSVG = function(node) { - var next = this.findPreviousUp(node, criteria); - if (next) - return next; + return node.namespaceURI == 'http://www.w3.org/2000/svg'; } - if (node.parentNode && node.parentNode != maxRoot) + var isElementXUL = this.isElementXUL = function(node) { - 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"); + return node instanceof XULElement; } - 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) + this.isSelfClosing = function(element) { - var range = doc.createRange(); // a helper object - range.selectNodeContents(element); // the environment to interpret the html + if (isElementSVG(element) || isElementMathML(element)) + return true; + var tag = element.localName.toLowerCase(); + return (this.selfClosingTags.hasOwnProperty(tag)); + }; - var fragment = range.createContextualFragment(html); // parse - var firstChild = fragment.firstChild; - element.insertBefore(fragment, referenceElement); - } - else + this.getElementHTML = function(element) { - if (!appendFragment || appendFragment.ownerDocument != doc) - appendFragment = doc.createDocumentFragment(); - - var div = doc.createElement("div"); - div.innerHTML = html; + var self=this; + function toHTML(elt) + { + if (elt.nodeType == Node.ELEMENT_NODE) + { + if (unwrapObject(elt).firebugIgnore) + return; - var firstChild = div.firstChild; - while (div.firstChild) - appendFragment.appendChild(div.firstChild); + html.push('<', elt.nodeName.toLowerCase()); - element.insertBefore(appendFragment, referenceElement); + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; - div = null; - } + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; - return firstChild; -}; + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } + html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); + } -// ************************************************************************************************ -// DOM creation + if (elt.firstChild) + { + html.push('>'); -this.createElement = function(tagName, properties) -{ - properties = properties || {}; - var doc = properties.document || FBL.Firebug.chrome.document; + var pureText=true; + for (var child = element.firstChild; child; child = child.nextSibling) + pureText=pureText && (child.nodeType == Node.TEXT_NODE); - var element = doc.createElement(tagName); + if (pureText) + html.push(escapeForHtmlEditor(elt.textContent)); + else { + for (var child = elt.firstChild; child; child = child.nextSibling) + toHTML(child); + } - for(var name in properties) - { - if (name != "document") - { - element[name] = properties[name]; - } - } + html.push(''); + } + else if (isElementSVG(elt) || isElementMathML(elt)) + { + html.push('/>'); + } + else if (self.isSelfClosing(elt)) + { + html.push((isElementXHTML(elt))?'/>':'>'); + } + else + { + html.push('>'); + } + } + else if (elt.nodeType == Node.TEXT_NODE) + html.push(escapeForTextNode(elt.textContent)); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + html.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + html.push(''); + } + + 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; - return element; -}; + xml.push('<', elt.nodeName.toLowerCase()); -this.createGlobalElement = function(tagName, properties) -{ - properties = properties || {}; - var doc = FBL.Env.browser.document; + for (var i = 0; i < elt.attributes.length; ++i) + { + var attr = elt.attributes[i]; - var element = this.NS && doc.createElementNS ? - doc.createElementNS(FBL.NS, tagName) : - doc.createElement(tagName); + // Hide attributes set by Firebug + if (attr.localName.indexOf("firebug-") == 0) + continue; - for(var name in properties) - { - var propname = name; - if (FBL.isIE && name == "class") propname = "className"; + // MathML + if (attr.localName.indexOf("-moz-math") == 0) + { + // just hide for now + continue; + } - if (name != "document") - { - element.setAttribute(propname, properties[name]); + 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(''); + } + else + xml.push('/>'); + } + else if (elt.nodeType == Node.TEXT_NODE) + xml.push(elt.nodeValue); + else if (elt.nodeType == Node.CDATA_SECTION_NODE) + xml.push(''); + else if (elt.nodeType == Node.COMMENT_NODE) + xml.push(''); } - } - return element; -}; + var xml = []; + toXML(element); + return xml.join(""); + }; + -//************************************************************************************************ + // ************************************************************************************************ + // CSS classes -this.safeGetWindowLocation = function(window) -{ - try + this.hasClass = function(node, name) // className, className, ... { - if (window) + // 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 { - if (window.closed) - return "(window.closed)"; - if ("location" in window) - return window.location+""; - else - return "(no window.location)"; + for (var i=1; i= 0) + { + var size = name.length; + node.className = node.className.substr(0,index-1) + node.className.substr(index+size); + } + } + }; - if (e.stopPropagation) - e.stopPropagation(); - else - e.cancelBubble = true; -}; + 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; -this.addGlobalEvent = function(name, handler) -{ - var doc = this.Firebug.browser.document; - var frames = this.Firebug.browser.window.frames; + if (elt.__setClassTimeout) + context.clearTimeout(elt.__setClassTimeout); + else + this.setClass(elt, name); - this.addEvent(doc, name, handler); + elt.__setClassTimeout = context.setTimeout(function() + { + delete elt.__setClassTimeout; - if (this.Firebug.chrome.type == "popup") - this.addEvent(this.Firebug.chrome.document, name, handler); + FBL.removeClass(elt, name); + }, timeout); + }; - for (var i = 0, frame; frame = frames[i]; i++) + this.cancelClassTimed = function(elt, name, context) { - try - { - this.addEvent(frame.document, name, handler); - } - catch(E) + if (elt.__setClassTimeout) { - // Avoid acess denied + FBL.removeClass(elt, name); + context.clearTimeout(elt.__setClassTimeout); + delete elt.__setClassTimeout; } - } -}; - -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); + // ************************************************************************************************ + // DOM queries - for (var i = 0, frame; frame = frames[i]; i++) + this.$ = function(id, doc) { - try + if (doc) + return doc.getElementById(id); + else { - this.removeEvent(frame.document, name, handler); + return FBL.Firebug.chrome.document.getElementById(id); } - catch(E) + }; + + this.$$ = function(selector, doc) + { + if (doc || !FBL.Firebug.chrome) + return FBL.Firebug.Selector(selector, doc); + else { - // Avoid acess denied + return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); } - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.dispatch = function(listeners, name, args) -{ - if (!listeners) return; + }; - try - {/**/ - if (typeof listeners.length != "undefined") + this.getChildByClass = function(node) // ,classname, classname, classname... + { + for (var i = 1; i < arguments.length; ++i) { - if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); - - for (var i = 0; i < listeners.length; ++i) + var className = arguments[i]; + var child = node.firstChild; + node = null; + for (; child; child = child.nextSibling) { - var listener = listeners[i]; - if ( listener[name] ) - listener[name].apply(listener, args); + if (this.hasClass(child, className)) + { + node = child; + break; + } } } - 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) + return node; + }; + + this.getAncestorByClass = function(node, className) { - if (FBTrace.DBG_ERRORS) + for (var parent = node; parent; parent = parent.parentNode) { - FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); - //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); + if (this.hasClass(parent, className)) + return parent; } - } - /**/ -}; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + return null; + }; + -var disableTextSelectionHandler = function(event) -{ - FBL.cancelEvent(event, true); + this.getElementsByClass = function(node, className) + { + var result = []; - return false; -}; + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (this.hasClass(child, className)) + result.push(child); + } -this.disableTextSelection = function(e) -{ - if (typeof e.onselectstart != "undefined") // IE - this.addEvent(e, "selectstart", disableTextSelectionHandler); + return result; + }; - else // others + this.getElementByClass = function(node, className) // className, className, ... { - e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; + 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; + } + } - // 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); - } + return null; + }; - e.style.cursor = "default"; -}; + this.isAncestor = function(node, potentialAncestor) + { + for (var parent = node; parent; parent = parent.parentNode) + { + if (parent == potentialAncestor) + return true; + } -this.restoreTextSelection = function(e) -{ - if (typeof e.onselectstart != "undefined") // IE - this.removeEvent(e, "selectstart", disableTextSelectionHandler); + return false; + }; - else // others + this.getNextElement = function(node) { - e.style.cssText = "cursor: default;"; + while (node && node.nodeType != 1) + node = node.nextSibling; - // 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" ] -}; + return node; + }; -this.getEventFamily = function(eventType) -{ - if (!this.families) + this.getPreviousElement = function(node) { - this.families = {}; + while (node && node.nodeType != 1) + node = node.previousSibling; - for (var family in eventTypes) - { - var types = eventTypes[family]; - for (var i = 0; i < types.length; ++i) - this.families[types[i]] = family; - } - } + return node; + }; - return this.families[eventType]; -}; + this.getBody = function(doc) + { + if (doc.body) + return doc.body; + var body = doc.getElementsByTagName("body")[0]; + if (body) + return body; -// ************************************************************************************************ -// URLs + return doc.firstChild; // For non-HTML docs + }; -this.getFileName = function(url) -{ - var split = this.splitURLBase(url); - return split.name; -}; + this.findNextDown = function(node, criteria) + { + if (!node) + return null; -this.splitURLBase = function(url) -{ - if (this.isDataURL(url)) - return this.splitDataURL(url); - return this.splitURLTrue(url); -}; + for (var child = node.firstChild; child; child = child.nextSibling) + { + if (criteria(child)) + return child; -this.splitDataURL = function(url) -{ - var mark = url.indexOf(':', 3); - if (mark != 4) - return false; // the first 5 chars must be 'data:' + var next = this.findNextDown(child, criteria); + if (next) + return next; + } + }; - var point = url.indexOf(',', mark+1); - if (point < mark) - return false; // syntax error + this.findPreviousUp = function(node, criteria) + { + if (!node) + return null; - var props = { encodedContent: url.substr(point+1) }; + for (var child = node.lastChild; child; child = child.previousSibling) + { + var next = this.findPreviousUp(child, criteria); + if (next) + return next; - 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]; - } + if (criteria(child)) + return child; + } + }; - // Additional Firebug-specific properties - if (props.hasOwnProperty('fileName')) + this.findNext = function(node, criteria, upOnly, maxRoot) { - var caller_URL = decodeURIComponent(props['fileName']); - var caller_split = this.splitURLTrue(caller_URL); + if (!node) + return null; - if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() + if (!upOnly) { - props['path'] = caller_split.path; - props['line'] = props['baseLineNumber']; - var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); - props['name'] = 'eval->'+hint; + var next = this.findNextDown(node, criteria); + if (next) + return next; } - else + + for (var sib = node.nextSibling; sib; sib = sib.nextSibling) { - props['name'] = caller_split.name; - props['path'] = caller_split.path; + if (criteria(sib)) + return sib; + + var next = this.findNextDown(sib, criteria); + if (next) + return next; } - } - else - { - if (!props.hasOwnProperty('path')) - props['path'] = "data:"; - if (!props.hasOwnProperty('name')) - props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); - } - return props; -}; + if (node.parentNode && node.parentNode != maxRoot) + return this.findNext(node.parentNode, criteria, true); + }; -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.findPrevious = function(node, criteria, downOnly, maxRoot) + { + if (!node) + return null; -this.getFileExtension = function(url) -{ - if (!url) - return null; + for (var sib = node.previousSibling; sib; sib = sib.previousSibling) + { + var prev = this.findPreviousUp(sib, criteria); + if (prev) + return prev; - // 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; -}; + if (criteria(sib)) + return sib; + } -this.isSystemPage = function(win) -{ - try - { - var doc = win.document; - if (!doc) - return false; + if (!downOnly) + { + var next = this.findPreviousUp(node, criteria); + if (next) + return next; + } - // 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; + if (node.parentNode && node.parentNode != maxRoot) + { + if (criteria(node.parentNode)) + return node.parentNode; - 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; - } -}; + return this.findPrevious(node.parentNode, criteria, true); + } + }; -this.isSystemStyleSheet = function(sheet) -{ - var href = sheet && sheet.href; - return href && FBL.isSystemURL(href); -}; + this.getNextByClass = function(root, state) + { + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findNext(root, iter); + }; -this.getURIHost = function(uri) -{ - try + this.getPreviousByClass = function(root, state) { - if (uri) - return uri.host; - else - return ""; - } - catch (exc) + var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; + return this.findPrevious(root, iter); + }; + + this.isElement = function(o) { - return ""; - } -}; + try { + return o && this.instanceOf(o, "Element"); + } + catch (ex) { + return false; + } + }; -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:"); -}; + // ************************************************************************************************ + // DOM Modification + + // TODO: xxxpedro use doc fragments in Context API + var appendFragment = null; -this.getLocalPath = function(url) -{ - if (this.isLocalURL(url)) + this.appendInnerHTML = function(element, html, referenceElement) { - 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, - 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; + // 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 m = reURL.exec(baseURL); - if (!m) - return ""; + var doc = element.ownerDocument; - 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; - } -}; + // 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 -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]; - } + var fragment = range.createContextualFragment(html); // parse + var firstChild = fragment.firstChild; + element.insertBefore(fragment, referenceElement); } - } - return url; -}; - -this.denormalizeURL = function(url) -{ - return url.replace(/file:\/\/\//g, "file:/"); -}; + else + { + if (!appendFragment || appendFragment.ownerDocument != doc) + appendFragment = doc.createDocumentFragment(); -this.parseURLParams = function(url) -{ - var q = url ? url.indexOf("?") : -1; - if (q == -1) - return []; + var div = doc.createElement("div"); + div.innerHTML = html; - var search = url.substr(q+1); - var h = search.lastIndexOf("#"); - if (h != -1) - search = search.substr(0, h); + var firstChild = div.firstChild; + while (div.firstChild) + appendFragment.appendChild(div.firstChild); - if (!search) - return []; + element.insertBefore(appendFragment, referenceElement); - return this.parseURLEncodedText(search); -}; + div = null; + } -this.parseURLEncodedText = function(text) -{ - var maxValueLength = 25000; + return firstChild; + }; - 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, " "); + // ************************************************************************************************ + // DOM creation - var args = text.split("&"); - for (var i = 0; i < args.length; ++i) + this.createElement = function(tagName, properties) { - try { - var parts = args[i].split("="); - if (parts.length == 2) - { - if (parts[1].length > maxValueLength) - parts[1] = this.$STR("LargeData"); + properties = properties || {}; + var doc = properties.document || FBL.Firebug.chrome.document; - params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); - } - else - params.push({name: decodeURIComponent(parts[0]), value: ""}); - } - catch (e) + var element = doc.createElement(tagName); + + for(var name in properties) { - if (FBTrace.DBG_ERRORS) + if (name != "document") { - FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); - FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + element[name] = properties[name]; } } - } - - 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 []; + return element; + }; - var search = url.substr(q+1); - var h = search.lastIndexOf("#"); - if (h != -1) - search = search.substr(0, h); + this.createGlobalElement = function(tagName, properties) + { + properties = properties || {}; + var doc = FBL.Env.browser.document; - if (!search) - return []; + var element = this.NS && doc.createElementNS ? + doc.createElementNS(FBL.NS, tagName) : + doc.createElement(tagName); - return this.parseURLEncodedTextArray(search); -}; + for(var name in properties) + { + var propname = name; + if (FBL.isIE && name == "class") propname = "className"; -this.parseURLEncodedTextArray = function(text) -{ - var maxValueLength = 25000; + if (name != "document") + { + element.setAttribute(propname, properties[name]); + } + } - var params = []; + return element; + }; - // 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) + this.safeGetWindowLocation = function(window) { - try { - var parts = args[i].split("="); - if (parts.length == 2) + try + { + if (window) { - if (parts[1].length > maxValueLength) - parts[1] = this.$STR("LargeData"); - - params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); + if (window.closed) + return "(window.closed)"; + if ("location" in window) + return window.location+""; + else + return "(no window.location)"; } else - params.push({name: decodeURIComponent(parts[0]), value: [""]}); + return "(no context.window)"; } - catch (e) + catch(exc) { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); - FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); - } + if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) + FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); + FBTrace.sysout("TabContext.getWindowLocation failed window:", window); + return "(getWindowLocation: "+exc+")"; } - } - - 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]); + // ************************************************************************************************ + // Events - var args = []; - for (var i = 0; i < params.length; ++i) - args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); + 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); + }; - var url = file.href; - url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); + 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); + }; - return url; -}; + 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.getResource = function(aURL) -{ - try + this.noKeyModifiers = function(event) { - var channel=ioService.newChannel(aURL,null,null); - var input=channel.open(); - return FBL.readFromStream(input); - } - catch (e) + return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; + }; + + this.isControlClick = function(event) { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.getResource FAILS for "+aURL, e); - } -}; + 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.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); + 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); + }; - if (matches) + this.isControl = function(event) { - jsonString = matches[1]; + return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; + }; - if (jsonString[0] == "\\" && jsonString[1] == "n") - jsonString = jsonString.substr(2); + this.isAlt = function(event) + { + return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; + }; - if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") - jsonString = jsonString.substr(0, jsonString.length-2); - } + 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); + }; - if (jsonString.indexOf("&&&START&&&")) + this.isControlShift = function(event) { - regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); - matches = regex.exec(jsonString); - if (matches) - jsonString = matches[1]; - } + return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; + }; - // throw on the extra parentheses - jsonString = "(" + jsonString + ")"; + this.isShift = function(event) + { + return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; + }; - ///var s = Components.utils.Sandbox(originURL); - var jsonObject = null; + this.addEvent = function(object, name, handler, useCapture) + { + if (object.addEventListener) + object.addEventListener(name, handler, useCapture); + else + object.attachEvent("on"+name, handler); + }; - try + this.removeEvent = function(object, name, handler, useCapture) { - ///jsonObject = Components.utils.evalInSandbox(jsonString, s); + 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); + } + }; - //jsonObject = Firebug.context.eval(jsonString); - jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); - } - catch(e) + this.cancelEvent = function(e, preventDefault) { - /*** - if (e.message.indexOf("is not defined")) + if (!e) return; + + if (preventDefault) { - 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; - } + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; } - else - {/**/ - if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) - FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); - return null; - ///} - } - return jsonObject; -}; + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; + }; -// ************************************************************************************************ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -this.objectToString = function(object) -{ - try - { - return object+""; - } - catch (exc) + this.addGlobalEvent = function(name, handler) { - return null; - } -}; + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; -// ************************************************************************************************ -// Input Caret Position + this.addEvent(doc, name, handler); -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(); - } -}; + if (this.Firebug.chrome.type == "popup") + this.addEvent(this.Firebug.chrome.document, name, handler); -// ************************************************************************************************ -// Input Selection Start / Caret Position + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.addEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } + } + }; -this.getInputSelectionStart = function(input) -{ - if (document.selection) + this.removeGlobalEvent = function(name, handler) { - var range = input.ownerDocument.selection.createRange(); - var text = range.text; + var doc = this.Firebug.browser.document; + var frames = this.Firebug.browser.window.frames; - //console.log("range", range.text); + this.removeEvent(doc, name, handler); - // 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); + if (this.Firebug.chrome.type == "popup") + this.removeEvent(this.Firebug.chrome.document, name, handler); - return range.text.length; + for (var i = 0, frame; frame = frames[i]; i++) + { + try + { + this.removeEvent(frame.document, name, handler); + } + catch(E) + { + // Avoid acess denied + } } - } - else if (typeof input.selectionStart != "undefined") - return input.selectionStart; + }; - return 0; -}; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ************************************************************************************************ -// Opera Tab Fix + this.dispatch = function(listeners, name, args) + { + if (!listeners) return; -function onOperaTabBlur(e) -{ - if (this.lastKey == 9) - this.focus(); -}; + try + {/**/ + if (typeof listeners.length != "undefined") + { + if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); -function onOperaTabKeyDown(e) -{ - this.lastKey = e.keyCode; -}; + 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"); -function onOperaTabFocus(e) -{ - this.lastKey = null; -}; + 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); + } + } + /**/ + }; -this.fixOperaTabKey = function(el) -{ - el.onfocus = onOperaTabFocus; - el.onblur = onOperaTabBlur; - el.onkeydown = onOperaTabKeyDown; -}; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + var disableTextSelectionHandler = function(event) + { + FBL.cancelEvent(event, true); -this.Property = function(object, name) -{ - this.object = object; - this.name = name; + return false; + }; - this.getObject = function() + this.disableTextSelection = function(e) { - return object[name]; - }; -}; + if (typeof e.onselectstart != "undefined") // IE + this.addEvent(e, "selectstart", disableTextSelectionHandler); -this.ErrorCopy = function(message) -{ - this.message = message; -}; + else // others + { + e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; -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) { } - } -} + // 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); + } -this.EventCopy = EventCopy; + e.style.cursor = "default"; + }; + this.restoreTextSelection = function(e) + { + if (typeof e.onselectstart != "undefined") // IE + this.removeEvent(e, "selectstart", disableTextSelectionHandler); -// ************************************************************************************************ -// Type Checking + else // others + { + e.style.cssText = "cursor: default;"; -var toString = Object.prototype.toString; -var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; + // 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); + } + }; -this.isArray = function(object) { - return toString.call(object) === '[object Array]'; -}; + // ************************************************************************************************ + // 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.isFunction = function(object) { - if (!object) return false; + this.getEventFamily = function(eventType) + { + if (!this.families) + { + this.families = {}; - return toString.call(object) === "[object Function]" || - this.isIE && typeof object != "string" && reFunction.test(""+object); -}; + 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]; + }; -// ************************************************************************************************ -// Instance Checking -this.instanceOf = function(object, className) -{ - if (!object || typeof object != "object") - return false; + // ************************************************************************************************ + // URLs - // 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) + this.getFileName = function(url) { - // find the correct window of the object - var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; + var split = this.splitURLBase(url); + return split.name; + }; - // 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 + this.splitURLBase = function(url) { - // 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; + if (this.isDataURL(url)) + return this.splitDataURL(url); + return this.splitURLTrue(url); + }; - // starts the hacky duck type detection - for(var n in cache) + this.splitDataURL = function(url) { - var obj = cache[n]; - var type = typeof obj; - obj = type == "object" ? obj : [obj]; + var mark = url.indexOf(':', 3); + if (mark != 4) + return false; // the first 5 chars must be 'data:' - 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 point = url.indexOf(',', mark+1); + if (point < mark) + return false; // syntax error - var value = obj[name]; + var props = { encodedContent: url.substr(point+1) }; - if( n == "property" && !(value in object) || - n == "method" && !this.isFunction(object[value]) || - n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) - return false; + 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]; } - } - return true; -}; + // Additional Firebug-specific properties + if (props.hasOwnProperty('fileName')) + { + var caller_URL = decodeURIComponent(props['fileName']); + var caller_split = this.splitURLTrue(caller_URL); -var instanceCheckMap = -{ - // DuckTypeCheck: - // { - // property: ["window", "document"], - // method: "setTimeout", - // value: {nodeType: 1} - // }, + 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*$/, ""); + } - Window: - { - property: ["window", "document"], - method: "setTimeout" - }, + return props; + }; - Document: + this.splitURLTrue = function(url) { - property: ["body", "cookie"], - method: "getElementById" - }, + 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]}; + }; - Node: + this.getFileExtension = function(url) { - property: "ownerDocument", - method: "appendChild" - }, + if (!url) + return null; - Element: - { - property: "tagName", - value: {nodeType: 1} - }, + // 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); + }; - Location: + this.isSystemURL = function(url) { - property: ["hostname", "protocol"], - method: "assign" - }, + 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; + }; - HTMLImageElement: + this.isSystemPage = function(win) { - property: "useMap", - value: + try { - nodeType: 1, - tagName: "img" - } - }, + var doc = win.document; + if (!doc) + return false; - HTMLAnchorElement: - { - property: "hreflang", - value: + // 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) { - nodeType: 1, - tagName: "a" + // 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); + }; - HTMLInputElement: + this.getURIHost = function(uri) { - property: "form", - value: + try { - nodeType: 1, - tagName: "input" + if (uri) + return uri.host; + else + return ""; } - }, + catch (exc) + { + return ""; + } + }; - HTMLButtonElement: + 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:"); + }; - HTMLFormElement: + this.getLocalPath = function(url) { - method: "submit", - value: + if (this.isLocalURL(url)) { - nodeType: 1, - tagName: "form" + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var file = fileHandler.getFileFromURLSpec(url); + return file.path; } - }, + }; - HTMLBodyElement: + this.getURLFromLocalFile = function(file) { + var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); + var URL = fileHandler.getURLSpecFromFile(file); + return URL; + }; - }, - - HTMLHtmlElement: + this.getDataURLForContent = function(content, url) { - + // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, + var uri = "data:text/html;"; + uri += "fileName="+encodeURIComponent(url)+ ","; + uri += encodeURIComponent(content); + return uri; }, - CSSStyleRule: + this.getDomain = function(url) { - property: ["selectorText", "style"] - } - -}; - - -// ************************************************************************************************ -// DOM Constants + var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); + return m ? m[1] : ""; + }; -/* + this.getURLPath = function(url) + { + var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); + return m ? m[1] : ""; + }; -Problems: + this.getPrettyDomain = function(url) + { + var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); + return m ? m[2] : ""; + }; - - IE does not have window.Node, window.Element, etc - - for (var name in Node.prototype) return nothing on FF + 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 domMemberMap2 = {}; + var m = reURL.exec(baseURL); + if (!m) + return ""; -var domMemberMap2Sandbox = null; + 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; + } + }; -var getDomMemberMap2 = function(name) -{ - if (!domMemberMap2Sandbox) + this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome { - 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"); + 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; + }; - else if (name.indexOf("Element") != -1) + this.denormalizeURL = function(url) { - object = domMemberMap2Sandbox.document.createElement("div"); - } + return url.replace(/file:\/\/\//g, "file:/"); + }; - if (object) + this.parseURLParams = function(url) { - //object = object.prototype || object; + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; - //props = 'addEventListener,document,location,navigator,window'.split(','); + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); - for (var n in object) - props.push(n); - } - /**/ + if (!search) + return []; - return props; - return extendArray(props, domMemberMap[name]); -}; + return this.parseURLEncodedText(search); + }; -// xxxpedro experimental get DOM members -this.getDOMMembers = function(object) -{ - if (!domMemberCache) + this.parseURLEncodedText = function(text) { - FBL.domMemberCache = domMemberCache = {}; + var maxValueLength = 25000; - for (var name in domMemberMap) + 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) { - var builtins = getDomMemberMap2(name); - var cache = domMemberCache[name] = {}; + try { + var parts = args[i].split("="); + if (parts.length == 2) + { + if (parts[1].length > maxValueLength) + parts[1] = this.$STR("LargeData"); - /* - if (name.indexOf("Element") != -1) + params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); + } + else + params.push({name: decodeURIComponent(parts[0]), value: ""}); + } + catch (e) { - this.append(cache, this.getDOMMembers("Node")); - this.append(cache, this.getDOMMembers("Element")); + if (FBTrace.DBG_ERRORS) + { + FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); + FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); + } } - /**/ - - 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] = {}; + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); - for (var i = 0; i < builtins.length; ++i) - cache[builtins[i]] = i; - } - } + return params; + }; - 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) + // 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) { - 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" - ], + var q = url ? url.indexOf("?") : -1; + if (q == -1) + return []; - "captionSide": - [ - "top", - "bottom", - "left", - "right" - ], + var search = url.substr(q+1); + var h = search.lastIndexOf("#"); + if (h != -1) + search = search.substr(0, h); - "clear": - [ - "left", - "right", - "both" - ], + if (!search) + return []; - "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" - ], + return this.parseURLEncodedTextArray(search); + }; - "bgAttachment": - [ - "scroll", - "fixed" - ], + this.parseURLEncodedTextArray = function(text) + { + var maxValueLength = 25000; - "bgPosition": - [ - "top", - "center", - "bottom", - "left", - "right" - ], + var params = []; - "bgRepeat": - [ - "repeat", - "repeat-x", - "repeat-y", - "no-repeat" - ], + // 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, " "); - "borderStyle": - [ - "hidden", - "dotted", - "dashed", - "solid", - "double", - "groove", - "ridge", - "inset", - "outset", - "-moz-bg-inset", - "-moz-bg-outset", - "-moz-bg-solid" - ], - - "borderCollapse": - [ - "collapse", - "separate" - ], + 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"); - "overflow": - [ - "visible", - "hidden", - "scroll", - "-moz-scrollbars-horizontal", - "-moz-scrollbars-none", - "-moz-scrollbars-vertical" - ], + 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]); + } + } + } - "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" - ], + params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); - "content": - [ - "open-quote", - "close-quote", - "no-open-quote", - "no-close-quote", - "inherit" - ], - - "fontStyle": - [ - "normal", - "italic", - "oblique", - "inherit" - ], + return params; + }; - "fontVariant": - [ - "normal", - "small-caps", - "inherit" - ], + this.reEncodeURL = function(file, text) + { + var lines = text.split("\n"); + var params = this.parseURLEncodedText(lines[lines.length-1]); - "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" - ], + var args = []; + for (var i = 0; i < params.length; ++i) + args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); - "textAlign": - [ - "left", - "right", - "center", - "justify" - ], + var url = file.href; + url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); - "tableLayout": - [ - "fixed" - ], + return url; + }; - "textDecoration": - [ - "underline", - "overline", - "line-through", - "blink" - ], + 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); + } + }; - "textTransform": - [ - "capitalize", - "lowercase", - "uppercase", - "inherit" - ], + 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); - "unicodeBidi": - [ - "normal", - "embed", - "bidi-override" - ], + if (matches) + { + jsonString = matches[1]; - "whiteSpace": - [ - "normal", - "pre", - "nowrap" - ], + if (jsonString[0] == "\\" && jsonString[1] == "n") + jsonString = jsonString.substr(2); - "verticalAlign": - [ - "baseline", - "sub", - "super", - "top", - "text-top", - "middle", - "bottom", - "text-bottom", - "inherit" - ], - - "thickness": - [ - "thin", - "medium", - "thick" - ], + if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") + jsonString = jsonString.substr(0, jsonString.length-2); + } - "userFocus": - [ - "ignore", - "normal" - ], + if (jsonString.indexOf("&&&START&&&")) + { + regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); + matches = regex.exec(jsonString); + if (matches) + jsonString = matches[1]; + } - "userInput": - [ - "disabled", - "enabled" - ], + // throw on the extra parentheses + jsonString = "(" + jsonString + ")"; - "userSelect": - [ - "normal" - ], + ///var s = Components.utils.Sandbox(originURL); + var jsonObject = null; - "mozBoxSizing": - [ - "content-box", - "padding-box", - "border-box" - ], + try + { + ///jsonObject = Components.utils.evalInSandbox(jsonString, s); - "mozBoxAlign": - [ - "start", - "center", - "end", - "baseline", - "stretch" - ], - - "mozBoxDirection": - [ - "normal", - "reverse" - ], + //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; + ///} + } - "mozBoxOrient": - [ - "horizontal", - "vertical" - ], + return jsonObject; + }; - "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 = this.getXHRObject(); - }, + // ************************************************************************************************ - getXHRObject: function() + this.objectToString = function(object) { - var xhrObj = false; try { - xhrObj = new XMLHttpRequest(); + return object+""; } - catch(e) + catch (exc) { - var progid = [ - "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" - ]; + return null; + } + }; - for ( var i=0; i < progid.length; ++i ) { - try - { - xhrObj = new ActiveXObject(progid[i]); - } - catch(e) - { - continue; - } - break; - } + // ************************************************************************************************ + // 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(); } - finally + else if (input.setSelectionRange) { - return xhrObj; + input.setSelectionRange(start, length); + input.focus(); } - }, + }; + // ************************************************************************************************ + // Input Selection Start / Caret Position - /** - * 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) + this.getInputSelectionStart = function(input) { - // process options - var o = FBL.extend( - { - // default values - type: "get", - async: true, - dataType: "text", - contentType: "application/x-www-form-urlencoded" - }, - options || {} - ); + if (document.selection) + { + var range = input.ownerDocument.selection.createRange(); + var text = range.text; - this.requests.push(o); + //console.log("range", range.text); - var s = this.getState(); - if (s == "Uninitialized" || s == "Complete" || s == "Loaded") - this.sendRequest(); - }, + // 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); - serialize: function(data) - { - var r = [""], rl = 0; - if (data) { - if (typeof data == "string") r[rl++] = data; + return range.text.length; + } + } + else if (typeof input.selectionStart != "undefined") + return input.selectionStart; - 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++] = "&"; - } + return 0; + }; - } else - for(var param in data) { - r[rl++] = encodeURIComponent(param); - r[rl++] = "="; - r[rl++] = encodeURIComponent(data[param]); - r[rl++] = "&"; - } - } - return r.join("").replace(/&$/, ""); - }, + // ************************************************************************************************ + // Opera Tab Fix + + function onOperaTabBlur(e) + { + if (this.lastKey == 9) + this.focus(); + }; - sendRequest: function() + function onOperaTabKeyDown(e) { - var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; + this.lastKey = e.keyCode; + }; - // open XHR object - t.open(r.type, r.url, r.async); + function onOperaTabFocus(e) + { + this.lastKey = null; + }; - //setRequestHeaders(); + this.fixOperaTabKey = function(el) + { + el.onfocus = onOperaTabFocus; + el.onblur = onOperaTabBlur; + el.onkeydown = onOperaTabKeyDown; + }; - // 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); + this.Property = function(object, name) + { + this.object = object; + this.name = name; - /** @ignore */ - // onreadystatechange handler - t.onreadystatechange = function() + this.getObject = function() { - FBL.Ajax.onStateChange(r); + return object[name]; }; + }; - // send the request - t.send(data); - }, - - /** - * Handles the state change - */ - onStateChange: function(options) + this.ErrorCopy = function(message) { - var fn, o = options, t = this.transport; - var state = this.getState(t); - - if (fn = o["on" + state]) fn(this.getResponse(o), o); + this.message = message; + }; - if (state == "Complete") + 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) { - var success = t.status == 200, response = this.getResponse(o); - - if (fn = o["onUpdate"]) - fn(response, o); + try { + this[name] = event[name]; + } catch (exc) { } + } + } - if (fn = o["on" + (success ? "Success" : "Failure")]) - fn(response, o); + this.EventCopy = EventCopy; - t.onreadystatechange = FBL.emptyFn; - if (this.requests.length > 0) - setTimeout(this.sendRequest, 10); - } - }, + // ************************************************************************************************ + // Type Checking - /** - * gets the appropriate response value according the type - */ - getResponse: function(options) - { - var t = this.transport, type = options.dataType; + var toString = Object.prototype.toString; + var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; - 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 + ")"); - }, + this.isArray = function(object) { + return toString.call(object) === '[object Array]'; + }; - /** - * returns the current state of the XHR object - */ - getState: function() - { - return this.states[this.transport.readyState]; - } + this.isFunction = function(object) { + if (!object) return false; -}; + return toString.call(object) === "[object Function]" || + this.isIE && typeof object != "string" && reFunction.test(""+object); + }; -// ************************************************************************************************ -// Cookie, from http://www.quirksmode.org/js/cookies.html + // ************************************************************************************************ + // Instance Checking -this.createCookie = function(name,value,days) -{ - if ('cookie' in document) + this.instanceOf = function(object, className) { - if (days) + 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) { - var date = new Date(); - date.setTime(date.getTime()+(days*24*60*60*1000)); - var expires = "; expires="+date.toGMTString(); + // 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 - 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); + // 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]; } - } - return null; -}; + // get the duck type model from the cache + var cache = instanceCheckMap[className]; + if (!cache) + return false; -this.removeCookie = function(name) -{ - this.createCookie(name, "", -1); -}; + // 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; -// ************************************************************************************************ -// 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 value = obj[name]; -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); + if( n == "property" && !(value in object) || + n == "method" && !this.isFunction(object[value]) || + n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) + return false; + } + } - FBL.pixelsPerInch = { - x: inch.offsetWidth, - y: inch.offsetHeight + return true; }; - 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... + var instanceCheckMap = { - return "{\"href\":\""+this.href+"\", "+ - (this.line?("\"line\":"+this.line+","):"")+ - (this.type?(" \"type\":\""+this.type+"\","):"")+ - "}"; - } + // DuckTypeCheck: + // { + // property: ["window", "document"], + // method: "setTimeout", + // value: {nodeType: 1} + // }, -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -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"' -}; - -// ************************************************************************************************ + Window: + { + property: ["window", "document"], + method: "setTimeout" + }, -FBL.$STR = function(name) -{ - return oSTR.hasOwnProperty(name) ? oSTR[name] : name; -}; + Document: + { + property: ["body", "cookie"], + method: "getElementById" + }, -FBL.$STRF = function(name, args) -{ - if (!oSTR.hasOwnProperty(name)) return name; + Node: + { + property: "ownerDocument", + method: "appendChild" + }, - var format = oSTR[name]; - var objIndex = 0; + Element: + { + property: "tagName", + value: {nodeType: 1} + }, - var parts = parseFormat(format); - var trialIndex = objIndex; - var objects = args; + Location: + { + property: ["hostname", "protocol"], + method: "assign" + }, - for (var i= 0; i < parts.length; i++) - { - var part = parts[i]; - if (part && typeof(part) == "object") + HTMLImageElement: { - if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. + property: "useMap", + value: { - format = ""; - objIndex = -1; - parts.length = 0; - break; + nodeType: 1, + tagName: "img" } - } - - } + }, - var result = []; - for (var i = 0; i < parts.length; ++i) - { - var part = parts[i]; - if (part && typeof(part) == "object") + HTMLAnchorElement: { - result.push(""+args.shift()); - } - else - result.push(part); - } - - return result.join(""); -}; - -// ************************************************************************************************ - -var parseFormat = function parseFormat(format) -{ - var parts = []; - if (format.length <= 0) - return parts; + property: "hreflang", + value: + { + nodeType: 1, + tagName: "a" + } + }, - 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) == "%%") + HTMLInputElement: { - parts.push(format.substr(0, m.index)); - parts.push(m[0].substr(1)); - } - else + property: "form", + value: + { + nodeType: 1, + tagName: "input" + } + }, + + HTMLButtonElement: { - var type = m[8] ? m[8] : m[5]; - var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + // ? + }, - var rep = null; - switch (type) + HTMLFormElement: + { + method: "submit", + value: { - case "s": - rep = FirebugReps.Text; - break; - case "f": - case "i": - case "d": - rep = FirebugReps.Number; - break; - case "o": - rep = null; - break; + nodeType: 1, + tagName: "form" } + }, - parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); - parts.push({rep: rep, precision: precision, type: ("%" + type)}); - } + HTMLBodyElement: + { - format = format.substr(m.index+m[0].length); - } + }, - parts.push(format); - return parts; -}; + HTMLHtmlElement: + { -// ************************************************************************************************ -}}); + }, -/* See license.txt for terms of usage */ + CSSStyleRule: + { + property: ["selectorText", "style"] + } -FBL.ns( /** @scope s_firebug */ function() { with (FBL) { -// ************************************************************************************************ + }; -// ************************************************************************************************ -// Globals -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Internals + // ************************************************************************************************ + // DOM Constants -var modules = []; -var panelTypes = []; -var panelTypeMap = {}; -var reps = []; + /* -var parentPanelMap = {}; + Problems: + - IE does not have window.Node, window.Element, etc + - for (var name in Node.prototype) return nothing on FF -// ************************************************************************************************ -// Firebug + */ -/** - * @namespace describe Firebug - * @exports FBL.Firebug as Firebug - */ -FBL.Firebug = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - version: "Firebug Lite 1.4.0a1", - revision: "$Revision$", - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - modules: modules, - panelTypes: panelTypes, - panelTypeMap: panelTypeMap, - reps: reps, + var domMemberMap2 = {}; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Initialization + var domMemberMap2Sandbox = null; - initialize: function() + var getDomMemberMap2 = function(name) { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); - - Firebug.browser = new Context(Env.browser); - Firebug.context = Firebug.browser; - - // Document must be cached before chrome initialization - cacheDocument(); - - if (Firebug.Inspector && Firebug.Inspector.create) - Firebug.Inspector.create(); - - if (FBL.processAllStyleSheets) - processAllStyleSheets(Firebug.browser.document); - - FirebugChrome.initialize(); - - dispatch(modules, "initialize", []); - - if (Env.onLoad) + if (!domMemberMap2Sandbox) { - var onLoad = Env.onLoad; - delete Env.onLoad; - - setTimeout(onLoad, 200); - } - }, - - shutdown: function() - { - if (Firebug.Inspector) - Firebug.Inspector.destroy(); + var doc = Firebug.chrome.document; + var frame = doc.createElement("iframe"); - dispatch(modules, "shutdown", []); + frame.id = "FirebugSandbox"; + frame.style.display = "none"; + frame.src = "about:blank"; - var chromeMap = FirebugChrome.chromeMap; + doc.body.appendChild(frame); - 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); - } - } + domMemberMap2Sandbox = frame.window || frame.contentWindow; } - Firebug.Lite.Cache.Element.clear(); - Firebug.Lite.Cache.StyleSheet.clear(); + var props = []; - Firebug.browser = null; - Firebug.context = null; - }, + //var object = domMemberMap2Sandbox[name]; + //object = object.prototype || object; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Registration + var object = null; - registerModule: function() - { - modules.push.apply(modules, arguments); + if (name == "Window") + object = domMemberMap2Sandbox.window; - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); - }, + else if (name == "Document") + object = domMemberMap2Sandbox.document; - registerPanel: function() - { - panelTypes.push.apply(panelTypes, arguments); + else if (name == "HTMLScriptElement") + object = domMemberMap2Sandbox.document.createElement("script"); - for (var i = 0, panelType; panelType = arguments[i]; ++i) - { - panelTypeMap[panelType.prototype.name] = arguments[i]; + else if (name == "HTMLAnchorElement") + object = domMemberMap2Sandbox.document.createElement("a"); - if (panelType.prototype.parentPanel) - parentPanelMap[panelType.prototype.parentPanel] = 1; + else if (name.indexOf("Element") != -1) + { + object = domMemberMap2Sandbox.document.createElement("div"); } - 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); - }, + if (object) + { + //object = object.prototype || object; - unregisterRep: function() - { - for (var i = 0; i < arguments.length; ++i) - remove(reps, arguments[i]); - }, + //props = 'addEventListener,document,location,navigator,window'.split(','); - setDefaultReps: function(funcRep, rep) - { - FBL.defaultRep = rep; - FBL.defaultFuncRep = funcRep; - }, + for (var n in object) + props.push(n); + } + /**/ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Reps + return props; + return extendArray(props, domMemberMap[name]); + }; - getRep: function(object) + // xxxpedro experimental get DOM members + this.getDOMMembers = function(object) { - var type = typeof object; - if (isIE && isFunction(object)) - type = "function"; - - for (var i = 0; i < reps.length; ++i) + if (!domMemberCache) { - 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) + FBL.domMemberCache = domMemberCache = {}; + + for (var name in domMemberMap) { - if (FBTrace.DBG_ERRORS) + var builtins = getDomMemberMap2(name); + var cache = domMemberCache[name] = {}; + + /* + if (name.indexOf("Element") != -1) { - 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(); + this.append(cache, this.getDOMMembers("Node")); + this.append(cache, this.getDOMMembers("Element")); } - } - } - - 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; + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; } } - }, - getRepNode: function(node) - { - for (var child = node; child; child = child.parentNode) + try { - if (child.repObject) - return child; + 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 {}; } - }, - - getElementByRepObject: function(element, object) - { - for (var child = element.firstChild; child; child = child.nextSibling) + catch(E) { - if (child.repObject == object) - return child; - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Preferences - - getPref: function(name) - { - return Firebug[name]; - }, + if (FBTrace.DBG_ERRORS) + FBTrace.sysout("lib.getDOMMembers FAILED ", E); - setPref: function(name, value) - { - Firebug[name] = value; + return {}; + } + }; - this.savePrefs(); - }, - setPrefs: function(prefs) + /* + this.getDOMMembers = function(object) { - for (var name in prefs) + if (!domMemberCache) { - if (prefs.hasOwnProperty(name)) - Firebug[name] = prefs[name]; - } + domMemberCache = {}; - this.savePrefs(); - }, + for (var name in domMemberMap) + { + var builtins = domMemberMap[name]; + var cache = domMemberCache[name] = {}; - restorePrefs: function() - { - var Options = Env.Options; + for (var i = 0; i < builtins.length; ++i) + cache[builtins[i]] = i; + } + } - for (var name in Options) + try { - Firebug[name] = Options[name]; + 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 {}; } - }, - - loadPrefs: function(prefs) - { - this.restorePrefs(); - - prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); - - for (var name in prefs) + catch(E) { - if (prefs.hasOwnProperty(name)) - Firebug[name] = prefs[name]; + return {}; } - }, + }; + /**/ - savePrefs: function() + this.isDOMMember = function(object, propName) { - var json = ['{'], jl = 0; - var Options = Env.Options; + var members = this.getDOMMembers(object); + return members && propName in members; + }; - for (var name in Options) - { - if (Options.hasOwnProperty(name)) - { - var value = Firebug[name]; + var domMemberCache = null; + var domMemberMap = {}; - json[++jl] = '"'; - json[++jl] = name; + 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", - var type = typeof value; - if (type == "boolean" || type == "number") - { - json[++jl] = '":'; - json[++jl] = value; - json[++jl] = ','; - } - else - { - json[++jl] = '":"'; - json[++jl] = value; - json[++jl] = '",'; - } - } - } + "width", + "height", - json.length = jl--; - json[++jl] = '}'; + "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" + ]); - createCookie("FirebugLite", json.join("")); - }, + 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", - erasePrefs: function() - { - removeCookie("FirebugLite"); - } -}; + "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" -Firebug.restorePrefs(); + ]); -// xxxpedro should we remove this? -window.Firebug = FBL.Firebug; + domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, + [ + "src" + ]); -if (!Env.Options.enablePersistent || - Env.Options.enablePersistent && Env.isChromeContext || - Env.isDebugMode) - Env.browser.window.Firebug = FBL.Firebug; + domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, + [ + "accessKey", + "disabled", + "form", + "name", + "type", + "value", + "click" + ]); -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Other methods + 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", -FBL.cacheDocument = function cacheDocument() -{ - var ElementCache = Firebug.Lite.Cache.Element; - var els = Firebug.browser.document.getElementsByTagName("*"); - for (var i=0, l=els.length, el; iFirebug.registerModule 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() - { - }, + domMemberMap.Text = extendArray(domMemberMap.Node, + [ + "data", + "length", + + "appendData", + "deleteData", + "insertData", + "replaceData", + "splitText", + "substringData" + ]); + + domMemberMap.Attr = extendArray(domMemberMap.Node, + [ + "name", + "value", + "specified", + "ownerElement" + ]); - /** - * Called when the window is closed. - */ - shutdown: function() - { - }, + 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" + ]; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - /** - * Called when a new context is created but before the page is loaded. - */ - initContext: function(context) - { - }, + 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 + }; - /** - * Called after a context is detached to a separate window; - */ - reattachContext: function(browser, context) - { - }, + 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": [] + }; - /** - * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. - */ - destroyContext: function(context, persistedState) - { - }, + 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 + }; - // 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) + 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" + ], - /** - * Called after a context's page gets DOMContentLoaded - */ - loadedContext: function(context) - { - }, + "none": + [ + "none" + ], - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + "captionSide": + [ + "top", + "bottom", + "left", + "right" + ], - showPanel: function(browser, panel) - { - }, + "clear": + [ + "left", + "right", + "both" + ], - showSidePanel: function(browser, panel) - { - }, + "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" + ], - updateOption: function(name, value) - { - }, + "bgPosition": + [ + "top", + "center", + "bottom", + "left", + "right" + ], + + "bgRepeat": + [ + "repeat", + "repeat-x", + "repeat-y", + "no-repeat" + ], - getObjectByURL: function(context, url) - { - } -}); + "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" + ], -// ************************************************************************************************ -// Panel + "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" + ], -/** - * @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!", + "textAlign": + [ + "left", + "right", + "center", + "justify" + ], - parentPanel: null, + "tableLayout": + [ + "fixed" + ], - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + "textDecoration": + [ + "underline", + "overline", + "line-through", + "blink" + ], - options: { - hasCommandLine: false, - hasStatusBar: false, - hasToolButtons: false, + "textTransform": + [ + "capitalize", + "lowercase", + "uppercase", + "inherit" + ], - // Pre-rendered panels are those included in the skin file (firebug.html) - isPreRendered: false, - innerHTMLSync: false + "unicodeBidi": + [ + "normal", + "embed", + "bidi-override" + ], - /* - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // To be used by external extensions - panelHTML: "", - panelCSS: "", + "whiteSpace": + [ + "normal", + "pre", + "nowrap" + ], - toolButtonsHTML: "" - /**/ - }, + "verticalAlign": + [ + "baseline", + "sub", + "super", + "top", + "text-top", + "middle", + "bottom", + "text-bottom", + "inherit" + ], + + "thickness": + [ + "thin", + "medium", + "thick" + ], - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + "userFocus": + [ + "ignore", + "normal" + ], - tabNode: null, - panelNode: null, - sidePanelNode: null, - statusBarNode: null, - toolButtonsNode: null, + "userInput": + [ + "disabled", + "enabled" + ], - panelBarNode: null, + "userSelect": + [ + "normal" + ], - sidePanelBarBoxNode: null, - sidePanelBarNode: null, + "mozBoxSizing": + [ + "content-box", + "padding-box", + "border-box" + ], - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + "mozBoxAlign": + [ + "start", + "center", + "end", + "baseline", + "stretch" + ], + + "mozBoxDirection": + [ + "normal", + "reverse" + ], - sidePanelBar: null, + "mozBoxOrient": + [ + "horizontal", + "vertical" + ], - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + "mozBoxPack": + [ + "start", + "center", + "end" + ] + }; - searchable: false, - editable: true, - order: 2147483647, - statusSeparator: "<", + this.nonEditableTags = + { + "HTML": 1, + "HEAD": 1, + "html": 1, + "head": 1 + }; - create: function(context, doc) + this.innerEditableTags = { - this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); + "BODY": 1, + "body": 1 + }; - this.panelBarNode = $("fbPanelBar1"); - this.sidePanelBarBoxNode = $("fbPanelBar2"); + 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 + }; - if (this.hasSidePanel) - { - this.sidePanelBar = extend({}, PanelBar); - this.sidePanelBar.create(this); - } + 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, + */ + }; - var options = this.options = extend(Firebug.Panel.options, this.options); - var panelId = "fb" + this.name; - if (options.isPreRendered) - { - this.panelNode = $(panelId); + 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 + }; + } - this.tabNode = $(panelId + "Tab"); - this.tabNode.style.display = "block"; - if (options.hasToolButtons) + // ************************************************************************************************ + // Ajax + + /** + * @namespace + */ + this.Ajax = + { + + requests: [], + transport: null, + states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], + + initialize: function() + { + this.transport = this.getXHRObject(); + }, + + getXHRObject: function() + { + var xhrObj = false; + try { - this.toolButtonsNode = $(panelId + "Buttons"); + xhrObj = new XMLHttpRequest(); } + catch(e) + { + var progid = [ + "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" + ]; - if (options.hasStatusBar) + for ( var i=0; i < progid.length; ++i ) { + try + { + xhrObj = new ActiveXObject(progid[i]); + } + catch(e) + { + continue; + } + break; + } + } + finally { - this.statusBarBox = $("fbStatusBarBox"); - this.statusBarNode = $(panelId + "StatusBar"); + return xhrObj; } - } - else + }, + + + /** + * 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) { - var containerSufix = this.parentPanel ? "2" : "1"; + // process options + var o = FBL.extend( + { + // default values + type: "get", + async: true, + dataType: "text", + contentType: "application/x-www-form-urlencoded" + }, + options || {} + ); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Create Panel - var panelNode = this.panelNode = createElement("div", { - id: panelId, - className: "fbPanel" - }); + this.requests.push(o); - $("fbPanel" + containerSufix).appendChild(panelNode); + var s = this.getState(); + if (s == "Uninitialized" || s == "Complete" || s == "Loaded") + this.sendRequest(); + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Create Panel Tab - var tabHTML = '' + - this.title + ''; + serialize: function(data) + { + var r = [""], rl = 0; + if (data) { + if (typeof data == "string") r[rl++] = data; - var tabNode = this.tabNode = createElement("a", { - id: panelId + "Tab", - className: "fbTab fbHover", - innerHTML: tabHTML - }); + 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++] = "&"; + } - if (isIE6) - { - tabNode.href = "javascript:void(0)"; + } else + for(var param in data) { + r[rl++] = encodeURIComponent(param); + r[rl++] = "="; + r[rl++] = encodeURIComponent(data[param]); + r[rl++] = "&"; + } } + return r.join("").replace(/&$/, ""); + }, - var panelBarNode = this.parentPanel ? - Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : - this.panelBarNode; - - panelBarNode.appendChild(tabNode); - tabNode.style.display = "block"; + sendRequest: function() + { + var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create ToolButtons - if (options.hasToolButtons) - { - this.toolButtonsNode = createElement("span", { - id: panelId + "Buttons", - className: "fbToolbarButtons" - }); + // open XHR object + t.open(r.type, r.url, r.async); - $("fbToolbarButtons").appendChild(this.toolButtonsNode); - } + //setRequestHeaders(); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create StatusBar - if (options.hasStatusBar) - { - this.statusBarBox = $("fbStatusBarBox"); + // indicates that it is a XHR request to the server + t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - this.statusBarNode = createElement("span", { - id: panelId + "StatusBar", - className: "fbToolbarButtons fbStatusBar" - }); + // if data is being sent, sets the appropriate content-type + if (data = FBL.Ajax.serialize(r.data)) + t.setRequestHeader("Content-Type", r.contentType); - this.statusBarBox.appendChild(this.statusBarNode); - } + /** @ignore */ + // onreadystatechange handler + t.onreadystatechange = function() + { + FBL.Ajax.onStateChange(r); + }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create SidePanel - } + // send the request + t.send(data); + }, - this.containerNode = this.panelNode.parentNode; + /** + * Handles the state change + */ + onStateChange: function(options) + { + var fn, o = options, t = this.transport; + var state = this.getState(t); - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); + if (fn = o["on" + state]) fn(this.getResponse(o), o); - // xxxpedro contextMenu - this.onContextMenu = bind(this.onContextMenu, this); + if (state == "Complete") + { + var status = t.status == 1223 ? 204 : t.status; + var success = status >= 200 && status <= 299, response = this.getResponse(o); - /* - this.context = context; - this.document = doc; + if (fn = o["onUpdate"]) + fn(response, o); - this.panelNode = doc.createElement("div"); - this.panelNode.ownerPanel = this; + if (fn = o["on" + (success ? "Success" : "Failure")]) + fn(response, o); - setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); - doc.body.appendChild(this.panelNode); + t.onreadystatechange = FBL.emptyFn; - if (FBTrace.DBG_INITIALIZE) - FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); + if (this.requests.length > 0) + setTimeout(this.sendRequest, 10); + } + }, - this.initializeNode(this.panelNode); - /**/ - }, + /** + * gets the appropriate response value according the type + */ + getResponse: function(options) + { + var t = this.transport, type = options.dataType; + var status = t.status == 1223 ? 204 : t.status; - destroy: function(state) // Panel may store info on state - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); + if (status >= 200 && status <= 299) 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 + ")"); + }, - if (this.hasSidePanel) + /** + * returns the current state of the XHR object + */ + getState: function() { - this.sidePanelBar.destroy(); - this.sidePanelBar = null; + return this.states[this.transport.readyState]; } - 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; + // ************************************************************************************************ + // Cookie, from http://www.quirksmode.org/js/cookies.html - //if (this.panelNode) - // delete this.panelNode.ownerPanel; + 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 = ""; - //this.destroyNode(); - }, + document.cookie = name+"="+value+expires+"; path=/"; + } + }; - initialize: function() + this.readCookie = function (name) { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (this.hasSidePanel) + if ('cookie' in document) { - this.sidePanelBar.initialize(); + 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); + } } - var options = this.options = extend(Firebug.Panel.options, this.options); - var panelId = "fb" + this.name; + return null; + }; - this.panelNode = $(panelId); + this.removeCookie = function(name) + { + this.createCookie(name, "", -1); + }; - this.tabNode = $(panelId + "Tab"); - this.tabNode.style.display = "block"; - if (options.hasStatusBar) + // ************************************************************************************************ + // http://www.mister-pixel.com/#Content__state=is_that_simple + var fixIE6BackgroundImageCache = function(doc) + { + doc = doc || document; + try { - this.statusBarBox = $("fbStatusBarBox"); - this.statusBarNode = $(panelId + "StatusBar"); + doc.execCommand("BackgroundImageCache", false, true); } - - if (options.hasToolButtons) + catch(E) { - this.toolButtonsNode = $(panelId + "Buttons"); - } - this.containerNode = this.panelNode.parentNode; + } + }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // restore persistent state - this.containerNode.scrollTop = this.lastScrollTop; + // ************************************************************************************************ + // calculatePixelsPerInch - // xxxpedro contextMenu - addEvent(this.containerNode, "contextmenu", this.onContextMenu); + 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); - /// TODO: xxxpedro infoTip Hack - Firebug.chrome.currentPanel = - Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? - Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : - Firebug.chrome.selectedPanel; + FBL.pixelsPerInch = { + x: inch.offsetWidth, + y: inch.offsetHeight + }; - Firebug.showInfoTips = true; - Firebug.InfoTip.initializeBrowser(Firebug.chrome); - }, + body.removeChild(inch); + }; - shutdown: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); - /// TODO: xxxpedro infoTip Hack - Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (Firebug.chrome.largeCommandLineVisible) - Firebug.chrome.hideLargeCommandLine(); + this.SourceLink = function(url, line, type, object, instance) + { + this.href = url; + this.instance = instance; + this.line = line; + this.type = type; + this.object = object; + }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (this.hasSidePanel) + this.SourceLink.prototype = + { + toString: function() + { + return this.href; + }, + toJSON: function() // until 3.1... { - // 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(); + return "{\"href\":\""+this.href+"\", "+ + (this.line?("\"line\":"+this.line+","):"")+ + (this.type?(" \"type\":\""+this.type+"\","):"")+ + "}"; } - // store persistent state - this.lastScrollTop = this.containerNode.scrollTop; + }; - // xxxpedro contextMenu - removeEvent(this.containerNode, "contextmenu", this.onContextMenu); - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - detach: function(oldChrome, newChrome) + this.SourceText = function(lines, owner) { - if (oldChrome.selectedPanel.name == this.name) - this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; - }, + this.lines = lines; + this.owner = owner; + }; - reattach: function(doc) + this.SourceText.getLineAsHTML = function(lineNo) { - if (this.options.innerHTMLSync) - this.synchronizeUI(); - }, + return escapeForSourceLine(this.lines[lineNo-1]); + }; - synchronizeUI: function() - { - this.containerNode.scrollTop = this.lastScrollTop || 0; - }, - show: function(state) + // ************************************************************************************************ + }).apply(FBL); + + /* See license.txt for terms of usage */ + + FBL.ns( /** @scope s_i18n */ function() { with (FBL) { + // ************************************************************************************************ + + // TODO: xxxpedro localization + var oSTR = { - var options = this.options; + "NoMembersWarning": "There are no properties to show for this object.", - if (options.hasStatusBar) - { - this.statusBarBox.style.display = "inline"; - this.statusBarNode.style.display = "inline"; - } + "EmptyStyleSheet": "There are no rules in this stylesheet.", + "EmptyElementCSS": "This element has no style rules.", + "AccessRestricted": "Access to restricted URI denied.", - if (options.hasToolButtons) - { - this.toolButtonsNode.style.display = "inline"; - } + "net.label.Parameters": "Parameters", + "net.label.Source": "Source", + "URLParameters": "Params", - this.panelNode.style.display = "block"; + "EditStyle": "Edit Element Style...", + "NewRule": "New Rule...", - this.visible = true; + "NewProp": "New Property...", + "EditProp": 'Edit "%s"', + "DeleteProp": 'Delete "%s"', + "DisableProp": 'Disable "%s"' + }; - if (!this.parentPanel) - Firebug.chrome.layout(this); - }, + // ************************************************************************************************ - hide: function(state) + FBL.$STR = function(name) { - var options = this.options; + return oSTR.hasOwnProperty(name) ? oSTR[name] : name; + }; - if (options.hasStatusBar) + 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++) { - this.statusBarBox.style.display = "none"; - this.statusBarNode.style.display = "none"; + 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; + } + } + } - if (options.hasToolButtons) + var result = []; + for (var i = 0; i < parts.length; ++i) { - this.toolButtonsNode.style.display = "none"; + var part = parts[i]; + if (part && typeof(part) == "object") + { + result.push(""+args.shift()); + } + else + result.push(part); } - this.panelNode.style.display = "none"; + return result.join(""); + }; - this.visible = false; - }, + // ************************************************************************************************ - watchWindow: function(win) + var parseFormat = function parseFormat(format) { - }, + var parts = []; + if (format.length <= 0) + return parts; - unwatchWindow: function(win) - { - }, + 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); - updateOption: function(name, value) - { - }, + 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 /** - * Toolbar helpers + * @namespace describe Firebug + * @exports FBL.Firebug as Firebug */ - showToolbarButtons: function(buttonsId, show) + FBL.Firebug = { - try + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + version: "Firebug Lite 1.4.0a1", + revision: "$Revision$", + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + modules: modules, + panelTypes: panelTypes, + panelTypeMap: panelTypeMap, + reps: reps, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Initialization + + initialize: function() { - if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); + + Firebug.browser = new Context(Env.browser); + Firebug.context = Firebug.browser; + + // Document must be cached before chrome initialization + cacheDocument(); + + if (Firebug.Inspector && Firebug.Inspector.create) + Firebug.Inspector.create(); + + if (FBL.processAllStyleSheets) + processAllStyleSheets(Firebug.browser.document); + + FirebugChrome.initialize(); + + dispatch(modules, "initialize", []); + + if (Env.onLoad) { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); + var onLoad = Env.onLoad; + delete Env.onLoad; - return; + setTimeout(onLoad, 200); } - var buttons = this.context.browser.chrome.$(buttonsId); - if (buttons) - collapse(buttons, show ? "false" : "true"); - } - catch (exc) + }, + + shutdown: function() { - if (FBTrace.DBG_ERRORS) + if (Firebug.Inspector) + Firebug.Inspector.destroy(); + + dispatch(modules, "shutdown", []); + + var chromeMap = FirebugChrome.chromeMap; + + for (var name in chromeMap) { - FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); - if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); + 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(); - /** - * 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; - }, + Firebug.browser = null; + Firebug.context = null; + }, - hasObject: function(object) // beyond type testing, is this object selectable? - { - return false; - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Registration - select: function(object, forceUpdate) - { - if (!object) - object = this.getDefaultSelection(this.context); + registerModule: function() + { + modules.push.apply(modules, arguments); - if(FBTrace.DBG_PANELS) - FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); + }, - if (forceUpdate || object != this.selection) + registerPanel: function() { - this.selection = object; - this.updateSelection(object); + panelTypes.push.apply(panelTypes, arguments); - // 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 - } - }, + for (var i = 0, panelType; panelType = arguments[i]; ++i) + { + panelTypeMap[panelType.prototype.name] = arguments[i]; - updateSelection: function(object) - { - }, + if (panelType.prototype.parentPanel) + parentPanelMap[panelType.prototype.parentPanel] = 1; + } - markChange: function(skipSelf) - { - if (this.dependents) + 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) { - if (skipSelf) + var target = null; + for (var child = node; child; child = child.parentNode) { - for (var i = 0; i < this.dependents.length; ++i) + if (hasClass(child, "repTarget")) + target = child; + + if (child.repObject) { - var panelName = this.dependents[i]; - if (panelName != this.name) - this.context.invalidatePanels(panelName); + if (!target && hasClass(child, "repIgnore")) + break; + else + return child.repObject; } } - else - this.context.invalidatePanels.apply(this.context, this.dependents); - } - }, + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + getRepNode: function(node) + { + for (var child = node; child; child = child.parentNode) + { + if (child.repObject) + return child; + } + }, - startInspecting: function() - { - }, + getElementByRepObject: function(element, object) + { + for (var child = element.firstChild; child; child = child.nextSibling) + { + if (child.repObject == object) + return child; + } + }, - stopInspecting: function(object, cancelled) - { - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Preferences - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + getPref: function(name) + { + return Firebug[name]; + }, - search: function(text, reverse) - { - }, + setPref: function(name, value) + { + Firebug[name] = value; - /** - * 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") - ]; - }, + this.savePrefs(); + }, - /** - * 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++); + setPrefs: function(prefs) + { + for (var name in prefs) + { + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } - 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; + this.savePrefs(); + }, + + restorePrefs: function() + { + var Options = Env.Options; + + for (var name in Options) + { + Firebug[name] = Options[name]; } - }; + }, - for (var next = 0; next < allLocs.length - 1; next++) + loadPrefs: function(prefs) { - var object = allLocs[transformIndex(next)]; + this.restorePrefs(); - if (match(object)) + prefs = prefs || eval("(" + readCookie("FirebugLite") + ")"); + + for (var name in prefs) { - this.navigate(object); - return object; + if (prefs.hasOwnProperty(name)) + Firebug[name] = prefs[name]; + } + }, + + savePrefs: function() + { + var json = ['{'], jl = 0; + var Options = Env.Options; + + for (var name in Options) + { + if (Options.hasOwnProperty(name)) + { + var value = Firebug[name]; + + json[++jl] = '"'; + json[++jl] = name; + + var type = typeof value; + if (type == "boolean" || type == "number") + { + json[++jl] = '":'; + json[++jl] = value; + json[++jl] = ','; + } + else + { + json[++jl] = '":"'; + json[++jl] = value; + json[++jl] = '",'; + } + } } + + json.length = jl--; + json[++jl] = '}'; + + createCookie("FirebugLite", json.join("")); + }, + + erasePrefs: function() + { + removeCookie("FirebugLite"); } - }, + }; + + 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 - // Called when "Options" clicked. Return array of - // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } - getOptionsMenuItems: function() + FBL.cacheDocument = function cacheDocument() { - return null; - }, + var ElementCache = Firebug.Lite.Cache.Element; + var els = Firebug.browser.document.getElementsByTagName("*"); + for (var i=0, l=els.length, el; iFirebug.registerModule 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 */ { - return Firebug.getRepObject(target); - }, + /** + * 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 = '' + + this.title + ''; + + 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; + Firebug.InfoTip.initializeBrowser(Firebug.chrome); + }, + + shutdown: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); + + /// TODO: xxxpedro infoTip Hack + 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.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: , command:function to set } + 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: + *
  • this.startMeasuring(view);
  • + *
  • var size = this.measureText(lineNoCharsSpacer);
  • + *
  • this.stopMeasuring();
  • + *
+ * + * @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) + FirebugChrome.selectedPanelName = panelName; + + this.selectedPanel = panel; + + setClass(panel.tabNode, "fbSelectedTab"); + panel.show(); + panel.initialize(); + } + }, - showInfoTip: function(infoTip, x, y) - { + getPanel: function(panelName) + { + var panel = this.panelMap[panelName]; - }, + return panel; + } - 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; - }, + //************************************************************************************************ + // Button - getDefaultLocation: function() - { - return null; - }, + /** + * options.element + * options.caption + * options.title + * + * options.owner + * options.className + * options.pressedClassName + * + * options.onPress + * options.onUnpress + * options.onClick + * + * @class + * @extends FBL.Controller + * + */ - getObjectLocation: function(object) + FBL.Button = function(options) { - return ""; - }, + options = options || {}; - // 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); - }, + append(this, options); - /* - * 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; + this.state = "unpressed"; + this.display = "unpressed"; - if (show) - tab.setAttribute("highlight", "true"); + if (this.element) + { + this.container = this.element.parentNode; + } else - tab.removeAttribute("highlight"); - }, + { + this.shouldDestroy = true; - getTab: function() - { - var chrome = Firebug.chrome; + this.container = this.owner.getPanel().toolButtonsNode; - var tab = chrome.$("fbPanelBar2").getTab(this.name); - if (!tab) - tab = chrome.$("fbPanelBar1").getTab(this.name); - return tab; - }, + this.element = createElement("a", { + className: this.baseClassName + " " + this.className + " fbHover", + innerHTML: this.caption + }); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Support for Break On Next + if (this.title) + this.element.title = this.title; - /** - * 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) - { - }, + this.container.appendChild(this.element); + } + }; - /** - * 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) + Button.prototype = extend(Controller, + /**@extend FBL.Button.prototype*/ { - return null; - }, + type: "normal", + caption: "caption", + title: null, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + className: "", // custom class + baseClassName: "fbButton", // control class + pressedClassName: "fbBtnPressed", // control pressed class - // xxxpedro contextMenu - onContextMenu: function(event) - { - if (!this.getContextMenuItems) - return; + element: null, + container: null, + owner: null, - cancelEvent(event, true); + state: null, + display: null, + + destroy: function() + { + this.shutdown(); - var target = event.target || event.srcElement; + // only remove if it is a dynamically generated button (not pre-rendered) + if (this.shouldDestroy) + this.container.removeChild(this.element); - var menu = this.getContextMenuItems(this.selection, target); - if (!menu) - return; + this.element = null; + this.container = null; + this.owner = null; + }, - var contextMenu = new Menu( + initialize: function() { - id: "fbPanelContextMenu", + Controller.initialize.apply(this); - items: menu - }); + var element = this.element; - contextMenu.show(event.clientX, event.clientY); + this.addController([element, "mousedown", this.handlePress]); - return true; + if (this.type == "normal") + this.addController( + [element, "mouseup", this.handleUnpress], + [element, "mouseout", this.handleUnpress], + [element, "click", this.handleClick] + ); + }, - /* - // TODO: xxxpedro move code to somewhere. code to get cross-browser - // window to screen coordinates - var box = Firebug.browser.getElementPosition(Firebug.chrome.node); + shutdown: function() + { + Controller.shutdown.apply(this); + }, - var screenY = 0; + restore: function() + { + this.changeState("unpressed"); + }, - // Firefox - if (typeof window.mozInnerScreenY != "undefined") + changeState: function(state) { - screenY = window.mozInnerScreenY; - } - // Chrome - else if (typeof window.innerHeight != "undefined") + this.state = state; + this.changeDisplay(state); + }, + + changeDisplay: function(display) { - screenY = window.outerHeight - window.innerHeight; - } - // IE - else if (typeof window.screenTop != "undefined") + 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) { - screenY = window.screenTop; - } + cancelEvent(event, true); - contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); - /**/ - } + 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; + }, -/** - * MeasureBox - * To get pixels size.width and size.height: - *
  • this.startMeasuring(view);
  • - *
  • var size = this.measureText(lineNoCharsSpacer);
  • - *
  • this.stopMeasuring();
  • - *
- * - * @namespace - */ -Firebug.MeasureBox = -{ - startMeasuring: function(target) - { - if (!this.measureBox) + handleUnpress: function(event) { - this.measureBox = target.ownerDocument.createElement("span"); - this.measureBox.className = "measureBox"; - } + cancelEvent(event, true); - copyTextStyles(target, this.measureBox); - target.ownerDocument.body.appendChild(this.measureBox); - }, + if (this.beforeClick) + this.changeDisplay("unpressed"); - getMeasuringElement: function() - { - return this.measureBox; - }, + return false; + }, - measureText: function(value) - { - this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; - return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; - }, + handleClick: function(event) + { + cancelEvent(event, true); - 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}; - }, + if (this.type == "normal") + { + if (this.onClick) + this.onClick.apply(this.owner); - getBox: function(target) - { - var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); - var box = getBoxFromStyles(style, this.measureBox); - return box; - }, + this.changeState("unpressed"); + } - stopMeasuring: function() - { - this.measureBox.parentNode.removeChild(this.measureBox); - } -}; + this.beforeClick = false; + return false; + } + }); -// ************************************************************************************************ -if (FBL.domplate) Firebug.Rep = domplate( -{ - className: "", - inspectable: true, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - supportsObject: function(object, type) + /** + * @class + * @extends FBL.Button + */ + FBL.IconButton = function() { - return false; - }, + Button.apply(this, arguments); + }; - inspectObject: function(object, context) + IconButton.prototype = extend(Button.prototype, + /**@extend FBL.IconButton.prototype*/ { - Firebug.chrome.select(object); - }, + baseClassName: "fbIconButton", + pressedClassName: "fbIconPressed" + }); - browseObject: function(object, context) - { - }, - persistObject: function(object, context) - { - }, + //************************************************************************************************ + // Menu - getRealObject: function(object, context) - { - return object; - }, + var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", + _command: "$item.command"}; - getTitle: function(object) + 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, { - var label = safeToString(object); + tag: + DIV({"class": "fbMenu fbShadow"}, + DIV({"class": "fbMenuContent fbShadowContent"}, + FOR("item", "$object.items|memberIterator", + TAG("$item.tag", {item: "$item"}) + ) + ) + ), - var re = /\[object (.*?)\]/; - var m = re.exec(label); + itemTag: + A(menuItemProps, + "$item.label" + ), - ///return m ? m[1] : label; + checkBoxTag: + A(extend(menuItemProps, {checked : "$item.checked"}), - // 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; - } - }, + "$item.label" + ), - getTooltip: function(object) - { - return null; - }, + radioButtonTag: + A(extend(menuItemProps, {selected : "$item.selected"}), - getContextMenuItems: function(object, target, context) - { - return []; - }, + "$item.label" + ), - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Convenience for domplates + groupTag: + A(extend(menuItemProps, {child: "$item.child"}), + "$item.label" + ), - STR: function(name) - { - return $STR(name); - }, + shortcutTag: + A(menuItemProps, + "$item.label", + SPAN({"class": "fbMenuShortcutKey"}, + "$item.key" + ) + ), - cropString: function(text) - { - return cropString(text); - }, + separatorTag: + SPAN({"class": "fbMenuSeparator"}), - cropMultipleLines: function(text, limit) - { - return cropMultipleLines(text, limit); - }, + memberIterator: function(items) + { + var result = []; - toLowerCase: function(text) - { - return text ? text.toLowerCase() : text; - }, + for (var i=0, length=items.length; i width || el.scrollHeight > height)) + { + width = el.scrollWidth; + height = el.scrollHeight; + } - this.shutdown(); + return {width: width, height: height}; + }, - if (isFunction(this.onHide)) - this.onHide.apply(this, arguments); - }, + 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; + } - showChildMenu: function(target) - { - var id = target.getAttribute("child"); + return {top:top, left:left}; + }, - var parent = this; - var target = target; - this.showChildTimeout = Firebug.chrome.window.setTimeout(function(){ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Element Methods - //if (!parent.isVisible) return; + 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); + }, - var box = Firebug.chrome.getElementBox(target); + getElementPosition: function(el) + { + var left = 0 + var top = 0; - var childMenuObject = menuMap.hasOwnProperty(id) ? - menuMap[id] : {element: $(id)}; + do + { + left += el.offsetLeft; + top += el.offsetTop; + } + while (el = el.offsetParent); - var childMenu = new Menu(extend(childMenuObject, - { - parentMenu: parent, - parentTarget: target - })); + return {left:left, top:top}; + }, - var offsetLeft = isIE6 ? -1 : -6; // IE6 problem with fixed position - childMenu.show(box.left + box.width + offsetLeft, box.top -6); - setClass(target, "fbMenuGroupSelected"); + getElementBox: function(el) + { + var result = {}; - },350); - }, + if (el.getBoundingClientRect) + { + var rect = el.getBoundingClientRect(); - clearHideTimeout: function() - { - if (this.hideTimeout) - { - Firebug.chrome.window.clearTimeout(this.hideTimeout); - delete this.hideTimeout; - } - }, + // fix IE problem with offset when not in fullscreen mode + var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; - clearShowChildTimeout: function() - { - if(this.showChildTimeout) - { - Firebug.chrome.window.clearTimeout(this.showChildTimeout); - this.showChildTimeout = null; - } - }, + var scroll = this.getWindowScrollPosition(); - handleMouseDown: function(event) - { - cancelEvent(event, true); + 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); - var topParent = this; - while (topParent.parentMenu) - topParent = topParent.parentMenu; + result.top = position.top; + result.left = position.left; + result.height = el.offsetHeight; + result.width = el.offsetWidth; + } - var target = event.target || event.srcElement; + return result; + }, - target = getAncestorByClass(target, "fbMenuOption"); - if(!target || hasClass(target, "fbMenuGroup")) - return false; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Measurement Methods - if (target && !hasClass(target, "fbMenuDisabled")) + getMeasurement: function(el, name) { - var type = target.getAttribute("type"); + var result = {value: 0, unit: "px"}; - if (type == "checkbox") - { - var checked = target.getAttribute("checked"); - var value = target.getAttribute("value"); - var wasChecked = hasClass(target, "fbMenuChecked"); + var cssValue = this.getStyle(el, name); - if (wasChecked) - { - removeClass(target, "fbMenuChecked"); - target.setAttribute("checked", ""); - } - else - { - setClass(target, "fbMenuChecked"); - target.setAttribute("checked", "true"); - } + if (!cssValue) return result; + if (cssValue.toLowerCase() == "auto") return result; - if (isFunction(this.onCheck)) - this.onCheck.call(this, target, value, !wasChecked) - } + var reMeasure = /(\d+\.?\d*)(.*)/; + var m = cssValue.match(reMeasure); - if (type == "radiobutton") + if (m) { - 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"); + result.value = m[1]-0; + result.unit = m[2].toLowerCase(); } - var handler = null; + return result; + }, - // target.command can be a function or a string. - var cmd = target.command; + getMeasurementInPixels: function(el, name) + { + if (!el) return null; - // 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 m = this.getMeasurement(el, name); + var value = m.value; + var unit = m.unit; - var closeMenu = true; + if (unit == "px") + return value; - if (handler) - closeMenu = handler.call(this, target) !== false; + else if (unit == "pt") + return this.pointsToPixels(name, value); - if (closeMenu) - topParent.hide(); - } + if (unit == "em") + return this.emToPixels(el, value); - return false; - }, + else if (unit == "%") + return this.percentToPixels(el, value); + }, - handleWindowMouseDown: function(event) - { - //console.log("handleWindowMouseDown"); + getMeasurementBox1: function(el, name) + { + var sufixes = ["Top", "Left", "Bottom", "Right"]; + var result = []; - var target = event.target || event.srcElement; + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); - target = getAncestorByClass(target, "fbMenu"); + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, - if (!target) + getMeasurementBox: function(el, name) { - removeEvent(Firebug.chrome.document, "mousedown", this.handleWindowMouseDown); - this.hide(); - } - }, + var result = []; + var sufixes = name == "border" ? + ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : + ["Top", "Left", "Bottom", "Right"]; - handleMouseOver: function(event) - { - //console.log("handleMouseOver", this.element.id); + if (isIE) + { + var propName, cssValue; + var autoMargin = null; - this.clearHideTimeout(); - this.clearShowChildTimeout(); + for(var i=0, sufix; sufix=sufixes[i]; i++) + { + propName = name + sufix; - var target = event.target || event.srcElement; + cssValue = el.currentStyle[propName] || el.style[propName]; - target = getAncestorByClass(target, "fbMenuOption"); + if (cssValue == "auto") + { + if (!autoMargin) + autoMargin = this.getCSSAutoMarginBox(el); - if(!target) - return; + result[i] = autoMargin[sufix.toLowerCase()]; + } + else + result[i] = this.getMeasurementInPixels(el, propName); - var childMenu = this.childMenu; - if(childMenu) - { - removeClass(childMenu.parentTarget, "fbMenuGroupSelected"); + } - if (childMenu.parentTarget != target && childMenu.isVisible) + } + else { - childMenu.clearHideTimeout(); - childMenu.hideTimeout = Firebug.chrome.window.setTimeout(function(){ - childMenu.destroy(); - },300); + for(var i=0, sufix; sufix=sufixes[i]; i++) + result[i] = this.getMeasurementInPixels(el, name + sufix); } - } - if(hasClass(target, "fbMenuGroup")) + return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; + }, + + getCSSAutoMarginBox: function(el) { - this.showChildMenu(target); - } - } -}); + 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}; + /**/ -append(Menu, -/**@extend FBL.Menu*/ -{ - register: function(object) - { - menuMap[object.id] = object; - }, + var offsetTop = 0; + if (false && isIEStantandMode) + { + var scrollSize = Firebug.browser.getWindowScrollSize(); + offsetTop = scrollSize.height; + } - check: function(element) - { - setClass(element, "fbMenuChecked"); - element.setAttribute("checked", "true"); - }, + 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;"; - uncheck: function(element) - { - removeClass(element, "fbMenuChecked"); - element.setAttribute("checked", ""); - }, + var clone = el.cloneNode(false); + var text = this.document.createTextNode(" "); + clone.appendChild(text); - disable: function(element) - { - setClass(element, "fbMenuDisabled"); - }, + box.appendChild(clone); - enable: function(element) - { - removeClass(element, "fbMenuDisabled"); - } -}); + this.document.body.appendChild(box); + var marginTop = clone.offsetTop - box.offsetTop - 1; + var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; -//************************************************************************************************ -// Status Bar + var marginLeft = clone.offsetLeft - box.offsetLeft - 1; + var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; -/**@class*/ -function StatusBar(){}; + this.document.body.removeChild(box); -StatusBar.prototype = extend(Controller, { + 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;"; -/* See license.txt for terms of usage */ + div.style.cssText = divStyle; + div.innerHTML = "A"; + el.appendChild(div); -FBL.ns( /**@scope s_context*/ function() { with (FBL) { -// ************************************************************************************************ + var value = div.offsetHeight; + el.removeChild(div); + return value; + } -// ************************************************************************************************ -// Globals + /* + var calibrationBase = 200; + var calibrationValue = computeDirtyFontSize(el, calibrationBase); + var rate = calibrationBase / calibrationValue; + /**/ -var refreshDelay = 300; + // the "dirty technique" fails in some environments, so we're using a static value + // based in some tests. + var rate = 200 / 225; -// 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 value = computeDirtyFontSize(el); -var evalError = "___firebug_evaluation_error___"; -var pixelsPerInch; + return value * rate; + }, -var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; -var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Unit Funtions -// ************************************************************************************************ -// Context + pointsToPixels: function(name, value, returnFloat) + { + var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; -/** @class */ -FBL.Context = function(win) -{ - this.window = win.window; - this.document = win.document; + var result = value * pixelsPerInch[axis] / 72; - this.browser = Env.browser; + return returnFloat ? result : Math.round(result); + }, - // 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"); - } + emToPixels: function(el, value) + { + if (!el) return null; - // 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 }" + - "')"); -}; + var fontSize = this.getFontSizeInPixels(el); -FBL.Context.prototype = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // partial-port of Firebug tabContext.js + return Math.round(value * fontSize); + }, - browser: null, - loaded: true, + exToPixels: function(el, value) + { + if (!el) return null; - setTimeout: function(fn, delay) - { - var win = this.window; + // get ex value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "ex;"; - if (win.setTimeout == this.setTimeout) - throw new Error("setTimeout recursion"); + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); - var timeout = win.setTimeout.apply ? // IE doesn't have apply method on setTimeout - win.setTimeout.apply(win, arguments) : - win.setTimeout(fn, delay); + return value; + }, - if (!this.timeouts) - this.timeouts = {}; + percentToPixels: function(el, value) + { + if (!el) return null; - this.timeouts[timeout] = 1; + // get % value, the dirty way + var div = this.document.createElement("div"); + div.style.cssText = offscreenStyle + "width:"+value + "%;"; - return timeout; - }, + el.appendChild(div); + var value = div.offsetWidth; + el.removeChild(div); - clearTimeout: function(timeout) - { - clearTimeout(timeout); + return value; + }, - if (this.timeouts) - delete this.timeouts[timeout]; - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - setInterval: function(fn, delay) - { - var win = this.window; + 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; + } - 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; - }, + /* See license.txt for terms of usage */ - clearInterval: function(timeout) - { - clearInterval(timeout); + FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { + // ************************************************************************************************ - if (this.intervals) - delete this.intervals[timeout]; - }, + // ************************************************************************************************ + // Globals - invalidatePanels: function() - { - if (!this.invalidPanels) - this.invalidPanels = {}; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Window Options - for (var i = 0; i < arguments.length; ++i) + var WindowDefaultOptions = { - var panelName = arguments[i]; - - // avoid error. need to create a better getPanel() function as explained below - if (!Firebug.chrome || !Firebug.chrome.selectedPanel) - return; + type: "frame", + id: "FirebugUI", + height: 250 + }, - //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; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Instantiated objects - if (panel && !panel.noRefresh) - this.invalidPanels[panelName] = 1; - } + commandLine, - if (this.refreshTimeout) - { - this.clearTimeout(this.refreshTimeout); - delete this.refreshTimeout; - } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Interface Elements Cache - this.refreshTimeout = this.setTimeout(bindFixed(function() - { - var invalids = []; + fbTop, + fbContent, + fbContentStyle, + fbBottom, + fbBtnInspect, - 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; + fbToolbar, - if (panel) - { - if (panel.visible && !panel.editing) - panel.refresh(); - else - panel.needsRefresh = true; + fbPanelBox1, + fbPanelBox1Style, + fbPanelBox2, + fbPanelBox2Style, + fbPanelBar2Box, + fbPanelBar2BoxStyle, - // If the panel is being edited, we'll keep trying to - // refresh it until editing is done - if (panel.editing) - invalids.push(panelName); - } - } + fbHSplitter, + fbVSplitter, + fbVSplitterStyle, - delete this.invalidPanels; - delete this.refreshTimeout; + fbPanel1, + fbPanel1Style, + fbPanel2, + fbPanel2Style, - // Keep looping until every tab is valid - if (invalids.length) - this.invalidatePanels.apply(this, invalids); - }, this), refreshDelay); - }, + fbConsole, + fbConsoleStyle, + fbHTML, + fbCommandLine, + fbLargeCommandLine, + fbLargeCommandButtons, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Evalutation Method + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Cached size values - /** - * 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) - { - // Need to remove line breaks otherwise only the first line will be executed - expr = stripNewLines(expr); + topHeight, + topPartialHeight, - // 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 cmd, - result; + chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, - // if the context is the "window" object, we don't need a closure - if (context == "window") - { - // try first the expression wrapped in parenthesis (so we can capture - // object literal expressions like "{}" and "{some:1,props:2}") - cmd = api ? - "with("+api+"){ ("+expr+") }" : - "(" + expr + ")"; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - result = this.eval(cmd); + lastSelectedPanelName, - // if it results in error, then try it without parenthesis - if (result && result[evalError]) - { - cmd = api ? - "with("+api+"){ "+expr+" }" : - expr; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - result = this.eval(cmd); + focusCommandLineState = 0, + lastFocusedPanelName, - } - } - else - { - // try to execute the command using a "return" statement in the evaluation closure. - cmd = api ? - // with API and context, trying to get the return value - "(function(arguments){ with(" + api + "){ return (" + - expr + - ") } }).call(" + context + ",undefined)" - : - // with context only, trying to get the return value - "(function(arguments){ return (" + - expr + - ") }).call(" +context + ",undefined)"; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - result = this.eval(cmd); + lastHSplitterMouseMove = 0, + onHSplitterMouseMoveBuffer = null, + onHSplitterMouseMoveTimer = null, - // if it results in error, then try it without the "return" statement - if (result && result[evalError]) - { - 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); - } - } + lastVSplitterMouseMove = 0; - if (result && result[evalError]) - { - var msg = result.name ? (result.name + ": ") : ""; - msg += result.message || result; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (errorHandler) - result = errorHandler(msg) - else - result = msg; - } - return result; - }, + // ************************************************************************************************ + // FirebugChrome + /**@namespace*/ + FBL.FirebugChrome = + { + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Window Methods + isOpen: false, + height: 250, + sidePanelWidth: 350, - getWindowSize: function() - { - var width=0, height=0, el; + selectedPanelName: "Console", + selectedHTMLElementId: null, - 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; - } + chromeMap: {}, - return {width: width, height: height}; - }, + htmlSelectionStack: [], + consoleMessageQueue: [], - 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)) + create: function() { - width = el.scrollWidth; - height = el.scrollHeight; - } + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); - // 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; - } + createChromeWindow(); + }, - return {width: width, height: height}; - }, + initialize: function() + { + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); - getWindowScrollPosition: function() - { - var top=0, left=0, el; + if (Env.chrome.type == "frame" || Env.chrome.type == "div") + ChromeMini.create(Env.chrome); - 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; - } + var chrome = Firebug.chrome = new Chrome(Env.chrome); + FirebugChrome.chromeMap[chrome.type] = chrome; - return {top:top, left:left}; - }, + 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(); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Element Methods + //chrome.reattach(frame, chrome); + //TODO: xxxpedro persist synchronize? + chrome.initialize(); + } + }, - getElementFromPoint: function(x, y) - { - if (shouldFixElementFromPoint) + clone: function(FBChrome) { - var scroll = this.getWindowScrollPosition(); - return this.document.elementFromPoint(x + scroll.left, y + scroll.top); + for (var name in FBChrome) + { + var prop = FBChrome[name]; + if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) + { + this[name] = prop; + } + } } - 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}; - }, + // ************************************************************************************************ + // Chrome Window Creation - getElementBox: function(el) + var createChromeWindow = function(options) { - var result = {}; - - if (el.getBoundingClientRect) - { - var rect = el.getBoundingClientRect(); + options = extend(WindowDefaultOptions, options || {}); - // fix IE problem with offset when not in fullscreen mode - var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Locals - var scroll = this.getWindowScrollPosition(); + var chrome = {}, - 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); + context = options.context || Env.browser, - result.top = position.top; - result.left = position.left; - result.height = el.offsetHeight; - result.width = el.offsetWidth; - } + type = chrome.type = Env.Options.enablePersistent ? + "popup" : + options.type, - return result; - }, + isChromeFrame = type == "frame", + useLocalSkin = Env.useLocalSkin, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Measurement Methods + url = useLocalSkin ? + Env.Location.skin : + "about:blank", - getMeasurement: function(el, name) - { - var result = {value: 0, unit: "px"}; + // document.body not available in XML+XSL documents in Firefox + body = context.document.getElementsByTagName("body")[0], - var cssValue = this.getStyle(el, name); + formatNode = function(node) + { + if (!Env.isDebugMode) + { + node.firebugIgnore = true; + } - if (!cssValue) return result; - if (cssValue.toLowerCase() == "auto") return result; + 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 = options.height + "px"; + + // avoid flickering during chrome rendering + if (isFirefox) + node.style.display = "none"; + }, - var reMeasure = /(\d+\.?\d*)(.*)/; - var m = cssValue.match(reMeasure); + 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."); - if (m) - { - result.value = m[1]-0; - result.unit = m[2].toLowerCase(); - } + var node = chrome.node = createGlobalElement("div"), + style = createGlobalElement("style"), - return result; - }, + css = FirebugChrome.Skin.CSS + /* + .replace(/;/g, " !important;") + .replace(/!important\s!important/g, "!important") + .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, - getMeasurementInPixels: function(el, name) - { - if (!el) return null; + // 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;}"; + }/**/ - var m = this.getMeasurement(el, name); - var value = m.value; - var unit = m.unit; + style.type = "text/css"; - if (unit == "px") - return value; + if (style.styleSheet) + style.styleSheet.cssText = rules; + else + style.appendChild(context.document.createTextNode(rules)); - else if (unit == "pt") - return this.pointsToPixels(name, value); + document.getElementsByTagName("head")[0].appendChild(style); - if (unit == "em") - return this.emToPixels(el, value); + node.className = "fbBody"; + node.style.overflow = "hidden"; + node.innerHTML = getChromeDivTemplate(); - else if (unit == "%") - return this.percentToPixels(el, value); - }, + 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); + /**/ + } - getMeasurementBox1: function(el, name) - { - var sufixes = ["Top", "Left", "Bottom", "Right"]; - var result = []; + formatNode(node); - for(var i=0, sufix; sufix=sufixes[i]; i++) - result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); + body.appendChild(node); - return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; - }, + chrome.window = window; + chrome.document = document; + onChromeLoad(chrome); + }; - getMeasurementBox: function(el, name) - { - var result = []; - var sufixes = name == "border" ? - ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : - ["Top", "Left", "Bottom", "Right"]; + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (isIE) + try { - var propName, cssValue; - var autoMargin = null; + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the Chrome as a "div" (windowless mode) + if (type == "div") + { + createChromeDiv(); + return; + } - for(var i=0, sufix; sufix=sufixes[i]; i++) + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // cretate the Chrome as an "iframe" + else if (isChromeFrame) { - propName = name + sufix; + // Create the Chrome Frame + var node = chrome.node = createGlobalElement("iframe"); + node.setAttribute("src", url); + node.setAttribute("frameBorder", "0"); - cssValue = el.currentStyle[propName] || el.style[propName]; + formatNode(node); - if (cssValue == "auto") - { - if (!autoMargin) - autoMargin = this.getCSSAutoMarginBox(el); + 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 = FirebugChrome.height || options.height, + + options = [ + "true,top=", + Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), + ",left=0,height=", + height, + ",width=", + screen.availWidth-10, // Opera opens popup in a new tab if it's too big! + ",resizable" + ].join(""), + + node = chrome.node = context.window.open( + url, + "popup", + options + ); - result[i] = autoMargin[sufix.toLowerCase()]; + if (node) + { + try + { + node.focus(); + } + catch(E) + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } } else - result[i] = this.getMeasurementInPixels(el, propName); - + { + alert("Firebug Error: Firebug popup was blocked."); + return; + } } - } - else - { - for(var i=0, sufix; sufix=sufixes[i]; i++) - result[i] = this.getMeasurementInPixels(el, name + sufix); - } + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Inject the interface HTML if it is not using the local skin - return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; - }, + if (!useLocalSkin) + { + var tpl = getChromeTemplate(!isChromeFrame), + doc = isChromeFrame ? node.contentWindow.document : node.document; - 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}; - /**/ + doc.write(tpl); + doc.close(); + } - 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}; - /**/ + //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Wait the Window to be loaded - var offsetTop = 0; - if (false && isIEStantandMode) - { - var scrollSize = Firebug.browser.getWindowScrollSize(); - offsetTop = scrollSize.height; - } + var win, + + waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, - 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;"; + waitForWindow = function() + { + if ( // Frame loaded... OR + isChromeFrame && (win=node.contentWindow) && + node.contentWindow.document.getElementById("fbCommandLine") || - var clone = el.cloneNode(false); - var text = this.document.createTextNode(" "); - clone.appendChild(text); + // Popup loaded + !isChromeFrame && (win=node.window) && node.document && + node.document.getElementById("fbCommandLine") ) + { + chrome.window = win.window; + chrome.document = win.document; - box.appendChild(clone); + // Prevent getting the wrong chrome height in FF when opening a popup + setTimeout(function(){ + onChromeLoad(chrome); + }, useLocalSkin ? 200 : 0); + } + else + setTimeout(waitForWindow, waitDelay); + }; - this.document.body.appendChild(box); + waitForWindow(); + } + catch(e) + { + var msg = e.message || e; - var marginTop = clone.offsetTop - box.offsetTop - 1; - var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; + 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". - var marginLeft = clone.offsetLeft - box.offsetLeft - 1; - var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; + if (isChromeFrame) + body.removeChild(node); + else if(type == "popup") + node.close(); - this.document.body.removeChild(box); + // Load the GUI in a "windowless mode" + createChromeDiv(); + } + else + { + alert("Firebug Error: Firebug GUI could not be created."); + } + } + }; - return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - getFontSizeInPixels: function(el) + var onChromeLoad = function onChromeLoad(chrome) { - var size = this.getMeasurement(el, "fontSize"); + Env.chrome = chrome; - if (size.unit == "px") return size.value; + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); - // get font size, the dirty way - var computeDirtyFontSize = function(el, calibration) + if (Env.Options.enablePersistent) { - var div = this.document.createElement("div"); - var divStyle = offscreenStyle; - - if (calibration) - divStyle += " font-size:"+calibration+"px;"; + // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode + Env.FirebugChrome = FirebugChrome; - div.style.cssText = divStyle; - div.innerHTML = "A"; - el.appendChild(div); + chrome.window.Firebug = chrome.window.Firebug || {}; + chrome.window.Firebug.SharedEnv = Env; - var value = div.offsetHeight; - el.removeChild(div); - return value; + 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 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 newChrome = new Chrome(chrome); - var value = computeDirtyFontSize(el); + // TODO: xxxpedro sync detach reattach attach + dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); - return value * rate; - }, + if (oldChrome) + oldChrome.close(); + newChrome.reattach(oldChrome, newChrome); + } + } + }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Unit Funtions + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - pointsToPixels: function(name, value, returnFloat) + var getChromeDivTemplate = function() { - var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; - - var result = value * pixelsPerInch[axis] / 72; - - return returnFloat ? result : Math.round(result); - }, + return FirebugChrome.Skin.HTML; + }; - emToPixels: function(el, value) + var getChromeTemplate = function(isPopup) { - if (!el) return null; + var tpl = FirebugChrome.Skin; + var r = [], i = -1; - var fontSize = this.getFontSizeInPixels(el); + r[++i] = ''; + r[++i] = ''; + r[++i] = Firebug.version; - return Math.round(value * fontSize); - }, + /* + r[++i] = ''; + /**/ - exToPixels: function(el, value) - { - if (!el) return null; + r[++i] = ''; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; - // get ex value, the dirty way - var div = this.document.createElement("div"); - div.style.cssText = offscreenStyle + "width:"+value + "ex;"; + return r.join(""); + }; - el.appendChild(div); - var value = div.offsetWidth; - el.removeChild(div); - return value; - }, + // ************************************************************************************************ + // Chrome Class - percentToPixels: function(el, value) + /**@class*/ + var Chrome = function Chrome(chrome) { - if (!el) return null; + var type = chrome.type; + var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; - // get % value, the dirty way - var div = this.document.createElement("div"); - div.style.cssText = offscreenStyle + "width:"+value + "%;"; + 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 - el.appendChild(div); - var value = div.offsetWidth; - el.removeChild(div); - - return value; - }, + FirebugChrome.chromeMap[type] = this; + Firebug.chrome = this; + Env.chrome = chrome.window; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + this.commandLineVisible = false; + this.sidePanelVisible = false; - 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; - } + 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 -/* See license.txt for terms of usage */ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from createChrome function -FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { -// ************************************************************************************************ + node: null, + type: null, -// ************************************************************************************************ -// Globals + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // inherited from Context.prototype -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Window Options + document: null, + window: null, -var WindowDefaultOptions = - { - type: "frame", - id: "FirebugUI", - height: 250 - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // value properties -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Instantiated objects + sidePanelVisible: false, + commandLineVisible: false, + largeCommandLineVisible: false, - commandLine, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // object properties -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Interface Elements Cache + inspectButton: null, - fbTop, - fbContent, - fbContentStyle, - fbBottom, - fbBtnInspect, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - fbToolbar, + create: function() + { + PanelBar.create.call(this); - fbPanelBox1, - fbPanelBox1Style, - fbPanelBox2, - fbPanelBox2Style, - fbPanelBar2Box, - fbPanelBar2BoxStyle, + if (Firebug.Inspector) + this.inspectButton = new Button({ + type: "toggle", + element: $("fbChrome_btInspect"), + owner: Firebug.Inspector, - fbHSplitter, - fbVSplitter, - fbVSplitterStyle, + onPress: Firebug.Inspector.startInspecting, + onUnpress: Firebug.Inspector.stopInspecting + }); + }, - fbPanel1, - fbPanel1Style, - fbPanel2, - fbPanel2Style, + destroy: function() + { + if(Firebug.Inspector) + this.inspectButton.destroy(); - fbConsole, - fbConsoleStyle, - fbHTML, + PanelBar.destroy.call(this); - fbCommandLine, - fbLargeCommandLine, - fbLargeCommandButtons, + this.shutdown(); + }, -//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Cached size values + testMenu: function() + { + var firebugMenu = new Menu( + { + id: "fbFirebugMenu", - topHeight, - topPartialHeight, + 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(); + }, - chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, + toggleChrome: function() + { + Firebug.chrome.toggle(); + }, -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + openPopup: function() + { + Firebug.chrome.toggle(true, true); + }, - lastSelectedPanelName, + toggleInspect: function() + { + Firebug.Inspector.toggleInspect(); + }, -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + focusCommandLine: function() + { + Firebug.chrome.focusCommandLine(); + }, - focusCommandLineState = 0, - lastFocusedPanelName, + visitWebsite: function() + { + this.visit("http://getfirebug.com/lite.html"); + }, -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + visitDiscussionGroup: function() + { + this.visit("http://groups.google.com/group/firebug"); + }, - lastHSplitterMouseMove = 0, - onHSplitterMouseMoveBuffer = null, - onHSplitterMouseMoveTimer = null, + visitIssueTracker: function() + { + this.visit("http://code.google.com/p/fbug/issues/list"); + }, -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + visit: function(url) + { + window.open(url); + } - lastVSplitterMouseMove = 0; + }); -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + /**@private*/ + var firebugOptionsMenu = + { + id: "fbFirebugOptionsMenu", + getItems: function() + { + var cookiesDisabled = !Firebug.saveCookies; -// ************************************************************************************************ -// FirebugChrome + return [ + { + label: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + 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: "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 + } + ]; + }, -/**@namespace*/ -FBL.FirebugChrome = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + onCheck: function(target, value, checked) + { + Firebug.setPref(value, checked); + }, - isOpen: false, - height: 250, - sidePanelWidth: 350, + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); - selectedPanelName: "Console", - selectedHTMLElementId: null, + if (!saveEnabled) this.restorePrefs(); - chromeMap: {}, + this.updateMenu(target); - htmlSelectionStack: [], - consoleMessageQueue: [], + return false; + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + restorePrefs: function(target) + { + Firebug.restorePrefs(); - create: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); - createChromeWindow(); - }, + if (target) + this.updateMenu(target); - initialize: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); + return false; + }, - if (Env.chrome.type == "frame" || Env.chrome.type == "div") - ChromeMini.create(Env.chrome); + updateMenu: function(target) + { + var options = getElementsByClass(target.parentNode, "fbMenuOption"); - var chrome = Firebug.chrome = new Chrome(Env.chrome); - FirebugChrome.chromeMap[chrome.type] = chrome; + var firstOption = options[0]; + var enabled = Firebug.saveCookies; + if (enabled) + Menu.check(firstOption); + else + Menu.uncheck(firstOption); - addGlobalEvent("keydown", onGlobalKeyDown); + if (enabled) + Menu.check(options[0]); + else + Menu.uncheck(options[0]); - 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(); + for (var i = 1, length = options.length; i < length; i++) + { + var option = options[i]; - //chrome.reattach(frame, chrome); - //TODO: xxxpedro persist synchronize? - chrome.initialize(); - } - }, + var value = option.getAttribute("value"); + var pref = Firebug[value]; - clone: function(FBChrome) - { - for (var name in FBChrome) - { - var prop = FBChrome[name]; - if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) - { - this[name] = prop; - } - } - } -}; + if (pref) + Menu.check(option); + else + Menu.uncheck(option); + if (enabled) + Menu.enable(option); + else + Menu.disable(option); + } + } + }; + Menu.register(firebugOptionsMenu); -// ************************************************************************************************ -// Chrome Window Creation + var menu = firebugMenu; -var createChromeWindow = function(options) -{ - options = extend(WindowDefaultOptions, options || {}); + var testMenuClick = function(event) + { + //console.log("testMenuClick"); + cancelEvent(event, true); - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Locals + var target = event.target || event.srcElement; - var chrome = {}, + if (menu.isVisible) + menu.hide(); + else + { + var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position - context = options.context || Env.browser, + chrome = Firebug.chrome, - type = chrome.type = Env.Options.enablePersistent ? - "popup" : - options.type, + box = chrome.getElementBox(target), - isChromeFrame = type == "frame", + offset = chrome.type == "div" ? + chrome.getElementPosition(chrome.node) : + {top: 0, left: 0}; - useLocalSkin = Env.useLocalSkin, + menu.show( + box.left + offsetLeft - offset.left, + box.top + box.height -5 - offset.top + ); + } - url = useLocalSkin ? - Env.Location.skin : - "about:blank", + return false; + }; - // document.body not available in XML+XSL documents in Firefox - body = context.document.getElementsByTagName("body")[0], + var iconButton = new IconButton({ + type: "toggle", + element: $("fbFirebugButton"), - formatNode = function(node) - { - if (!Env.isDebugMode) - { - node.firebugIgnore = true; - } + onClick: testMenuClick + }); - 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 = options.height + "px"; + iconButton.initialize(); - // avoid flickering during chrome rendering - if (isFirefox) - node.style.display = "none"; + //addEvent($("fbToolbarIcon"), "click", testMenuClick); }, - createChromeDiv = function() + initialize: 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;}"; - }/**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + 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"); - style.type = "text/css"; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (Firebug.Console) + Firebug.Console.flush(); - if (style.styleSheet) - style.styleSheet.cssText = rules; - else - style.appendChild(context.document.createTextNode(rules)); + if (Firebug.Trace) + FBTrace.flush(Firebug.Trace); - document.getElementsByTagName("head")[0].appendChild(style); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); - node.className = "fbBody"; - node.style.overflow = "hidden"; - node.innerHTML = getChromeDivTemplate(); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize inherited classes + Controller.initialize.call(this); + PanelBar.initialize.call(this); - 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); - /**/ - } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // create the interface elements cache - formatNode(node); + fbTop = $("fbTop"); + fbContent = $("fbContent"); + fbContentStyle = fbContent.style; + fbBottom = $("fbBottom"); + fbBtnInspect = $("fbBtnInspect"); - body.appendChild(node); + fbToolbar = $("fbToolbar"); - chrome.window = window; - chrome.document = document; - onChromeLoad(chrome); - }; + fbPanelBox1 = $("fbPanelBox1"); + fbPanelBox1Style = fbPanelBox1.style; + fbPanelBox2 = $("fbPanelBox2"); + fbPanelBox2Style = fbPanelBox2.style; + fbPanelBar2Box = $("fbPanelBar2Box"); + fbPanelBar2BoxStyle = fbPanelBar2Box.style; - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + fbHSplitter = $("fbHSplitter"); + fbVSplitter = $("fbVSplitter"); + fbVSplitterStyle = fbVSplitter.style; - try - { - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create the Chrome as a "div" (windowless mode) - if (type == "div") - { - createChromeDiv(); - return; - } + fbPanel1 = $("fbPanel1"); + fbPanel1Style = fbPanel1.style; + fbPanel2 = $("fbPanel2"); + fbPanel2Style = fbPanel2.style; - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // 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"); + fbConsole = $("fbConsole"); + fbConsoleStyle = fbConsole.style; + fbHTML = $("fbHTML"); - formatNode(node); + fbCommandLine = $("fbCommandLine"); + fbLargeCommandLine = $("fbLargeCommandLine"); + fbLargeCommandButtons = $("fbLargeCommandButtons"); - body.appendChild(node); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache + topHeight = fbTop.offsetHeight; + topPartialHeight = fbToolbar.offsetHeight; - // 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 = FirebugChrome.height || options.height, - - options = [ - "true,top=", - Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0), - ",left=0,height=", - height, - ",width=", - screen.availWidth-10, // Opera opens popup in a new tab if it's too big! - ",resizable" - ].join(""), - - node = chrome.node = context.window.open( - url, - "popup", - options - ); + disableTextSelection($("fbToolbar")); + disableTextSelection($("fbPanelBarBox")); + disableTextSelection($("fbPanelBar1")); + disableTextSelection($("fbPanelBar2")); - if (node) + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 + if (isIE6 && Firebug.Selector) { - try - { - node.focus(); - } - catch(E) + // TODO: xxxpedro change to getElementsByClass + var as = $$(".fbHover"); + for (var i=0, a; a=as[i]; i++) { - alert("Firebug Error: Firebug popup was blocked."); - return; + a.setAttribute("href", "javascript:void(0)"); } } - else + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // initialize all panels + /* + var panelMap = Firebug.panelTypes; + for (var i=0, p; p=panelMap[i]; i++) { - alert("Firebug Error: Firebug popup was blocked."); - return; + if (!p.parentPanel) + { + this.addPanel(p.prototype.name); + } } - } + /**/ - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Inject the interface HTML if it is not using the local skin + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + + 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(FirebugChrome.selectedPanelName); + + if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) + Firebug.chrome.focusCommandLine(); + },0); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + //this.draw(); - 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() + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + var onPanelMouseDown = function onPanelMouseDown(event) { - if ( // Frame loaded... OR - isChromeFrame && (win=node.contentWindow) && - node.contentWindow.document.getElementById("fbCommandLine") || + //console.log("onPanelMouseDown", event.target || event.srcElement, event); + + var target = event.target || event.srcElement; - // Popup loaded - !isChromeFrame && (win=node.window) && node.document && - node.document.getElementById("fbCommandLine") ) + if (FBL.isLeftClick(event)) { - chrome.window = win.window; - chrome.document = win.document; + var editable = FBL.getAncestorByClass(target, "editable"); - // Prevent getting the wrong chrome height in FF when opening a popup - setTimeout(function(){ - onChromeLoad(chrome); - }, useLocalSkin ? 200 : 0); + // 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); } - else - setTimeout(waitForWindow, waitDelay); }; - waitForWindow(); - } - catch(e) - { - var msg = e.message || e; + Firebug.getElementPanel = function(element) + { + var panelNode = getAncestorByClass(element, "fbPanel"); + var id = panelNode.id.substr(2); - 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". + var panel = Firebug.chrome.panelMap[id]; - if (isChromeFrame) - body.removeChild(node); - else if(type == "popup") - node.close(); + if (!panel) + { + if (Firebug.chrome.selectedPanel.sidePanelBar) + panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + } - // Load the GUI in a "windowless mode" - createChromeDiv(); - } - else - { - alert("Firebug Error: Firebug GUI could not be created."); - } - } -}; + return panel; + }; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -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; + // TODO: xxxpedro port to Firebug - chrome.window.Firebug = chrome.window.Firebug || {}; - chrome.window.Firebug.SharedEnv = Env; + // 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]; - 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; + for (var i = 0, listener; listener = listeners[i]; i++) + { + var filter = listener.filter || FBL.noKeyModifiers; - var newChrome = new Chrome(chrome); + if (event.keyCode == keyCode && (!filter || filter(event))) + { + listener.listener(); + FBL.cancelEvent(event, true); + return false; + } + } + } + }; - // TODO: xxxpedro sync detach reattach attach - dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); + addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); - if (oldChrome) - oldChrome.close(); + /** + * @name keyCodeListen + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + var keyCode = KeyEvent["DOM_VK_"+key]; - newChrome.reattach(oldChrome, newChrome); - } - } -}; + if (!onKeyCodeListenersMap[keyCode]) + onKeyCodeListenersMap[keyCode] = []; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + onKeyCodeListenersMap[keyCode].push({ + filter: filter, + listener: listener + }); -var getChromeDivTemplate = function() -{ - return FirebugChrome.Skin.HTML; -}; + return keyCode; + }; -var getChromeTemplate = function(isPopup) -{ - var tpl = FirebugChrome.Skin; - var r = [], i = -1; + /** + * @name keyIgnore + * @memberOf FBL.FirebugChrome + */ + Firebug.chrome.keyIgnore = function(keyCode) + { + onKeyCodeListenersMap[keyCode] = null; + delete onKeyCodeListenersMap[keyCode]; + }; - r[++i] = ''; - r[++i] = ''; - r[++i] = Firebug.version; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - /* - r[++i] = ''; - /**/ + /**/ + // move to shutdown + //removeEvent(Firebug.chrome.document, "keydown", listener[0]); - r[++i] = ''; - /**/ - r[++i] = ''; - r[++i] = tpl.HTML; - r[++i] = ''; + /* + Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) + { + if (!filter) + filter = FBL.noKeyModifiers; - return r.join(""); -}; + 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; + } + } -// ************************************************************************************************ -// Chrome Class + addEvent(Firebug.chrome.document, "keydown", fn); -/**@class*/ -var Chrome = function Chrome(chrome) -{ - var type = chrome.type; - var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; + return [fn, capture]; + }; - 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 + Firebug.chrome.keyIgnore = function(listener) + { + removeEvent(Firebug.chrome.document, "keydown", listener[0]); + }; + /**/ - FirebugChrome.chromeMap[type] = this; - Firebug.chrome = this; - Env.chrome = chrome.window; - this.commandLineVisible = false; - this.sidePanelVisible = false; + this.addController( + [fbPanel1, "mousedown", onPanelMouseDown], + [fbPanel2, "mousedown", onPanelMouseDown] + ); + /**/ + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - this.create(); - return this; -}; + // menus can be used without domplate + if (FBL.domplate) + this.testMenu(); + /**/ -// ************************************************************************************************ -// ChromeBase + //test XHR + /* + setTimeout(function(){ -/** - * @namespace - * @extends FBL.Controller - * @extends FBL.PanelBar - **/ -var ChromeBase = {}; -append(ChromeBase, Controller); -append(ChromeBase, PanelBar); -append(ChromeBase, -/**@extend ns-chrome-ChromeBase*/ -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited properties + FBL.Ajax.request({url: "../content/firebug/boot.js"}); + FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited from createChrome function + },1000); + /**/ + }, - node: null, - type: null, + shutdown: function() + { + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited from Context.prototype + if(Firebug.Inspector) + this.inspectButton.shutdown(); - document: null, - window: null, + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ + // ************************************************************************************************ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // value properties + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - sidePanelVisible: false, - commandLineVisible: false, - largeCommandLineVisible: false, + // remove disableTextSelection event handlers + restoreTextSelection($("fbToolbar")); + restoreTextSelection($("fbPanelBarBox")); + restoreTextSelection($("fbPanelBar1")); + restoreTextSelection($("fbPanelBar2")); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // object properties + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // shutdown inherited classes + Controller.shutdown.call(this); + PanelBar.shutdown.call(this); - inspectButton: null, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // 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; - create: function() - { - PanelBar.create.call(this); + fbToolbar = null; - if (Firebug.Inspector) - this.inspectButton = new Button({ - type: "toggle", - element: $("fbChrome_btInspect"), - owner: Firebug.Inspector, + fbPanelBox1 = null; + fbPanelBox1Style = null; + fbPanelBox2 = null; + fbPanelBox2Style = null; + fbPanelBar2Box = null; + fbPanelBar2BoxStyle = null; - onPress: Firebug.Inspector.startInspecting, - onUnpress: Firebug.Inspector.stopInspecting - }); - }, + fbHSplitter = null; + fbVSplitter = null; + fbVSplitterStyle = null; - destroy: function() - { - if(Firebug.Inspector) - this.inspectButton.destroy(); + fbPanel1 = null; + fbPanel1Style = null; + fbPanel2 = null; - PanelBar.destroy.call(this); + fbConsole = null; + fbConsoleStyle = null; + fbHTML = null; - this.shutdown(); - }, + fbCommandLine = null; + fbLargeCommandLine = null; + fbLargeCommandButtons = null; - testMenu: function() - { - var firebugMenu = new Menu( - { - id: "fbFirebugMenu", + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // static values cache - 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" - } - ], + topHeight = null; + topPartialHeight = null; + }, - onHide: function() - { - iconButton.restore(); - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - toggleChrome: function() + toggle: function(forceOpen, popup) + { + if(popup) { - Firebug.chrome.toggle(); - }, - - openPopup: function() + this.detach(); + } + else { - Firebug.chrome.toggle(true, true); - }, + if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) + { + var frame = FirebugChrome.chromeMap.frame; + frame.reattach(); - toggleInspect: function() - { - Firebug.Inspector.toggleInspect(); - }, + FirebugChrome.chromeMap.popup = null; - focusCommandLine: function() - { - Firebug.chrome.focusCommandLine(); - }, + frame.open(); - visitWebsite: function() - { - this.visit("http://getfirebug.com/lite.html"); - }, + return; + } - visitDiscussionGroup: function() - { - this.visit("http://groups.google.com/group/firebug"); - }, + // If the context is a popup, ignores the toggle process + if (Firebug.chrome.type == "popup") return; - visitIssueTracker: function() - { - this.visit("http://code.google.com/p/fbug/issues/list"); - }, + var shouldOpen = forceOpen || !FirebugChrome.isOpen; - visit: function(url) - { - window.open(url); + if(shouldOpen) + this.open(); + else + this.close(); } + }, - }); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - /**@private*/ - var firebugOptionsMenu = + detach: function() { - id: "fbFirebugOptionsMenu", - - getItems: function() + if(!FirebugChrome.chromeMap.popup) { - var cookiesDisabled = !Firebug.saveCookies; + createChromeWindow({type: "popup"}); + } + }, - return [ - { - label: "Save Options in Cookies", - type: "checkbox", - value: "saveCookies", - checked: Firebug.saveCookies, - command: "saveOptions" - }, - "-", - { - 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: "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 - } - ]; - }, + reattach: function(oldChrome, newChrome) + { + Firebug.browser.window.Firebug = Firebug; - onCheck: function(target, value, checked) - { - Firebug.setPref(value, checked); - }, + // chrome synchronization + var newPanelMap = newChrome.panelMap; + var oldPanelMap = oldChrome.panelMap; - saveOptions: function(target) + var panel; + for(var name in newPanelMap) { - var saveEnabled = target.getAttribute("checked"); - - if (!saveEnabled) this.restorePrefs(); + // TODO: xxxpedro innerHTML + panel = newPanelMap[name]; + if (panel.options.innerHTMLSync) + panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; + } - this.updateMenu(target); + Firebug.chrome = newChrome; - return false; - }, + // TODO: xxxpedro sync detach reattach attach + //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); - restorePrefs: function(target) + if (newChrome.type == "popup") + { + newChrome.initialize(); + //dispatch(Firebug.modules, "initialize", []); + } + else { - Firebug.restorePrefs(); + // TODO: xxxpedro only needed in persistent + // should use FirebugChrome.clone, but popup FBChrome + // isn't acessible + FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; + } - if(Firebug.saveCookies) - Firebug.savePrefs(); - else - Firebug.erasePrefs(); + dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); + }, - if (target) - this.updateMenu(target); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - return false; - }, + draw: function() + { + var size = this.getSize(); - updateMenu: function(target) - { - var options = getElementsByClass(target.parentNode, "fbMenuOption"); + // Height related values + var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, - var firstOption = options[0]; - var enabled = Firebug.saveCookies; - if (enabled) - Menu.check(firstOption); - else - Menu.uncheck(firstOption); + y = Math.max(size.height /* chrome height */, topHeight), - if (enabled) - Menu.check(options[0]); - else - Menu.uncheck(options[0]); + heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), - for (var i = 1, length = options.length; i < length; i++) - { - var option = options[i]; + height = heightValue + "px", - var value = option.getAttribute("value"); - var pref = Firebug[value]; + // Width related values + sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, - if (pref) - Menu.check(option); - else - Menu.uncheck(option); + width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; - if (enabled) - Menu.enable(option); - else - Menu.disable(option); - } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // 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"; + }/**/ - Menu.register(firebugOptionsMenu); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // Width related rendering + fbPanelBox1Style.width = width; + fbPanel1Style.width = width; - var menu = firebugMenu; + // SidePanel rendering + if (Firebug.chrome.sidePanelVisible) + { + sideWidthValue = Math.max(sideWidthValue - 6, 0); - var testMenuClick = function(event) - { - //console.log("testMenuClick"); - cancelEvent(event, true); + var sideWidth = sideWidthValue + "px"; - var target = event.target || event.srcElement; + fbPanelBox2Style.width = sideWidth; - if (menu.isVisible) - menu.hide(); - else - { - var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position + fbVSplitterStyle.right = sideWidth; - chrome = Firebug.chrome, + if (Firebug.chrome.largeCommandLineVisible) + { + fbLargeCommandLine = $("fbLargeCommandLine"); - box = chrome.getElementBox(target), + fbLargeCommandLine.style.height = heightValue - 4 + "px"; + fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; - offset = chrome.type == "div" ? - chrome.getElementPosition(chrome.node) : - {top: 0, left: 0}; + fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandButtons.style.width = sideWidth; + } + else + { + fbPanel2Style.height = height; + fbPanel2Style.width = sideWidth; - menu.show( - box.left + offsetLeft - offset.left, - box.top + box.height -5 - offset.top - ); + fbPanelBar2BoxStyle.width = sideWidth; + } } + }, - return false; - }; - - var iconButton = new IconButton({ - type: "toggle", - element: $("fbFirebugButton"), - - onClick: testMenuClick - }); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - iconButton.initialize(); + getSize: function() + { + return this.type == "div" ? + { + height: this.node.offsetHeight, + width: this.node.offsetWidth + } + : + this.getWindowSize(); + }, - //addEvent($("fbToolbarIcon"), "click", testMenuClick); - }, + resize: function() + { + var self = this; - 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"); + // avoid partial resize when maximizing window + setTimeout(function(){ + self.draw(); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (Firebug.Console) - Firebug.Console.flush(); + if (noFixedPosition && (self.type == "frame" || self.type == "div")) + self.fixIEPosition(); + }, 0); + }, - if (Firebug.Trace) - FBTrace.flush(Firebug.Trace); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); + layout: function(panel) + { + if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize inherited classes - Controller.initialize.call(this); - PanelBar.initialize.call(this); + var options = panel.options; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create the interface elements cache + changeCommandLineVisibility(options.hasCommandLine); + changeSidePanelVisibility(panel.hasSidePanel); - fbTop = $("fbTop"); - fbContent = $("fbContent"); - fbContentStyle = fbContent.style; - fbBottom = $("fbBottom"); - fbBtnInspect = $("fbBtnInspect"); + Firebug.chrome.draw(); + }, - fbToolbar = $("fbToolbar"); + showLargeCommandLine: function(hideToggleIcon) + { + var chrome = Firebug.chrome; - fbPanelBox1 = $("fbPanelBox1"); - fbPanelBox1Style = fbPanelBox1.style; - fbPanelBox2 = $("fbPanelBox2"); - fbPanelBox2Style = fbPanelBox2.style; - fbPanelBar2Box = $("fbPanelBar2Box"); - fbPanelBar2BoxStyle = fbPanelBar2Box.style; + if (!chrome.largeCommandLineVisible) + { + chrome.largeCommandLineVisible = true; - fbHSplitter = $("fbHSplitter"); - fbVSplitter = $("fbVSplitter"); - fbVSplitterStyle = fbVSplitter.style; + if (chrome.selectedPanel.options.hasCommandLine) + { + if (Firebug.CommandLine) + Firebug.CommandLine.blur(); - fbPanel1 = $("fbPanel1"); - fbPanel1Style = fbPanel1.style; - fbPanel2 = $("fbPanel2"); - fbPanel2Style = fbPanel2.style; + changeCommandLineVisibility(false); + } - fbConsole = $("fbConsole"); - fbConsoleStyle = fbConsole.style; - fbHTML = $("fbHTML"); + changeSidePanelVisibility(true); - fbCommandLine = $("fbCommandLine"); - fbLargeCommandLine = $("fbLargeCommandLine"); - fbLargeCommandButtons = $("fbLargeCommandButtons"); + fbLargeCommandLine.style.display = "block"; + fbLargeCommandButtons.style.display = "block"; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // static values cache - topHeight = fbTop.offsetHeight; - topPartialHeight = fbToolbar.offsetHeight; + fbPanel2Style.display = "none"; + fbPanelBar2BoxStyle.display = "none"; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + chrome.draw(); - disableTextSelection($("fbToolbar")); - disableTextSelection($("fbPanelBarBox")); - disableTextSelection($("fbPanelBar1")); - disableTextSelection($("fbPanelBar2")); + fbLargeCommandLine.focus(); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // 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)"); + if (Firebug.CommandLine) + Firebug.CommandLine.setMultiLine(true); } - } + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize all panels - /* - var panelMap = Firebug.panelTypes; - for (var i=0, p; p=panelMap[i]; i++) + hideLargeCommandLine: function() { - if (!p.parentPanel) + if (Firebug.chrome.largeCommandLineVisible) { - 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(FirebugChrome.selectedPanelName); + Firebug.chrome.largeCommandLineVisible = false; - if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine) - Firebug.chrome.focusCommandLine(); - },0); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - //this.draw(); + 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(); + } + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - var onPanelMouseDown = function onPanelMouseDown(event) + focusCommandLine: function() { - //console.log("onPanelMouseDown", event.target || event.srcElement, event); + var selectedPanelName = this.selectedPanel.name, panelToSelect; - var target = event.target || event.srcElement; + if (focusCommandLineState == 0 || selectedPanelName != "Console") + { + focusCommandLineState = 0; + lastFocusedPanelName = selectedPanelName; - if (FBL.isLeftClick(event)) + panelToSelect = "Console"; + } + if (focusCommandLineState == 1) { - var editable = FBL.getAncestorByClass(target, "editable"); + panelToSelect = lastFocusedPanelName; + } - // 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 + this.selectPanel(panelToSelect); + + try + { + if (Firebug.CommandLine) { - if (!hasClass(target, "textEditorInner")) - Firebug.Editor.stopEditing(); + if (panelToSelect == "Console") + Firebug.CommandLine.focus(); + else + Firebug.CommandLine.blur(); } } - else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) + catch(e) { - // Prevent auto-scroll when middle-clicking a rep object - FBL.cancelEvent(event); + //TODO: xxxpedro trace error } - }; - Firebug.getElementPanel = function(element) + focusCommandLineState = ++focusCommandLineState % 2; + } + + }); + + // ************************************************************************************************ + // ChromeFrameBase + + /** + * @namespace + * @extends ns-chrome-ChromeBase + */ + var ChromeFrameBase = extend(ChromeBase, + /**@extend ns-chrome-ChromeFrameBase*/ + { + create: function() { - var panelNode = getAncestorByClass(element, "fbPanel"); - var id = panelNode.id.substr(2); + ChromeBase.create.call(this); - var panel = Firebug.chrome.panelMap[id]; + // restore display for the anti-flicker trick + if (isFirefox) + this.node.style.display = "block"; - if (!panel) + if (Env.Options.startInNewWindow) { - if (Firebug.chrome.selectedPanel.sidePanelBar) - panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; + this.close(); + this.toggle(true, true); + return; } - return panel; - }; + if (Env.Options.startOpened) + this.open(); + else + this.close(); + }, + + destroy: function() + { + removeGlobalEvent("keydown", onGlobalKeyDown); + ChromeBase.destroy.call(this); + this.document = null; + delete this.document; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + this.window = null; + delete this.window; - // TODO: xxxpedro port to Firebug + this.node.parentNode.removeChild(this.node); + this.node = null; + delete this.node; + }, - // 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) + initialize: function() { - for (var keyCode in onKeyCodeListenersMap) - { - var listeners = onKeyCodeListenersMap[keyCode]; + //FBTrace.sysout("Frame", "initialize();") + ChromeBase.initialize.call(this); - for (var i = 0, listener; listener = listeners[i]; i++) - { - var filter = listener.filter || FBL.noKeyModifiers; + this.addController( + [Firebug.browser.window, "resize", this.resize], + [$("fbWindow_btClose"), "click", this.close], + [$("fbWindow_btDetach"), "click", this.detach], + [$("fbWindow_btDeactivate"), "click", this.deactivate] + ); - if (event.keyCode == keyCode && (!filter || filter(event))) - { - listener.listener(); - FBL.cancelEvent(event, true); - return false; - } - } + if (!Env.Options.enablePersistent) + this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); } - }; - addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); + fbVSplitter.onmousedown = onVSplitterMouseDown; + fbHSplitter.onmousedown = onHSplitterMouseDown; - /** - * @name keyCodeListen - * @memberOf FBL.FirebugChrome - */ - Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) - { - var keyCode = KeyEvent["DOM_VK_"+key]; + this.isInitialized = true; + }, - if (!onKeyCodeListenersMap[keyCode]) - onKeyCodeListenersMap[keyCode] = []; + shutdown: function() + { + fbVSplitter.onmousedown = null; + fbHSplitter.onmousedown = null; - onKeyCodeListenersMap[keyCode].push({ - filter: filter, - listener: listener - }); + ChromeBase.shutdown.apply(this); - return keyCode; - }; + this.isInitialized = false; + }, - /** - * @name keyIgnore - * @memberOf FBL.FirebugChrome - */ - Firebug.chrome.keyIgnore = function(keyCode) + reattach: function() { - onKeyCodeListenersMap[keyCode] = null; - delete onKeyCodeListenersMap[keyCode]; - }; + var frame = FirebugChrome.chromeMap.frame; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); + }, - /**/ - // move to shutdown - //removeEvent(Firebug.chrome.document, "keydown", listener[0]); + open: function() + { + if (!FirebugChrome.isOpen) + { + FirebugChrome.isOpen = true; + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,1"); - /* - Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) - { - if (!filter) - filter = FBL.noKeyModifiers; + var node = this.node; - var keyCode = KeyEvent["DOM_VK_"+key]; + node.style.visibility = "hidden"; // Avoid flickering - var fn = function fn(event) - { - if (event.keyCode == keyCode && (!filter || filter(event))) + if (Firebug.showIconWhenHidden) { - listener(); - FBL.cancelEvent(event, true); - return false; + if (ChromeMini.isInitialized) + { + ChromeMini.shutdown(); + } + } - } + else + node.style.display = "block"; - addEvent(Firebug.chrome.document, "keydown", fn); + var main = $("fbChrome"); - return [fn, capture]; - }; + // IE6 throws an error when setting this property! why? + //main.style.display = "table"; + main.style.display = ""; - Firebug.chrome.keyIgnore = function(listener) - { - removeEvent(Firebug.chrome.document, "keydown", listener[0]); - }; - /**/ + var self = this; + /// TODO: xxxpedro FOUC + node.style.visibility = "visible"; + setTimeout(function(){ + ///node.style.visibility = "visible"; + //dispatch(Firebug.modules, "initialize", []); + self.initialize(); - this.addController( - [fbPanel1, "mousedown", onPanelMouseDown], - [fbPanel2, "mousedown", onPanelMouseDown] - ); -/**/ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (noFixedPosition) + self.fixIEPosition(); + self.draw(); - // menus can be used without domplate - if (FBL.domplate) - this.testMenu(); - /**/ + }, 10); + } + }, - //test XHR - /* - setTimeout(function(){ + close: function() + { + if (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } - FBL.Ajax.request({url: "../content/firebug/boot.js"}); - FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); + FirebugChrome.isOpen = false; - },1000); - /**/ - }, + if (Env.isChromeExtension) + localStorage.setItem("Firebug", "1,0"); - shutdown: function() - { - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ + var node = this.node; - if(Firebug.Inspector) - this.inspectButton.shutdown(); + 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(); - // remove disableTextSelection event handlers - restoreTextSelection($("fbToolbar")); - restoreTextSelection($("fbPanelBarBox")); - restoreTextSelection($("fbPanelBar1")); - restoreTextSelection($("fbPanelBar2")); + node.style.visibility = "visible"; + } + else + node.style.display = "none"; + } + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // shutdown inherited classes - Controller.shutdown.call(this); - PanelBar.shutdown.call(this); + 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"); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Remove the interface elements cache (this must happen after calling - // the shutdown method of all dependent components to avoid errors) + // 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(); + } + }, - fbTop = null; - fbContent = null; - fbContentStyle = null; - fbBottom = null; - fbBtnInspect = null; + 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; - fbToolbar = null; + var size = Firebug.browser.getWindowSize(); + var scroll = Firebug.browser.getWindowScrollPosition(); + var maxHeight = size.height; + var height = this.node.offsetHeight; - fbPanelBox1 = null; - fbPanelBox1Style = null; - fbPanelBox2 = null; - fbPanelBox2Style = null; - fbPanelBar2Box = null; - fbPanelBar2BoxStyle = null; + var bodyStyle = doc.body.currentStyle; - fbHSplitter = null; - fbVSplitter = null; - fbVSplitterStyle = null; + this.node.style.top = maxHeight - height + scroll.top + "px"; - fbPanel1 = null; - fbPanel1Style = null; - fbPanel2 = null; + if ((this.type == "frame" || this.type == "div") && + (bodyStyle.marginLeft || bodyStyle.marginRight)) + { + this.node.style.width = size.width + "px"; + } - fbConsole = null; - fbConsoleStyle = null; - fbHTML = null; + if (fbVSplitterStyle) + fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; - fbCommandLine = null; - fbLargeCommandLine = null; - fbLargeCommandButtons = null; + this.draw(); + } - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // static values cache + }); - topHeight = null; - topPartialHeight = null; - }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // ************************************************************************************************ + // ChromeMini - toggle: function(forceOpen, popup) + /** + * @namespace + * @extends FBL.Controller + */ + var ChromeMini = extend(Controller, + /**@extend ns-chrome-ChromeMini*/ { - if(popup) + create: function(chrome) { - this.detach(); - } - else + append(this, chrome); + this.type = "mini"; + }, + + initialize: function() { - if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) - { - var frame = FirebugChrome.chromeMap.frame; - frame.reattach(); + Controller.initialize.apply(this); - FirebugChrome.chromeMap.popup = null; + var doc = FirebugChrome.chromeMap.frame.document; - frame.open(); + var mini = $("fbMiniChrome", doc); + mini.style.display = "block"; - return; - } + var miniIcon = $("fbMiniIcon", doc); + var width = miniIcon.offsetWidth + 10; + miniIcon.title = "Open " + Firebug.version; - // If the context is a popup, ignores the toggle process - if (Firebug.chrome.type == "popup") return; + var errors = $("fbMiniErrors", doc); + if (errors.offsetWidth) + width += errors.offsetWidth + 10; - var shouldOpen = forceOpen || !FirebugChrome.isOpen; + var node = this.node; + node.style.height = "27px"; + node.style.width = width + "px"; + node.style.left = ""; + node.style.right = 0; - if(shouldOpen) - this.open(); + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "true"); + this.document.body.style.backgroundColor = "transparent"; + } else - this.close(); - } - }, + node.style.background = "transparent"; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + if (noFixedPosition) + this.fixIEPosition(); - detach: function() - { - if(!FirebugChrome.chromeMap.popup) - { - createChromeWindow({type: "popup"}); - } - }, + this.addController( + [$("fbMiniIcon", doc), "click", onMiniIconClick] + ); - reattach: function(oldChrome, newChrome) - { - Firebug.browser.window.Firebug = Firebug; + if (noFixedPosition) + { + this.addController( + [Firebug.browser.window, "scroll", this.fixIEPosition] + ); + } - // chrome synchronization - var newPanelMap = newChrome.panelMap; - var oldPanelMap = oldChrome.panelMap; + this.isInitialized = true; + }, - var panel; - for(var name in newPanelMap) + shutdown: function() { - // TODO: xxxpedro innerHTML - panel = newPanelMap[name]; - if (panel.options.innerHTMLSync) - panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; - } + var node = this.node; + node.style.height = FirebugChrome.height + "px"; + node.style.width = "100%"; + node.style.left = 0; + node.style.right = ""; - Firebug.chrome = newChrome; + if (this.node.nodeName.toLowerCase() == "iframe") + { + node.setAttribute("allowTransparency", "false"); + this.document.body.style.backgroundColor = "#fff"; + } + else + node.style.background = "#fff"; - // TODO: xxxpedro sync detach reattach attach - //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); + if (noFixedPosition) + this.fixIEPosition(); - 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 - FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name; - } + var doc = FirebugChrome.chromeMap.frame.document; - dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); - }, + var mini = $("fbMiniChrome", doc); + mini.style.display = "none"; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Controller.shutdown.apply(this); - draw: function() - { - var size = this.getSize(); + this.isInitialized = false; + }, - // Height related values - var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, + draw: function() + { - y = Math.max(size.height /* chrome height */, topHeight), + }, - heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), + fixIEPosition: ChromeFrameBase.fixIEPosition - height = heightValue + "px", + }); - // Width related values - sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0, - width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; + // ************************************************************************************************ + // ChromePopupBase - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Height related rendering - fbPanelBox1Style.height = height; - fbPanel1Style.height = height; + /** + * @namespace + * @extends ns-chrome-ChromeBase + */ + var ChromePopupBase = extend(ChromeBase, + /**@extend ns-chrome-ChromePopupBase*/ + { - if (isIE || isOpera) + initialize: function() { - // 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"; - }/**/ + setClass(this.document.body, "FirebugPopup"); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Width related rendering - fbPanelBox1Style.width = width; - fbPanel1Style.width = width; + ChromeBase.initialize.call(this); - // SidePanel rendering - if (Firebug.chrome.sidePanelVisible) - { - sideWidthValue = Math.max(sideWidthValue - 6, 0); + this.addController( + [Firebug.chrome.window, "resize", this.resize], + [Firebug.chrome.window, "unload", this.destroy] + ); - var sideWidth = sideWidthValue + "px"; + 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] + ); - fbPanelBox2Style.width = sideWidth; + fbVSplitter.onmousedown = onVSplitterMouseDown; + }, - fbVSplitterStyle.right = sideWidth; + destroy: function() + { + // TODO: xxxpedro sync detach reattach attach + var frame = FirebugChrome.chromeMap.frame; - if (Firebug.chrome.largeCommandLineVisible) + if(frame) { - fbLargeCommandLine = $("fbLargeCommandLine"); + dispatch(frame.panelMap, "detach", [this, frame]); - fbLargeCommandLine.style.height = heightValue - 4 + "px"; - fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; - - fbLargeCommandButtons = $("fbLargeCommandButtons"); - fbLargeCommandButtons.style.width = sideWidth; + frame.reattach(this, frame); } - else - { - fbPanel2Style.height = height; - fbPanel2Style.width = sideWidth; - fbPanelBar2BoxStyle.width = sideWidth; + if (Env.Options.enablePersistent) + { + removeEvent(Firebug.browser.window, "unload", this.persist); } - } - }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + ChromeBase.destroy.apply(this); - getSize: function() - { - return this.type == "div" ? - { - height: this.node.offsetHeight, - width: this.node.offsetWidth - } - : - this.getWindowSize(); - }, + FirebugChrome.chromeMap.popup = null; - resize: function() - { - var self = this; + this.node.close(); + }, - // avoid partial resize when maximizing window - setTimeout(function(){ - self.draw(); + persist: function() + { + persistTimeStart = new Date().getTime(); - if (noFixedPosition && (self.type == "frame" || self.type == "div")) - self.fixIEPosition(); - }, 0); - }, + removeEvent(Firebug.browser.window, "unload", this.persist); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + Firebug.Inspector.destroy(); + Firebug.browser.window.FirebugOldBrowser = true; - layout: function(panel) - { - if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); + var persistTimeStart = new Date().getTime(); - var options = panel.options; + var waitMainWindow = function() + { + var doc, head; - changeCommandLineVisibility(options.hasCommandLine); - changeSidePanelVisibility(panel.hasSidePanel); + try + { + if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && + doc.documentElement && (head = doc.documentElement.firstChild)*/) + { - Firebug.chrome.draw(); - }, + try + { + // exposes the FBL to the global namespace when in debug mode + if (Env.isDebugMode) + { + window.FBL = FBL; + } - showLargeCommandLine: function(hideToggleIcon) - { - var chrome = Firebug.chrome; + window.Firebug = Firebug; + window.opener.Firebug = Firebug; - if (!chrome.largeCommandLineVisible) - { - chrome.largeCommandLineVisible = true; + Env.browser = window.opener; + Firebug.browser = Firebug.context = new Context(Env.browser); - if (chrome.selectedPanel.options.hasCommandLine) - { - if (Firebug.CommandLine) - Firebug.CommandLine.blur(); + registerConsole(); - changeCommandLineVisibility(false); - } + // 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; - changeSidePanelVisibility(true); + var chrome = Firebug.chrome; + addEvent(Firebug.browser.window, "unload", chrome.persist); - fbLargeCommandLine.style.display = "block"; - fbLargeCommandButtons.style.display = "block"; + FBL.cacheDocument(); + Firebug.Inspector.create(); - fbPanel2Style.display = "none"; - fbPanelBar2BoxStyle.display = "none"; + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); - chrome.draw(); + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + catch(pE) + { + alert("persist error: " + (pE.message || pE)); + } - fbLargeCommandLine.focus(); + } + else + { + window.setTimeout(waitMainWindow, 0); + } - if (Firebug.CommandLine) - Firebug.CommandLine.setMultiLine(true); - } - }, + } catch (E) { + window.close(); + } + }; - hideLargeCommandLine: function() - { - if (Firebug.chrome.largeCommandLineVisible) - { - Firebug.chrome.largeCommandLineVisible = false; + waitMainWindow(); + }, - if (Firebug.CommandLine) - Firebug.CommandLine.setMultiLine(false); + close: function() + { + this.destroy(); + } - fbLargeCommandLine.blur(); + }); - fbPanel2Style.display = "block"; - fbPanelBar2BoxStyle.display = "block"; - fbLargeCommandLine.style.display = "none"; - fbLargeCommandButtons.style.display = "none"; + //************************************************************************************************ + // UI helpers - changeSidePanelVisibility(false); + var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) + { + var last = Firebug.chrome.commandLineVisible; + var visible = Firebug.chrome.commandLineVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; - if (Firebug.chrome.selectedPanel.options.hasCommandLine) - changeCommandLineVisibility(true); + if (visible != last) + { + if (visible) + { + fbBottom.className = ""; - Firebug.chrome.draw(); + if (Firebug.CommandLine) + Firebug.CommandLine.activate(); + } + else + { + if (Firebug.CommandLine) + Firebug.CommandLine.deactivate(); + fbBottom.className = "hide"; + } } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + }; - focusCommandLine: function() + var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) { - var selectedPanelName = this.selectedPanel.name, panelToSelect; - - if (focusCommandLineState == 0 || selectedPanelName != "Console") - { - focusCommandLineState = 0; - lastFocusedPanelName = selectedPanelName; + var last = Firebug.chrome.sidePanelVisible; + Firebug.chrome.sidePanelVisible = + typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; - panelToSelect = "Console"; - } - if (focusCommandLineState == 1) + if (Firebug.chrome.sidePanelVisible != last) { - panelToSelect = lastFocusedPanelName; + fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; + fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; } + }; - this.selectPanel(panelToSelect); - try + // ************************************************************************************************ + // 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)) { - if (Firebug.CommandLine) + 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) { - if (panelToSelect == "Console") - Firebug.CommandLine.focus(); - else - Firebug.CommandLine.blur(); + Firebug.GoogleChrome.dispatch("FB_enableIcon"); } } - catch(e) + else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) + { + Firebug.Inspector.toggleInspect(); + cancelEvent(event, true); + } + else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) { - //TODO: xxxpedro trace error + Firebug.chrome.focusCommandLine(); + cancelEvent(event, true); } + }; - focusCommandLineState = ++focusCommandLineState % 2; - } + var onMiniIconClick = function onMiniIconClick(event) + { + Firebug.chrome.toggle(false, event.ctrlKey); + cancelEvent(event, true); + }; -}); -// ************************************************************************************************ -// ChromeFrameBase + // ************************************************************************************************ + // Horizontal Splitter Handling -/** - * @namespace - * @extends ns-chrome-ChromeBase - */ -var ChromeFrameBase = extend(ChromeBase, -/**@extend ns-chrome-ChromeFrameBase*/ -{ - create: function() + var onHSplitterMouseDown = function onHSplitterMouseDown(event) { - ChromeBase.create.call(this); + addGlobalEvent("mousemove", onHSplitterMouseMove); + addGlobalEvent("mouseup", onHSplitterMouseUp); - // restore display for the anti-flicker trick - if (isFirefox) - this.node.style.display = "block"; + if (isIE) + addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); - if (Env.Options.startInNewWindow) - { - this.close(); - this.toggle(true, true); - return; - } + fbHSplitter.className = "fbOnMovingHSplitter"; - if (Env.Options.startOpened) - this.open(); - else - this.close(); - }, + return false; + }; - destroy: function() + var onHSplitterMouseMove = function onHSplitterMouseMove(event) { - removeGlobalEvent("keydown", onGlobalKeyDown); - - ChromeBase.destroy.call(this); + cancelEvent(event, true); - this.document = null; - delete this.document; + var clientY = event.clientY; + var win = isIE + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument && event.target.ownerDocument.defaultView; - this.window = null; - delete this.window; + if (!win) + return; - this.node.parentNode.removeChild(this.node); - this.node = null; - delete this.node; - }, + if (win != win.parent) + { + var frameElement = win.frameElement; + if (frameElement) + { + var framePos = Firebug.browser.getElementPosition(frameElement).top; + clientY += framePos; - initialize: function() - { - //FBTrace.sysout("Frame", "initialize();") - ChromeBase.initialize.call(this); + if (frameElement.style.position != "fixed") + clientY -= Firebug.browser.getWindowScrollPosition().top; + } + } - this.addController( - [Firebug.browser.window, "resize", this.resize], - [$("fbWindow_btClose"), "click", this.close], - [$("fbWindow_btDetach"), "click", this.detach], - [$("fbWindow_btDeactivate"), "click", this.deactivate] - ); + 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 + );/**/ - if (!Env.Options.enablePersistent) - this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); + onHSplitterMouseMoveBuffer = clientY; // buffer - if (noFixedPosition) + if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping { - this.addController( - [Firebug.browser.window, "scroll", this.fixIEPosition] - ); + lastHSplitterMouseMove = new Date().getTime(); + handleHSplitterMouseMove(); } + else + if (!onHSplitterMouseMoveTimer) + onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); - fbVSplitter.onmousedown = onVSplitterMouseDown; - fbHSplitter.onmousedown = onHSplitterMouseDown; - - this.isInitialized = true; - }, + // 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; + }; - shutdown: function() + var handleHSplitterMouseMove = function() { - fbVSplitter.onmousedown = null; - fbHSplitter.onmousedown = null; - - ChromeBase.shutdown.apply(this); + if (onHSplitterMouseMoveTimer) + { + clearTimeout(onHSplitterMouseMoveTimer); + onHSplitterMouseMoveTimer = null; + } - this.isInitialized = false; - }, + var clientY = onHSplitterMouseMoveBuffer; - reattach: function() - { - var frame = FirebugChrome.chromeMap.frame; + var windowSize = Firebug.browser.getWindowSize(); + var scrollSize = Firebug.browser.getWindowScrollSize(); - ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); - }, + // 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; - open: function() - { - if (!FirebugChrome.isOpen) - { - FirebugChrome.isOpen = true; + var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; - if (Env.isChromeExtension) - localStorage.setItem("Firebug", "1,1"); + //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; + var height = windowSize.height; - var node = this.node; + // 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); - node.style.visibility = "hidden"; // Avoid flickering + FirebugChrome.height = chromeHeight; + chromeNode.style.height = chromeHeight + "px"; - if (Firebug.showIconWhenHidden) - { - if (ChromeMini.isInitialized) - { - ChromeMini.shutdown(); - } + if (noFixedPosition) + Firebug.chrome.fixIEPosition(); - } - else - node.style.display = "block"; + Firebug.chrome.draw(); + }; - var main = $("fbChrome"); + var onHSplitterMouseUp = function onHSplitterMouseUp(event) + { + removeGlobalEvent("mousemove", onHSplitterMouseMove); + removeGlobalEvent("mouseup", onHSplitterMouseUp); - // IE6 throws an error when setting this property! why? - //main.style.display = "table"; - main.style.display = ""; + if (isIE) + removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); - var self = this; - /// TODO: xxxpedro FOUC - node.style.visibility = "visible"; - setTimeout(function(){ - ///node.style.visibility = "visible"; + fbHSplitter.className = ""; - //dispatch(Firebug.modules, "initialize", []); - self.initialize(); + Firebug.chrome.draw(); - if (noFixedPosition) - self.fixIEPosition(); + // avoid text selection in IE when returning to the document + // after the mouse leaves the document during the resizing + return false; + }; - self.draw(); - }, 10); - } - }, + // ************************************************************************************************ + // Vertical Splitter Handling - close: function() + var onVSplitterMouseDown = function onVSplitterMouseDown(event) { - if (FirebugChrome.isOpen || !this.isInitialized) - { - if (this.isInitialized) - { - //dispatch(Firebug.modules, "shutdown", []); - this.shutdown(); - } - - FirebugChrome.isOpen = false; - - if (Env.isChromeExtension) - localStorage.setItem("Firebug", "1,0"); + addGlobalEvent("mousemove", onVSplitterMouseMove); + addGlobalEvent("mouseup", onVSplitterMouseUp); - var node = this.node; + return false; + }; - if (Firebug.showIconWhenHidden) + 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 { - node.style.visibility = "hidden"; // Avoid flickering + var clientX = event.clientX; + var win = document.all + ? event.srcElement.ownerDocument.parentWindow + : event.target.ownerDocument.defaultView; - // TODO: xxxpedro - persist IE fixed? - var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); - main.style.display = "none"; + if (win != win.parent) + clientX += win.frameElement ? win.frameElement.offsetLeft : 0; - ChromeMini.initialize(); + var size = Firebug.chrome.getSize(); + var x = Math.max(size.width - clientX + 3, 6); - node.style.visibility = "visible"; + FirebugChrome.sidePanelWidth = x; + Firebug.chrome.draw(); } - 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(); + lastVSplitterMouseMove = new Date().getTime(); } - }, - - 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"; + cancelEvent(event, true); + return false; + }; - if ((this.type == "frame" || this.type == "div") && - (bodyStyle.marginLeft || bodyStyle.marginRight)) - { - this.node.style.width = size.width + "px"; - } + var onVSplitterMouseUp = function onVSplitterMouseUp(event) + { + removeGlobalEvent("mousemove", onVSplitterMouseMove); + removeGlobalEvent("mouseup", onVSplitterMouseUp); - if (fbVSplitterStyle) - fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px"; + Firebug.chrome.draw(); + }; - this.draw(); - } -}); + // ************************************************************************************************ + }}); + /* See license.txt for terms of usage */ -// ************************************************************************************************ -// ChromeMini + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ -/** - * @namespace - * @extends FBL.Controller - */ -var ChromeMini = extend(Controller, -/**@extend ns-chrome-ChromeMini*/ -{ - create: function(chrome) + Firebug.Lite = { - 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"; + /* See license.txt for terms of usage */ - var miniIcon = $("fbMiniIcon", doc); - var width = miniIcon.offsetWidth + 10; - miniIcon.title = "Open " + Firebug.version; + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ - 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; + Firebug.Lite.Browser = function(window) + { + this.contentWindow = window; + this.contentDocument = window.document; + this.currentURI = + { + spec: window.location.href + }; + }; - if (this.node.nodeName.toLowerCase() == "iframe") + Firebug.Lite.Browser.prototype = + { + toString: function() { - node.setAttribute("allowTransparency", "true"); - this.document.body.style.backgroundColor = "transparent"; + return "Firebug.Lite.Browser"; } - 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; - }, + /* See license.txt for terms of usage */ - shutdown: function() + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ + + Firebug.Lite.Cache = { - var node = this.node; - node.style.height = FirebugChrome.height + "px"; - node.style.width = "100%"; - node.style.left = 0; - node.style.right = ""; + ID: "firebug-" + new Date().getTime() + }; - 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(); + /** + * 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 doc = FirebugChrome.chromeMap.frame.document; + var CID = Firebug.Lite.Cache.ID; - var mini = $("fbMiniChrome", doc); - mini.style.display = "none"; + // better detection + var supportsDeleteExpando = !document.all; - Controller.shutdown.apply(this); + var cacheFunction = function(element) + { + return cacheAPI.set(element); + }; - this.isInitialized = false; - }, + var cacheAPI = + { + get: function(key) + { + return map.hasOwnProperty(key) ? + map[key] : + null; + }, - draw: function() - { + set: function(element) + { + var id = getValidatedKey(element); - }, + if (!id) + { + id = ++cacheUID; + element[CID] = id; + } - fixIEPosition: ChromeFrameBase.fixIEPosition + if (!map.hasOwnProperty(id)) + { + map[id] = element; + data[id] = {}; + } -}); + return id; + }, + unset: function(element) + { + var id = getValidatedKey(element); -// ************************************************************************************************ -// ChromePopupBase + if (!id) return; -/** - * @namespace - * @extends ns-chrome-ChromeBase - */ -var ChromePopupBase = extend(ChromeBase, -/**@extend ns-chrome-ChromePopupBase*/ -{ + if (supportsDeleteExpando) + { + delete element[CID]; + } + else if (element.removeAttribute) + { + element.removeAttribute(CID); + } - initialize: function() - { - setClass(this.document.body, "FirebugPopup"); + delete map[id]; + delete data[id]; - ChromeBase.initialize.call(this); + }, - this.addController( - [Firebug.chrome.window, "resize", this.resize], - [Firebug.chrome.window, "unload", this.destroy] - ); + key: function(element) + { + return getValidatedKey(element); + }, - 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] - ); + has: function(element) + { + var id = getValidatedKey(element); + return id && map.hasOwnProperty(id); + }, - fbVSplitter.onmousedown = onVSplitterMouseDown; - }, + each: function(callback) + { + for (var key in map) + { + if (map.hasOwnProperty(key)) + { + callback(key, map[key]); + } + } + }, - destroy: function() - { - // TODO: xxxpedro sync detach reattach attach - var frame = FirebugChrome.chromeMap.frame; + data: function(element, name, value) + { + // set data + if (value) + { + if (!name) return null; - if(frame) - { - dispatch(frame.panelMap, "detach", [this, frame]); + var id = cacheAPI.set(element); - frame.reattach(this, frame); - } + return data[id][name] = value; + } + // get data + else + { + var id = cacheAPI.key(element); - if (Env.Options.enablePersistent) - { - removeEvent(Firebug.browser.window, "unload", this.persist); - } + return data.hasOwnProperty(id) && data[id].hasOwnProperty(name) ? + data[id][name] : + null; + } + }, - ChromeBase.destroy.apply(this); + clear: function() + { + for (var id in map) + { + var element = map[id]; + cacheAPI.unset(element); + } + } + }; - FirebugChrome.chromeMap.popup = null; + var getValidatedKey = function(element) + { + var id = element[CID]; - this.node.close(); - }, + // 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); - persist: function() - { - persistTimeStart = new Date().getTime(); + id = null; + } - removeEvent(Firebug.browser.window, "unload", this.persist); + return id; + } - Firebug.Inspector.destroy(); - Firebug.browser.window.FirebugOldBrowser = true; + FBL.append(cacheFunction, cacheAPI); - var persistTimeStart = new Date().getTime(); + return cacheFunction; + }; - var waitMainWindow = function() - { - var doc, head; + // ************************************************************************************************ - try - { - if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && - doc.documentElement && (head = doc.documentElement.firstChild)*/) - { + // TODO: xxxpedro : check if we need really this on FBL scope + Firebug.Lite.Cache.StyleSheet = createCache(); + Firebug.Lite.Cache.Element = createCache(); - try - { - // exposes the FBL to the global namespace when in debug mode - if (Env.isDebugMode) - { - window.FBL = FBL; - } + // TODO: xxxpedro + Firebug.Lite.Cache.Event = createCache(); - window.Firebug = Firebug; - window.opener.Firebug = Firebug; - Env.browser = window.opener; - Firebug.browser = Firebug.context = new Context(Env.browser); + // ************************************************************************************************ + }}); - 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; + /* See license.txt for terms of usage */ - var chrome = Firebug.chrome; - addEvent(Firebug.browser.window, "unload", chrome.persist); + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ - FBL.cacheDocument(); - Firebug.Inspector.create(); - var htmlPanel = chrome.getPanel("HTML"); - htmlPanel.createUI(); + Firebug.Lite.Proxy = + { + // jsonp callbacks + _callbacks: {}, - Firebug.Console.logFormatted( - ["Firebug could not capture console calls during " + - persistDelay + "ms"], - Firebug.context, - "info" - ); - } - catch(pE) - { - alert("persist error: " + (pE.message || pE)); - } + /** + * 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 - } - else - { - window.setTimeout(waitMainWindow, 0); - } + return isLocalResource ? fetchResource(url) : fetchProxyResource(url); + }, - } catch (E) { - window.close(); - } - }; + /** + * Load a resource using JSONP technique. + */ + loadJSONP: function(url, callback) + { + var script = createGlobalElement("script"), + doc = Firebug.context.document, - waitMainWindow(); - }, + uid = "" + new Date().getTime(), + callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, - close: function() - { - this.destroy(); - } + 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]; + }; -//************************************************************************************************ -// UI helpers + script.src = jsonpURL; -var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) -{ - var last = Firebug.chrome.commandLineVisible; - var visible = Firebug.chrome.commandLineVisible = - typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; + if (doc.documentElement) + doc.documentElement.appendChild(script); + }, - if (visible != last) - { - if (visible) + /** + * Load a resource using YQL (not reliable). + */ + YQL: function(url, callback) { - fbBottom.className = ""; + var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + + encodeURIComponent(url) + "%22&format=xml"; - if (Firebug.CommandLine) - Firebug.CommandLine.activate(); - } - else - { - if (Firebug.CommandLine) - Firebug.CommandLine.deactivate(); + this.loadJSONP(yql, function(data) + { + var source = data.results[0]; + + // clean up YQL bogus elements + var match = /\s+

([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; - fbBottom.className = "hide"; + console.log(source); + }); } - } -}; + }; -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) + var fetchResource = function(url) { - fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; - fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; - } -}; + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + return xhr.responseText; + }; -// ************************************************************************************************ -// 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)) + var fetchProxyResource = function(url) { - Firebug.chrome.toggle(false, ctrlKey); - cancelEvent(event, true); + var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); + var response = fetchResource(proxyURL); - // TODO: xxxpedro replace with a better solution. we're doing this - // to allow reactivating with the F12 key after being deactivated - if (Env.isChromeExtension) + try { - Firebug.GoogleChrome.dispatch("FB_enableIcon"); + var data = eval("(" + response + ")"); + } + catch(E) + { + return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; } - } - 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 + return data ? data.contents : ""; + }; -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; -}; + /* See license.txt for terms of usage */ -var onHSplitterMouseMove = function onHSplitterMouseMove(event) -{ - cancelEvent(event, true); + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ - var clientY = event.clientY; - var win = isIE - ? event.srcElement.ownerDocument.parentWindow - : event.target.ownerDocument && event.target.ownerDocument.defaultView; + Firebug.Lite.Script = function(window) + { + this.fileName = null; + this.isValid = null; + this.baseLineNumber = null; + this.lineExtent = null; + this.tag = null; - if (!win) - return; + this.functionName = null; + this.functionSource = null; + }; - if (win != win.parent) + Firebug.Lite.Script.prototype = { - var frameElement = win.frameElement; - if (frameElement) - { - var framePos = Firebug.browser.getElementPosition(frameElement).top; - clientY += framePos; + isLineExecutable: function(){}, + pcToLine: function(){}, + lineToPc: function(){}, - if (frameElement.style.position != "fixed") - clientY -= Firebug.browser.getWindowScrollPosition().top; + toString: function() + { + return "Firebug.Lite.Script"; } - } + }; + + // ************************************************************************************************ + }}); - 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 + /* See license.txt for terms of usage */ - if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping + FBL.ns(function() { with (FBL) { + // ************************************************************************************************ + + Firebug.Lite.Style = { - 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(); + /* See license.txt for terms of usage */ - // 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; + FBL.ns( /**@scope s_selector*/ function() { with (FBL) { + // ************************************************************************************************ - var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; + /* + * 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 height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; - var height = windowSize.height; + 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; + }); - // 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); + /** + * @name Firebug.Selector + * @namespace + */ - FirebugChrome.height = chromeHeight; - chromeNode.style.height = chromeHeight + "px"; + /** + * @exports Sizzle as Firebug.Selector + */ + var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; - if (noFixedPosition) - Firebug.chrome.fixIEPosition(); + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } - Firebug.chrome.draw(); -}; + if ( !selector || typeof selector !== "string" ) { + return results; + } -var onHSplitterMouseUp = function onHSplitterMouseUp(event) -{ - removeGlobalEvent("mousemove", onHSplitterMouseMove); - removeGlobalEvent("mouseup", onHSplitterMouseUp); + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; - if (isIE) - removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; - fbHSplitter.className = ""; + parts.push( m[1] ); - Firebug.chrome.draw(); + if ( m[2] ) { + extra = m[3]; + break; + } + } - // avoid text selection in IE when returning to the document - // after the mouse leaves the document during the resizing - return false; -}; + 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(); -// ************************************************************************************************ -// Vertical Splitter Handling + if ( Expr.relative[ selector ] ) + selector += parts.shift(); -var onVSplitterMouseDown = function onVSplitterMouseDown(event) -{ - addGlobalEvent("mousemove", onVSplitterMouseMove); - addGlobalEvent("mouseup", onVSplitterMouseUp); + 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; + } - return false; -}; + while ( parts.length ) { + var cur = parts.pop(), pop = cur; -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 ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } - if (win != win.parent) - clientX += win.frameElement ? win.frameElement.offsetLeft : 0; + if ( pop == null ) { + pop = context; + } - var size = Firebug.chrome.getSize(); - var x = Math.max(size.width - clientX + 3, 6); + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } - FirebugChrome.sidePanelWidth = x; - Firebug.chrome.draw(); + if ( !checkSet ) { + checkSet = set; } - lastVSplitterMouseMove = new Date().getTime(); - } + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } - cancelEvent(event, true); - return false; -}; + 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 ); + } -var onVSplitterMouseUp = function onVSplitterMouseUp(event) -{ - removeGlobalEvent("mousemove", onVSplitterMouseMove); - removeGlobalEvent("mouseup", onVSplitterMouseUp); + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } - Firebug.chrome.draw(); -}; + 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); + } + } + } + } -/* See license.txt for terms of usage */ + return results; + }; -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ + Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); + }; -Firebug.Lite = -{ -}; + 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; -/* See license.txt for terms of usage */ + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ + 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("*"); + } -Firebug.Lite.Browser = function(window) -{ - this.contentWindow = window; - this.contentDocument = window.document; - this.currentURI = - { - spec: window.location.href + return {set: set, expr: expr}; }; -}; -Firebug.Lite.Browser.prototype = -{ - toString: function() - { - return "Firebug.Lite.Browser"; - } -}; + 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; + } + } -/* See license.txt for terms of usage */ + 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; + } + } + } + } -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } -Firebug.Lite.Cache = -{ - ID: "firebug-" + new Date().getTime() -}; + expr = expr.replace( Expr.match[ type ], "" ); -// ************************************************************************************************ + if ( !anyFound ) { + return []; + } -/** - * 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 = {}; + break; + } + } + } - var CID = Firebug.Lite.Cache.ID; + // Improper expression + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } - // better detection - var supportsDeleteExpando = !document.all; + old = expr; + } - var cacheFunction = function(element) - { - return cacheAPI.set(element); + return curLoop; }; - var cacheAPI = - { - get: function(key) - { - return map.hasOwnProperty(key) ? - map[key] : - null; + /**#@+ @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(); + } - set: function(element) - { - var id = getValidatedKey(element); + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - if (!id) - { - id = ++cacheUID; - element[CID] = id; - } + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } - if (!map.hasOwnProperty(id)) - { - map[id] = element; - data[id] = {}; - } + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; - return id; - }, + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); - unset: function(element) - { - var id = getValidatedKey(element); + 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 (!id) return; + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; - if (supportsDeleteExpando) - { - delete element[CID]; - } - else if (element.removeAttribute) - { - element.removeAttribute(CID); - } + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } - delete map[id]; - delete data[id]; + 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; + } - key: function(element) - { - return getValidatedKey(element); + 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]); - has: function(element) - { - var id = getValidatedKey(element); - return id && map.hasOwnProperty(id); + 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, "") + " "; - each: function(callback) - { - for (var key in map) - { - if (map.hasOwnProperty(key)) - { - callback(key, map[key]); + 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; + } + } - data: function(element, name, value) - { - // set data - if (value) - { - if (!name) return null; + 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]; - var id = cacheAPI.set(element); + if ( first == 1 && last == 0 ) { + return true; + } - return data[id][name] = value; - } - // get data - else - { - var id = cacheAPI.key(element); + var doneName = match[0], + parent = elem.parentNode; - return data.hasOwnProperty(id) && data[id].hasOwnProperty(name) ? - data[id][name] : - null; - } - }, + 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; + } - clear: function() - { - for (var id in map) - { - var element = map[id]; - cacheAPI.unset(element); + 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 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; - } + var origPOS = Expr.match.POS; - return id; + 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 ); } - 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 makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + if ( results ) { + results.push.apply( results, array ); + return results; + } -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, + return array; + }; - uid = "" + new Date().getTime(), - callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, + // 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 ); - jsonpURL = url.indexOf("?") != -1 ? - url + "&" + callbackName : - url + "?" + callbackName; + // Provide a fallback method if it does not work + } catch(e){ + makeArray = function(array, results) { + var ret = results || []; - Firebug.Lite.Proxy._callbacks[uid] = function(data) - { - if (callback) - callback(data); + 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] ); + } + } + } - script.parentNode.removeChild(script); - delete Firebug.Lite.Proxy._callbacks[uid]; + return ret; }; - - 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 = /\s+

([\s\S]+)<\/p>\s+<\/body>$/.exec(source); - if (match) - source = match[1]; - - console.log(source); - }); } -}; -// ************************************************************************************************ + var sortOrder; -var fetchResource = function(url) -{ - var xhr = FBL.Ajax.getXHRObject(); - xhr.open("get", url, false); - xhr.send(); + if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } - return xhr.responseText; -}; + 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 fetchProxyResource = function(url) -{ - var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); - var response = fetchResource(proxyURL); + 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; + } - try - { - var data = eval("(" + response + ")"); - } - catch(E) - { - return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; + 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; + }; } - return data ? data.contents : ""; -}; - - -// ************************************************************************************************ -}}); - + // 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 = ""; + + // 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 : []; + } + }; -/* See license.txt for terms of usage */ + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ + root.removeChild( form ); + root = form = null; // release memory in IE + })(); -Firebug.Lite.Script = function(window) -{ - this.fileName = null; - this.isValid = null; - this.baseLineNumber = null; - this.lineExtent = null; - this.tag = null; + (function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") - this.functionName = null; - this.functionSource = null; -}; + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); -Firebug.Lite.Script.prototype = -{ - isLineExecutable: function(){}, - pcToLine: function(){}, - lineToPc: function(){}, + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); - toString: function() - { - return "Firebug.Lite.Script"; - } -}; + // 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; + } -/* See license.txt for terms of usage */ + return results; + }; + } -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } -Firebug.Lite.Style = -{ -}; + div = null; // release memory in IE + })(); -// ************************************************************************************************ -}}); + if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } -/* See license.txt for terms of usage */ + Sizzle = function(query, context, extra, seed){ + context = context || document; -FBL.ns( /**@scope s_selector*/ function() { with (FBL) { -// ************************************************************************************************ + // 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){} + } -/* - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ + return oldSizzle(query, context, extra, seed); + }; -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } -// 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; -}); + div = null; // release memory in IE + })(); -/** - * @name Firebug.Selector - * @namespace - */ + if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
"; -/** - * @exports Sizzle as Firebug.Selector - */ -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; - if ( !selector || typeof selector !== "string" ) { - return results; - } + if ( div.getElementsByClassName("e").length === 1 ) + return; - var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), - soFar = selector; + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; - // Reset the position of the chunker regexp (start from head) - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; + div = null; // release memory in IE + })(); - parts.push( m[1] ); + 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; - if ( m[2] ) { - extra = m[3]; - break; - } - } + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + 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 ); + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } - while ( parts.length ) { - selector = parts.shift(); + if ( elem.nodeName === cur ) { + match = elem; + break; + } - if ( Expr.relative[ selector ] ) - selector += parts.shift(); + elem = elem[dir]; + } - set = posProcess( selector, set ); + checkSet[i] = match; } } - } 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; + 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; - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } - if ( !checkSet ) { - checkSet = set; - } + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } - if ( !checkSet ) { - throw "Syntax error, unrecognized expression: " + (cur || selector); - } + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } - 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] ); + elem = elem[dir]; } + + checkSet[i] = match; } } - } else { - makeArray( checkSet, results ); } - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } + var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; + } : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); + }; - return results; -}; + var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; + }; -Sizzle.uniqueSort = function(results){ - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); + var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } + // 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, "" ); } - } - return results; -}; + selector = Expr.relative[selector] ? selector + "*" : selector; -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 = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; + return Sizzle.filter( later, tmpSet ); + }; - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); + // EXPOSE - 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; - } - } - } - } + Firebug.Selector = Sizzle; - 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]); + // 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 - 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 = []; - } + /* See license.txt for terms of usage */ - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + ( /** @scope s_domplate */ function() { - 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; + /** @class */ + FBL.DomplateTag = function DomplateTag(tagName) + { + this.tagName = tagName; + }; - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } + /** + * @class + * @extends FBL.DomplateTag + */ + FBL.DomplateEmbed = function DomplateEmbed() + { + }; - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } + /** + * @class + * @extends FBL.DomplateTag + */ + FBL.DomplateLoop = function DomplateLoop() + { + }; - expr = expr.replace( Expr.match[ type ], "" ); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if ( !anyFound ) { - return []; - } + var DomplateTag = FBL.DomplateTag; + var DomplateEmbed = FBL.DomplateEmbed; + var DomplateLoop = FBL.DomplateLoop; - break; - } - } - } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Improper expression - if ( expr == old ) { - if ( anyFound == null ) { - throw "Syntax error, unrecognized expression: " + expr; - } else { - break; - } - } + var womb = null; - old = expr; - } + FBL.domplate = function() + { + var lastSubject; + for (var i = 0; i < arguments.length; ++i) + lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; - 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"); + for (var name in lastSubject) + { + var val = lastSubject[name]; + if (isTag(val)) + val.tag.subject = lastSubject; } - }, - relative: { - "+": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; - if ( isTag && !isXML ) { - part = part.toUpperCase(); - } + return lastSubject; + }; - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + var domplate = FBL.domplate; - checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? - elem || false : - elem === part; - } - } + FBL.domplate.context = function(context, fn) + { + var lastContext = domplate.lastContext; + domplate.topContext = context; + fn.apply(context); + domplate.topContext = lastContext; + }; - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string"; + FBL.TAG = function() + { + var embed = new DomplateEmbed(); + return embed.merge(arguments); + }; - if ( isPartStr && !/\W/.test(part) ) { - part = isXML ? part : part.toUpperCase(); + FBL.FOR = function() + { + var loop = new DomplateLoop(); + return loop.merge(arguments); + }; - 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; - } - } + FBL.DomplateTag.prototype = + { + merge: function(args, oldTag) + { + if (oldTag) + this.tagName = oldTag.tagName; - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; + 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) : []; - if ( !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } + var attrs = args.length ? args[0] : null; + var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; + this.children = []; - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } + if (domplate.topContext) + this.context = domplate.topContext; - 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]); + if (args.length) + parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } + if (hasAttrs) + this.parseAttrs(attrs); - return ret.length === 0 ? null : ret; - } + return creator(this, DomplateTag); }, - 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; - } + parseAttrs: function(args) + { + for (var name in args) + { + var val = parseValue(args[name]); + readPartNames(val, this.vars); - 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; - } + 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; } } - - 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; - } + compile: function() + { + if (this.renderMarkup) + return; - // TODO: Move to normal caching system - match[0] = done++; + this.compileMarkup(); + this.compileDOM(); - return match; + //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); }, - 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; - } + compileMarkup: function() + { + this.markupArgs = []; + var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; - 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; - } - } + this.generateMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); - 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]; + var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; + for (var i = 0; i < info.argIndex; ++i) + fnBlock.push(', s', i); + fnBlock.push(') {'); - if ( first == 1 && last == 0 ) { - return true; - } + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (__context__) {'); + fnBlock.push('with (__in__) {'); - var doneName = match[0], - parent = elem.parentNode; + fnBlock.push.apply(fnBlock, blocks); - 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; - } + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); - 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 ); - } - } - } -}; + fnBlock.push('}})'); -var origPOS = Expr.match.POS; + function __link__(tag, code, outputs, args) + { + if (!tag || !tag.tag) + return; -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 ); -} + tag.tag.compile(); -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); + 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); - if ( results ) { - results.push.apply( results, array ); - return results; - } + outputs.push(tag); + outputs.push(tagOutputs); + } - return array; -}; + function __escape__(value) + { + function replaceChars(ch) + { + switch (ch) + { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + return "?"; + }; + return String(value).replace(/[<>&"']/g, replaceChars); + } -// 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 ); + function __loop__(iter, outputs, fn) + { + var iterOuts = []; + outputs.push(iterOuts); -// Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; + if (iter instanceof Array) + iter = new ArrayIterator(iter); - 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] ); + try + { + while (1) + { + var value = iter.next(); + var itemOuts = [0,0]; + iterOuts.push(itemOuts); + fn.apply(this, [value, itemOuts]); + } } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); + catch (exc) + { + if (exc != StopIteration) + throw exc; } } - } - return ret; - }; -} + var js = fnBlock.join(""); + var r = null; + eval(js); + this.renderMarkup = r; + }, -var sortOrder; + getVarNames: function(args) + { + if (this.vars) + args.push.apply(args, this.vars); -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; + 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]); + } + } + } } - 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; - } + generateMarkup: function(topBlock, topOuts, blocks, info) + { + topBlock.push(',"<', this.tagName, '"'); - 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; + for (var name in this.attrs) + { + if (name != "class") + { + var val = this.attrs[name]; + topBlock.push(', " ', name, '=\\""'); + addParts(val, ',', topBlock, info, true); + topBlock.push(', "\\""'); + } } - 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 = ""; - - // 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 : []; + if (this.listeners) + { + for (var i = 0; i < this.listeners.length; i += 2) + readPartNames(this.listeners[i+1], topOuts); } - }; - - 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 = []; + if (this.props) + { + for (var name in this.props) + readPartNames(this.props[name], topOuts); + } - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } + 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(',">"'); - results = tmp; + this.generateChildMarkup(topBlock, topOuts, blocks, info); + topBlock.push(',""'); + }, + + 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); } + }, - return results; - }; - } + 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); + }, - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - } + addLocals: function(blocks) + { + var varNames = []; + this.getVarNames(varNames); - div = null; // release memory in IE -})(); + var map = {}; + for (var i = 0; i < varNames.length; ++i) + { + var name = varNames[i]; + if ( map.hasOwnProperty(name) ) + continue; -if ( document.querySelectorAll ) (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

"; + map[name] = 1; + var names = name.split("."); + blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); + } + }, - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } + 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); - Sizzle = function(query, context, extra, seed){ - context = context || document; + var fnBlock = ['r=(function (root, context, o']; - // 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){} - } + for (var i = 0; i < path.staticIndex; ++i) + fnBlock.push(', ', 's'+i); - return oldSizzle(query, context, extra, seed); - }; + for (var i = 0; i < path.renderIndex; ++i) + fnBlock.push(', ', 'd'+i); - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } + 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;'); - div = null; // release memory in IE -})(); + if (this.subject) + fnBlock.push('with (this) {'); + if (this.context) + fnBlock.push('with (context) {'); -if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ - var div = document.createElement("div"); - div.innerHTML = "
"; + fnBlock.push(blocks.join("")); - // Opera can't find a second classname (in 9.6) - if ( div.getElementsByClassName("e").length === 0 ) - return; + if (this.subject) + fnBlock.push('}'); + if (this.context) + fnBlock.push('}'); - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; + fnBlock.push('return ', nodeCount, ';'); + fnBlock.push('})'); - if ( div.getElementsByClassName("e").length === 1 ) - return; + function __bind__(object, fn) + { + return function(event) { return fn.apply(object, [event]); }; + } - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; + function __link__(node, tag, args) + { + if (!tag || !tag.tag) + return; - div = null; // release memory in IE -})(); + tag.tag.compile(); -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; + 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); } - elem = elem[dir]; - var match = false; - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; + 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; + } - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } + function __path__(parent, offset) + { + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); + var root = parent; - if ( elem.nodeName === cur ) { - match = elem; - break; + 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]; } - elem = elem[dir]; + //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); + return parent; } - 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; - } + var js = fnBlock.join(""); + //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); + var r = null; + eval(js); + this.renderDOM = r; + }, - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } + generateDOM: function(path, blocks, args) + { + if (this.listeners || this.props) + this.generateNodePath(path, blocks); - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } + 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);'); } - - 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; + 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, ';'); + } + } - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } + this.generateChildDOM(path, blocks, args); + return 1; + }, - return Sizzle.filter( later, tmpSet ); -}; + 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(");"); + }, -// EXPOSE + 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(); + } + }; -Firebug.Selector = Sizzle; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -/**#@-*/ + 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); + } -// 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 + return creator(this, DomplateEmbed); + }, + getVarNames: function(names) + { + if (this.value instanceof Parts) + names.push(this.value.parts[0].name); -/* See license.txt for terms of usage */ + if (this.vars) + names.push.apply(names, this.vars); + }, -( /** @scope s_domplate */ function() { + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + blocks.push('__link__('); + addParts(this.value, '', blocks, info); + blocks.push(', __code__, __out__, {'); -/** @class */ -FBL.DomplateTag = function DomplateTag(tagName) -{ - this.tagName = tagName; -}; + var lastName = null; + for (var name in this.attrs) + { + if (lastName) + blocks.push(','); + lastName = name; -/** - * @class - * @extends FBL.DomplateTag - */ -FBL.DomplateEmbed = function DomplateEmbed() -{ -}; + var val = this.attrs[name]; + blocks.push('"', name, '":'); + addParts(val, '', blocks, info); + } -/** - * @class - * @extends FBL.DomplateTag - */ -FBL.DomplateLoop = function DomplateLoop() -{ -}; + blocks.push('});'); + //this.generateChildMarkup(topBlock, topOuts, blocks, info); + }, -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + generateDOM: function(path, blocks, args) + { + var embedName = 'e'+path.embedIndex++; -var DomplateTag = FBL.DomplateTag; -var DomplateEmbed = FBL.DomplateEmbed; -var DomplateLoop = FBL.DomplateLoop; + this.generateNodePath(path, blocks); -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + var valueName = 'd' + path.renderIndex++; + var argsName = 'd' + path.renderIndex++; + blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); -var womb = null; + return embedName; + } + }); -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) + FBL.DomplateLoop.prototype = copyObject(FBL.DomplateTag.prototype, + /** @lends FBL.DomplateLoop.prototype */ { - var val = lastSubject[name]; - if (isTag(val)) - val.tag.subject = lastSubject; - } - - return lastSubject; -}; + merge: function(args, oldTag) + { + this.varName = oldTag ? oldTag.varName : args[0]; + this.iter = oldTag ? oldTag.iter : parseValue(args[1]); + this.vars = []; -var domplate = FBL.domplate; + this.children = oldTag ? copyArray(oldTag.children) : []; -FBL.domplate.context = function(context, fn) -{ - var lastContext = domplate.lastContext; - domplate.topContext = context; - fn.apply(context); - domplate.topContext = lastContext; -}; + var offset = Math.min(args.length, 2); + parseChildren(args, offset, this.vars, this.children); -FBL.TAG = function() -{ - var embed = new DomplateEmbed(); - return embed.merge(arguments); -}; + return creator(this, DomplateLoop); + }, -FBL.FOR = function() -{ - var loop = new DomplateLoop(); - return loop.merge(arguments); -}; + getVarNames: function(names) + { + if (this.iter instanceof Parts) + names.push(this.iter.parts[0].name); -FBL.DomplateTag.prototype = -{ - merge: function(args, oldTag) - { - if (oldTag) - this.tagName = oldTag.tagName; + DomplateTag.prototype.getVarNames.apply(this, [names]); + }, - 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) : []; + generateMarkup: function(topBlock, topOuts, blocks, info) + { + this.addCode(topBlock, topOuts, blocks); - var attrs = args.length ? args[0] : null; - var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); + var iterName; + if (this.iter instanceof Parts) + { + var part = this.iter.parts[0]; + iterName = part.name; - this.children = []; + if (part.format) + { + for (var i = 0; i < part.format.length; ++i) + iterName = part.format[i] + "(" + iterName + ")"; + } + } + else + iterName = this.iter; - if (domplate.topContext) - this.context = domplate.topContext; + blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); + this.generateChildMarkup(topBlock, topOuts, blocks, info); + this.addCode(topBlock, topOuts, blocks); + blocks.push('}]);'); + }, - if (args.length) - parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); + generateDOM: function(path, blocks, args) + { + var iterName = 'd'+path.renderIndex++; + var counterName = 'i'+path.loopIndex; + var loopName = 'l'+path.loopIndex++; - if (hasAttrs) - this.parseAttrs(attrs); + if (!path.length) + path.push(-1, 0); - return creator(this, DomplateTag); - }, + var preIndex = path.renderIndex; + path.renderIndex = 0; - parseAttrs: function(args) - { - for (var name in args) - { - var val = parseValue(args[name]); - readPartNames(val, this.vars); + var nodeCount = 0; - 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 subBlocks = []; + var basePath = path[path.length-1]; + for (var i = 0; i < this.children.length; ++i) { - 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; + path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; + + var child = this.children[i]; + if (isTag(child)) + nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); else - this.attrs[name] = val; + nodeCount += '+1'; } - } - }, - compile: function() - { - if (this.renderMarkup) - return; + path[path.length-1] = basePath+'+'+loopName; - this.compileMarkup(); - this.compileDOM(); + 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('}]);'); - //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); - }, + path.renderIndex = preIndex; + + return loopName; + } + }); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - compileMarkup: function() + /** @class */ + function Variable(name, format) { - this.markupArgs = []; - var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; + this.name = name; + this.format = format; + } - this.generateMarkup(topBlock, topOuts, blocks, info); - this.addCode(topBlock, topOuts, blocks); + /** @class */ + function Parts(parts) + { + this.parts = parts; + } - 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__) {'); + function parseParts(str) + { + var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; + var index = 0; + var parts = []; - fnBlock.push.apply(fnBlock, blocks); + var m; + while (m = re.exec(str)) + { + var pre = str.substr(index, (re.lastIndex-m[0].length)-index); + if (pre) + parts.push(pre); - if (this.subject) - fnBlock.push('}'); - if (this.context) - fnBlock.push('}'); + var expr = m[1].split("|"); + parts.push(new Variable(expr[0], expr.slice(1))); + index = re.lastIndex; + } - fnBlock.push('}})'); + if (!index) + return str; - function __link__(tag, code, outputs, args) - { - if (!tag || !tag.tag) - return; + var post = str.substr(index); + if (post) + parts.push(post); - tag.tag.compile(); + return new Parts(parts); + } - 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); + function parseValue(val) + { + return typeof(val) == 'string' ? parseParts(val) : val; + } - outputs.push(tag); - outputs.push(tagOutputs); + 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 __escape__(value) + function readPartNames(val, vars) + { + if (val instanceof Parts) { - function replaceChars(ch) + for (var i = 0; i < val.parts.length; ++i) { - switch (ch) - { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "'": - return "'"; - case '"': - return """; - } - return "?"; - }; - return String(value).replace(/[<>&"']/g, replaceChars); + var part = val.parts[i]; + if (part instanceof Variable) + vars.push(part.name); + } } + } - function __loop__(iter, outputs, fn) + function generateArg(val, path, args) + { + if (val instanceof Parts) { - var iterOuts = []; - outputs.push(iterOuts); - - if (iter instanceof Array) - iter = new ArrayIterator(iter); - - try + var vals = []; + for (var i = 0; i < val.parts.length; ++i) { - while (1) + var part = val.parts[i]; + if (part instanceof Variable) { - var value = iter.next(); - var itemOuts = [0,0]; - iterOuts.push(itemOuts); - fn.apply(this, [value, itemOuts]); + 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, '\\"')+'"'); } - catch (exc) - { - if (exc != StopIteration) - throw exc; - } - } - var js = fnBlock.join(""); - var r = null; - eval(js); - this.renderMarkup = r; - }, + return vals.join('+'); + } + else + { + args.push(val); + return 's' + path.staticIndex++; + } + } - getVarNames: function(args) + function addParts(val, delim, block, info, escapeIt) { - if (this.vars) - args.push.apply(args, this.vars); - - for (var i = 0; i < this.children.length; ++i) + var vals = []; + if (val instanceof Parts) { - var child = this.children[i]; - if (isTag(child)) - child.tag.getVarNames(args); - else if (child instanceof Parts) + for (var i = 0; i < val.parts.length; ++i) { - for (var i = 0; i < child.parts.length; ++i) + var part = val.parts[i]; + if (part instanceof Variable) { - if (child.parts[i] instanceof Variable) + var partName = part.name; + if (part.format) { - var name = child.parts[i].name; - var names = name.split("."); - args.push(names[0]); + 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 + '"'); - generateMarkup: function(topBlock, topOuts, blocks, info) + var parts = vals.join(delim); + if (parts) + block.push(delim, parts); + } + + function isTag(obj) { - topBlock.push(',"<', this.tagName, '"'); + return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; + } - for (var name in this.attrs) - { - if (name != "class") - { - var val = this.attrs[name]; - topBlock.push(', " ', name, '=\\""'); - addParts(val, ',', topBlock, info, true); - topBlock.push(', "\\""'); - } - } + 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);"); - if (this.listeners) - { - for (var i = 0; i < this.listeners.length; i += 2) - readPartNames(this.listeners[i+1], topOuts); - } + fn.tag = tag; + fn.cons = cons; + extend(fn, Renderer); - if (this.props) - { - for (var name in this.props) - readPartNames(this.props[name], topOuts); - } + return fn; + } - 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(',""'); - }, + function copyArray(oldArray) + { + var ary = []; + if (oldArray) + for (var i = 0; i < oldArray.length; ++i) + ary.push(oldArray[i]); + return ary; + } - generateChildMarkup: function(topBlock, topOuts, blocks, info) + function copyObject(l, r) { - 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); - } - }, + var m = {}; + extend(m, l); + extend(m, r); + return m; + } - addCode: function(topBlock, topOuts, blocks) + function extend(l, r) { - 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); - }, + 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); + } + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - addLocals: function(blocks) + /** @class */ + function ArrayIterator(array) { - var varNames = []; - this.getVarNames(varNames); + var index = -1; - var map = {}; - for (var i = 0; i < varNames.length; ++i) + this.next = function() { - var name = varNames[i]; - if ( map.hasOwnProperty(name) ) - continue; + if (++index >= array.length) + throw StopIteration; - map[name] = 1; - var names = name.split("."); - blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); - } - }, + return array[index]; + }; + } + + /** @class */ + function StopIteration() {} + + FBL.$break = function() + { + throw StopIteration; + }; - compileDOM: function() + // ************************************************************************************************ + + /** @namespace */ + var Renderer = { - 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); + 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 fnBlock = ['r=(function (root, context, o']; + var outputs = []; + var html = this.renderHTML(args, outputs, self); - for (var i = 0; i < path.staticIndex; ++i) - fnBlock.push(', ', 's'+i); + var doc = before.ownerDocument; + var div = doc.createElement("div"); + div.innerHTML = ""+html+"
"; - for (var i = 0; i < path.renderIndex; ++i) - fnBlock.push(', ', 'd'+i); + var tbody = div.firstChild.firstChild; + var parent = before.tagName == "TR" ? before.parentNode : before; + var after = before.tagName == "TR" ? before.nextSibling : null; - 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;'); + var firstRow = tbody.firstChild, lastRow; + while (tbody.firstChild) + { + lastRow = tbody.firstChild; + if (after) + parent.insertBefore(lastRow, after); + else + parent.appendChild(lastRow); + } - if (this.subject) - fnBlock.push('with (this) {'); - if (this.context) - fnBlock.push('with (context) {'); + var offset = 0; + if (before.tagName == "TR") + { + var node = firstRow.parentNode.firstChild; + for (; node && node != firstRow; node = node.nextSibling) + ++offset; + } - fnBlock.push(blocks.join("")); + var domArgs = [firstRow, this.tag.context, offset]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); - if (this.subject) - fnBlock.push('}'); - if (this.context) - fnBlock.push('}'); + this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + return [firstRow, lastRow]; + }, - fnBlock.push('return ', nodeCount, ';'); - fnBlock.push('})'); + insertBefore: function(args, before, self) + { + return this.insertNode(args, before.ownerDocument, before, false, self); + }, - function __bind__(object, fn) + insertAfter: function(args, after, self) { - return function(event) { return fn.apply(object, [event]); }; - } + return this.insertNode(args, after.ownerDocument, after, true, self); + }, - function __link__(node, tag, args) + insertNode: function(args, doc, element, isAfter, self) { - if (!tag || !tag.tag) - return; + if (!args) + args = {}; - tag.tag.compile(); + this.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 outputs = []; + var html = this.renderHTML(args, outputs, self); - var self = this; - function __loop__(iter, fn) - { - var nodeCount = 0; - for (var i = 0; i < iter.length; ++i) + //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) { - iter[i][0] = i; - iter[i][1] = nodeCount; - nodeCount += fn.apply(this, iter[i]); - //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); + while (womb.firstChild) + if (element.nextSibling) + element.parentNode.insertBefore(womb.firstChild, element.nextSibling); + else + element.parentNode.appendChild(womb.firstChild); } - return nodeCount; - } + 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); - function __path__(parent, offset) + return root; + }, + /**/ + + /* + insertAfter: function(args, before, self) { - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); - var root = parent; + this.tag.compile(); - for (var i = 2; i < arguments.length; ++i) - { - var index = arguments[i]; - if (i == 3) - index += offset; + 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; - if (index == -1) - parent = parent.parentNode; + var root = womb.firstChild; + while (womb.firstChild) + if (before.nextSibling) + before.parentNode.insertBefore(womb.firstChild, before.nextSibling); else - parent = parent.childNodes[index]; - } + before.parentNode.appendChild(womb.firstChild); - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); - return parent; - } + var domArgs = [root, this.tag.context, 0]; + domArgs.push.apply(domArgs, this.tag.domArgs); + domArgs.push.apply(domArgs, outputs); - var js = fnBlock.join(""); - //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); - var r = null; - eval(js); - this.renderDOM = r; - }, + this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), + domArgs); - generateDOM: function(path, blocks, args) - { - if (this.listeners || this.props) - this.generateNodePath(path, blocks); + return root; + }, + /**/ - if (this.listeners) + replace: function(args, parent, self) { - for (var i = 0; i < this.listeners.length; i += 2) + this.tag.compile(); + + var outputs = []; + var html = this.renderHTML(args, outputs, self); + + var root; + if (parent.nodeType == 1) { - 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);'); + parent.innerHTML = html; + root = parent.firstChild; } - } - - if (this.props) - { - for (var name in this.props) + else { - var val = this.props[name]; - var arg = generateArg(val, path, args); - blocks.push('node.', name, ' = ', arg, ';'); + 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); } - } - this.generateChildDOM(path, blocks, args); - return 1; - }, + 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); - 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(");"); - }, + return root; + }, - generateChildDOM: function(path, blocks, args) - { - path.push(0); - for (var i = 0; i < this.children.length; ++i) + append: function(args, parent, self) { - var child = this.children[i]; - if (isTag(child)) - path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); - else - path[path.length-1] += '+1'; + 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; } - path.pop(); - } -}; + }; -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // ************************************************************************************************ -FBL.DomplateEmbed.prototype = copyObject(FBL.DomplateTag.prototype, -/** @lends FBL.DomplateEmbed.prototype */ -{ - merge: function(args, oldTag) + function defineTags() { - 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) + for (var i = 0; i < arguments.length; ++i) { - var val = parseValue(attrs[name]); - this.attrs[name] = val; - readPartNames(val, this.vars); + 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; } + } - return creator(this, DomplateEmbed); - }, + 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" + ); - getVarNames: function(names) - { - if (this.value instanceof Parts) - names.push(this.value.parts[0].name); + })(); + + + /* 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" + }); - if (this.vars) - names.push.apply(names, this.vars); - }, - generateMarkup: function(topBlock, topOuts, blocks, info) + // ************************************************************************************************ + + this.Undefined = domplate(Firebug.Rep, { - this.addCode(topBlock, topOuts, blocks); + tag: OBJECTBOX("undefined"), - 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; + className: "undefined", - var val = this.attrs[name]; - blocks.push('"', name, '":'); - addParts(val, '', blocks, info); + supportsObject: function(object, type) + { + return type == "undefined"; } + }); - blocks.push('});'); - //this.generateChildMarkup(topBlock, topOuts, blocks, info); - }, + // ************************************************************************************************ - generateDOM: function(path, blocks, args) + this.Null = domplate(Firebug.Rep, { - var embedName = 'e'+path.embedIndex++; + tag: OBJECTBOX("null"), - this.generateNodePath(path, blocks); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - var valueName = 'd' + path.renderIndex++; - var argsName = 'd' + path.renderIndex++; - blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); + className: "null", - return embedName; - } -}); + supportsObject: function(object, type) + { + return object == null; + } + }); -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // ************************************************************************************************ -FBL.DomplateLoop.prototype = copyObject(FBL.DomplateTag.prototype, -/** @lends FBL.DomplateLoop.prototype */ -{ - merge: function(args, oldTag) + this.Nada = domplate(Firebug.Rep, { - this.varName = oldTag ? oldTag.varName : args[0]; - this.iter = oldTag ? oldTag.iter : parseValue(args[1]); - this.vars = []; + tag: SPAN(""), - this.children = oldTag ? copyArray(oldTag.children) : []; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - var offset = Math.min(args.length, 2); - parseChildren(args, offset, this.vars, this.children); + className: "nada" + }); - return creator(this, DomplateLoop); - }, + // ************************************************************************************************ - getVarNames: function(names) + this.Number = domplate(Firebug.Rep, { - if (this.iter instanceof Parts) - names.push(this.iter.parts[0].name); + tag: OBJECTBOX("$object"), - DomplateTag.prototype.getVarNames.apply(this, [names]); - }, + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - generateMarkup: function(topBlock, topOuts, blocks, info) - { - this.addCode(topBlock, topOuts, blocks); + className: "number", - var iterName; - if (this.iter instanceof Parts) + supportsObject: function(object, type) { - 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 + ")"; - } + return type == "boolean" || type == "number"; } - 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) + this.String = domplate(Firebug.Rep, { - var iterName = 'd'+path.renderIndex++; - var counterName = 'i'+path.loopIndex; - var loopName = 'l'+path.loopIndex++; + tag: OBJECTBOX(""$object""), - if (!path.length) - path.push(-1, 0); + shortTag: OBJECTBOX(""$object|cropString""), - var preIndex = path.renderIndex; - path.renderIndex = 0; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - var nodeCount = 0; + className: "string", - var subBlocks = []; - var basePath = path[path.length-1]; - for (var i = 0; i < this.children.length; ++i) + supportsObject: function(object, type) { - 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'; + return type == "string"; } + }); - 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; + this.Text = domplate(Firebug.Rep, + { + tag: OBJECTBOX("$object"), - return loopName; - } -}); + shortTag: OBJECTBOX("$object|cropString"), -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -/** @class */ -function Variable(name, format) -{ - this.name = name; - this.format = format; -} + className: "text" + }); -/** @class */ -function Parts(parts) -{ - this.parts = parts; -} + // ************************************************************************************************ -// ************************************************************************************************ + this.Caption = domplate(Firebug.Rep, + { + tag: SPAN({"class": "caption"}, "$object") + }); -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)) + this.Warning = domplate(Firebug.Rep, { - 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; - } + tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") + }); - if (!index) - return str; + // ************************************************************************************************ - var post = str.substr(index); - if (post) - parts.push(post); + this.Func = domplate(Firebug.Rep, + { + tag: + OBJECTLINK("$object|summarizeFunction"), - return new Parts(parts); -} + summarizeFunction: function(fn) + { + var fnRegex = /function ([^(]+\([^)]*\)) \{/; + var fnText = safeToString(fn); -function parseValue(val) -{ - return typeof(val) == 'string' ? parseParts(val) : val; -} + var m = fnRegex.exec(fnText); + return m ? m[1] : "function()"; + }, -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) + copySource: function(fn) { - var part = val.parts[i]; - if (part instanceof Variable) - vars.push(part.name); - } - } -} + copyToClipboard(safeToString(fn)); + }, -function generateArg(val, path, args) -{ - if (val instanceof Parts) - { - var vals = []; - for (var i = 0; i < val.parts.length; ++i) + monitor: function(fn, script, monitored) { - 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); - } + if (monitored) + Firebug.Debugger.unmonitorScript(fn, script, "monitor"); else - vals.push('"'+part.replace(/"/g, '\\"')+'"'); - } + Firebug.Debugger.monitorScript(fn, script, "monitor"); + }, - 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) + className: "function", + + supportsObject: function(object, type) { - 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 + ")"; - } + return isFunction(object); + }, - 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); -} + 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(); + }, -/** @class */ -function ArrayIterator(array) -{ - var index = -1; + getTitle: function(fn, context) + { + var name = fn.name ? fn.name : "function"; + return name + "()"; + }, - this.next = function() - { - if (++index >= array.length) - throw StopIteration; + getContextMenuItems: function(fn, target, context, script) + { + if (!script) + script = findScriptForFunctionInContext(context, fn); + if (!script) + return; - return array[index]; - }; -} + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; -/** @class */ -function StopIteration() {} + 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) } + ]; + } + }); -FBL.$break = function() -{ - throw StopIteration; -}; + // ************************************************************************************************ + /* + 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); + }, -/** @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(); + className: "jsdScript", + inspectable: false, - var outputs = []; - var html = this.renderHTML(args, outputs, self); + supportsObject: function(object, type) + { + return object instanceof jsdIScript; + }, - var doc = before.ownerDocument; - var div = doc.createElement("div"); - div.innerHTML = ""+html+"
"; + inspectObject: function(script, context) + { + var sourceLink = getSourceLinkForScript(script, context); + if (sourceLink) + Firebug.chrome.select(sourceLink); + }, - var tbody = div.firstChild.firstChild; - var parent = before.tagName == "TR" ? before.parentNode : before; - var after = before.tagName == "TR" ? before.nextSibling : null; + getRealObject: function(script, context) + { + return script; + }, - var firstRow = tbody.firstChild, lastRow; - while (tbody.firstChild) + getTooltip: function(script) { - lastRow = tbody.firstChild; - if (after) - parent.insertBefore(lastRow, after); - else - parent.appendChild(lastRow); - } + return $STRF("jsdIScript", [script.tag]); + }, - var offset = 0; - if (before.tagName == "TR") + getTitle: function(script, context) { - var node = firstRow.parentNode.firstChild; - for (; node && node != firstRow; node = node.nextSibling) - ++offset; - } + var fn = script.functionObject.getWrappedValue(); + return FirebugReps.Func.getTitle(fn, context); + }, - var domArgs = [firstRow, this.tag.context, offset]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); + getContextMenuItems: function(script, target, context) + { + var fn = script.functionObject.getWrappedValue(); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); - return [firstRow, lastRow]; - }, + var scriptInfo = getSourceFileAndLineByScript(context, script); + var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; - insertBefore: function(args, before, self) - { - return this.insertNode(args, before.ownerDocument, before, false, self); - }, + var name = getFunctionName(script, context); - insertAfter: function(args, after, self) - { - return this.insertNode(args, after.ownerDocument, after, true, self); - }, + 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) } + ]; + } + }); + /**/ + //************************************************************************************************ - insertNode: function(args, doc, element, isAfter, self) + this.Obj = domplate(Firebug.Rep, { - if (!args) - args = {}; + 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"}, "}") + ) + ), - this.tag.compile(); + propNumberTag: + SPAN({"class": "objectProp-number"}, "$object"), - var outputs = []; - var html = this.renderHTML(args, outputs, self); + propStringTag: + SPAN({"class": "objectProp-string"}, ""$object""), - //if (FBTrace.DBG_DOM) - // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); + propObjectTag: + SPAN({"class": "objectProp-object"}, "$object"), - var doc = element.ownerDocument; - if (!womb || womb.ownerDocument != doc) - womb = doc.createElement("div"); + propIterator: function (object) + { + ///Firebug.ObjectShortIteratorMax; + var maxLength = 55; // default max length for long representation - womb.innerHTML = html; + if (!object) + return []; - 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 props = []; + var length = 0; - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); + var numProperties = 0; + var numPropertiesShown = 0; + var maxLengthReached = false; - //if (FBTrace.DBG_DOM) - // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + var lib = this; - return root; - }, - /**/ + var propRepsMap = + { + "boolean": this.propNumberTag, + "number": this.propNumberTag, + "string": this.propStringTag, + "object": this.propObjectTag + }; - /* - insertAfter: function(args, before, self) - { - this.tag.compile(); + try + { + var title = Firebug.Rep.getTitle(object); + length += title.length; - var outputs = []; - var html = this.renderHTML(args, outputs, self); + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } - var doc = before.ownerDocument; - if (!womb || womb.ownerDocument != doc) - womb = doc.createElement("div"); + var type = typeof(value); + if (type == "boolean" || + type == "number" || + (type == "string" && value) || + (type == "object" && value && value.toString)) + { + var tag = propRepsMap[type]; - womb.innerHTML = html; + var value = (type == "object") ? + Firebug.getRep(value).getTitle(value) : + value + ""; - var root = womb.firstChild; - while (womb.firstChild) - if (before.nextSibling) - before.parentNode.insertBefore(womb.firstChild, before.nextSibling); - else - before.parentNode.appendChild(womb.firstChild); + length += name.length + value.length + 4; - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); + if (length <= maxLength) + { + props.push({ + tag: tag, + name: name, + object: value, + equal: "=", + delim: ", " + }); + + numPropertiesShown++; + } + else + maxLengthReached = true; - this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), - domArgs); + } - return root; - }, - /**/ + numProperties++; - replace: function(args, parent, self) - { - this.tag.compile(); + if (maxLengthReached && numProperties > numPropertiesShown) + break; + } - var outputs = []; - var html = this.renderHTML(args, outputs, self); + 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; + }, - var root; - if (parent.nodeType == 1) + fb_1_6_propIterator: function (object, max) { - parent.innerHTML = html; - root = parent.firstChild; - } - else - { - if (!parent || parent.nodeType != 9) - parent = document; + max = max || 3; + if (!object) + return []; - if (!womb || womb.ownerDocument != parent) - womb = parent.createElement("div"); - womb.innerHTML = html; + var props = []; + var len = 0, count = 0; - root = womb.firstChild; - //womb.removeChild(root); - } + try + { + for (var name in object) + { + var value; + try + { + value = object[name]; + } + catch (exc) + { + continue; + } - 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); + 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; + }, - return root; - }, + /* + propIterator: function (object) + { + if (!object) + return []; - append: function(args, parent, self) - { - this.tag.compile(); + var props = []; + var len = 0; - var outputs = []; - var html = this.renderHTML(args, outputs, self); - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); + try + { + for (var name in object) + { + var val; + try + { + val = object[name]; + } + catch (exc) + { + continue; + } - if (!womb || womb.ownerDocument != parent.ownerDocument) - womb = parent.ownerDocument.createElement("div"); - womb.innerHTML = html; + 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 + } - // TODO: xxxpedro domplate port to Firebug - var root = womb.firstChild; - while (womb.firstChild) - parent.appendChild(womb.firstChild); + return props; + }, + /**/ - // 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); + className: "object", - //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); + supportsObject: function(object, type) + { + return true; + } + }); - return root; - } -}; -// ************************************************************************************************ + // ************************************************************************************************ -function defineTags() -{ - for (var i = 0; i < arguments.length; ++i) + this.Arr = domplate(Firebug.Rep, { - var tagName = arguments[i]; - var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); - fn.DomplateTag = DomplateTag; + 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"}, "]") + ), - var fnName = tagName.toUpperCase(); - FBL[fnName] = fn; - } -} + 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 ? "" : ", "); -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" -); + 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 ? "" : ", "); -/* See license.txt for terms of usage */ + items.push({object: value, tag: tag, delim: delim}); + } -var FirebugReps = FBL.ns(function() { with (FBL) { + if (array.length > 3) + items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); + return items; + }, -// ************************************************************************************************ -// Common Tags + shortPropIterator: this.Obj.propIterator, -var OBJECTBOX = this.OBJECTBOX = - SPAN({"class": "objectBox objectBox-$className"}); + getItemIndex: function(child) + { + var arrayIndex = 0; + for (child = child.previousSibling; child; child = child.previousSibling) + { + if (child.repObject) + ++arrayIndex; + } + return arrayIndex; + }, -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" - }); + 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); + } + } -this.Undefined = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("undefined"), + return false; + }, + // END Yahoo BSD SOURCE See license below. - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + getTitle: function(object, context) + { + return "[" + object.length + "]"; + } + }); - className: "undefined", + // ************************************************************************************************ - supportsObject: function(object, type) + this.Property = domplate(Firebug.Rep, { - return type == "undefined"; - } -}); - -// ************************************************************************************************ + supportsObject: function(object) + { + return object instanceof Property; + }, -this.Null = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("null"), + getRealObject: function(prop, context) + { + return prop.object[prop.name]; + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + getTitle: function(prop, context) + { + return prop.name; + } + }); - className: "null", + // ************************************************************************************************ - supportsObject: function(object, type) + this.NetFile = domplate(this.Obj, { - return object == null; - } -}); + supportsObject: function(object) + { + return object instanceof Firebug.NetFile; + }, + + browseObject: function(file, context) + { + openNewTab(file.href); + return true; + }, -// ************************************************************************************************ + getRealObject: function(file, context) + { + return null; + } + }); -this.Nada = domplate(Firebug.Rep, -{ - tag: SPAN(""), + // ************************************************************************************************ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + this.Except = domplate(Firebug.Rep, + { + tag: + OBJECTBOX({_repObject: "$object"}, "$object.message"), - className: "nada" -}); + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ************************************************************************************************ + className: "exception", -this.Number = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("$object"), + supportsObject: function(object) + { + return object instanceof ErrorCopy; + } + }); - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - className: "number", + // ************************************************************************************************ - supportsObject: function(object, type) + this.Element = domplate(Firebug.Rep, { - return type == "boolean" || type == "number"; - } -}); + tag: + OBJECTLINK( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + 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"; + }, -this.String = domplate(Firebug.Rep, -{ - tag: OBJECTBOX(""$object""), + getSelectorTag: function(elt) + { + return elt.nodeName.toLowerCase(); + }, - shortTag: OBJECTBOX(""$object|cropString""), + getSelectorId: function(elt) + { + return elt.id ? "#" + elt.id : ""; + }, - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + getSelectorClass: function(elt) + { + return elt.className ? "." + elt.className.split(" ")[0] : ""; + }, - className: "string", + 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]; - supportsObject: function(object, type) - { - return type == "string"; - } -}); + // 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 '; - /**/ - - r[++i] = ''; - r[++i] = tpl.HTML; - r[++i] = ''; - - 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: "Save Options in Cookies", - type: "checkbox", - value: "saveCookies", - checked: Firebug.saveCookies, - command: "saveOptions" - }, - "-", - { - 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: "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); - }, - - saveOptions: function(target) - { - var saveEnabled = target.getAttribute("checked"); - - if (!saveEnabled) this.restorePrefs(); - - this.updateMenu(target); - - return false; - }, - - restorePrefs: function(target) - { - Firebug.restorePrefs(); - - if(Firebug.saveCookies) - Firebug.savePrefs(); - else - Firebug.erasePrefs(); - - if (target) - this.updateMenu(target); - - return false; - }, - - 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(FirebugChrome.selectedPanelName); - - if (FirebugChrome.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 || !FirebugChrome.isOpen; - - if(shouldOpen) - this.open(); - else - this.close(); - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - detach: function() - { - if(!FirebugChrome.chromeMap.popup) - { - 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 - FirebugChrome.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 ? FirebugChrome.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() - { - 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 (!FirebugChrome.isOpen) - { - FirebugChrome.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 (FirebugChrome.isOpen || !this.isInitialized) - { - if (this.isInitialized) - { - //dispatch(Firebug.modules, "shutdown", []); - this.shutdown(); - } - - FirebugChrome.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 = FirebugChrome.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 = FirebugChrome.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] - ); - - 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() - { - // 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); - - 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(); - - var htmlPanel = chrome.getPanel("HTML"); - htmlPanel.createUI(); - - Firebug.Console.logFormatted( - ["Firebug could not capture console calls during " + - persistDelay + "ms"], - Firebug.context, - "info" - ); - } - 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.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); - - FirebugChrome.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); - - FirebugChrome.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.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 */ - - 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) { - // ************************************************************************************************ - - - 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 = /\s+

([\s\S]+)<\/p>\s+<\/body>$/.exec(source); - if (match) - source = match[1]; - - console.log(source); - }); - } - }; - - // ************************************************************************************************ - - var fetchResource = function(url) - { - var xhr = FBL.Ajax.getXHRObject(); - xhr.open("get", url, false); - xhr.send(); - - return xhr.responseText; - }; - - var fetchProxyResource = function(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."; - } - - return data ? data.contents : ""; - }; - - - // ************************************************************************************************ - }}); - - - /* 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.Style = - { - }; - - // ************************************************************************************************ - }}); - - - /* 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 = ""; - - // 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 = ""; - 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 = "

"; - - // 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 = "
"; - - // 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; - - /**#@-*/ - - // ************************************************************************************************ - }}); - - // 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 "<"; - case ">": - return ">"; - case "&": - return "&"; - case "'": - return "'"; - case '"': - return """; - } - 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(',""'); - }, - - 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 = ""+html+"
"; - - 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(""$object""), - - shortTag: OBJECTBOX(""$object|cropString""), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - 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"}, ""$object""), - - 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( - "<", - SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), - FOR("attr", "$object|attrIterator", - " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ - ), - ">" - ), - - 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 '; + /**/ + + r[++i] = ''; + r[++i] = tpl.HTML; + r[++i] = ''; + + 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: "Save Options in Cookies", + type: "checkbox", + value: "saveCookies", + checked: Firebug.saveCookies, + command: "saveOptions" + }, + "-", + { + 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: "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); + }, + + saveOptions: function(target) + { + var saveEnabled = target.getAttribute("checked"); + + if (!saveEnabled) this.restorePrefs(); + + this.updateMenu(target); + + return false; + }, + + restorePrefs: function(target) + { + Firebug.restorePrefs(); + + if(Firebug.saveCookies) + Firebug.savePrefs(); + else + Firebug.erasePrefs(); + + if (target) + this.updateMenu(target); + + return false; + }, + + 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(FirebugChrome.selectedPanelName); + + if (FirebugChrome.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 || !FirebugChrome.isOpen; + + if(shouldOpen) + this.open(); + else + this.close(); + } + }, + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + detach: function() + { + if(!FirebugChrome.chromeMap.popup) + { + 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 + FirebugChrome.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 ? FirebugChrome.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() + { + 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 (!FirebugChrome.isOpen) + { + FirebugChrome.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 (FirebugChrome.isOpen || !this.isInitialized) + { + if (this.isInitialized) + { + //dispatch(Firebug.modules, "shutdown", []); + this.shutdown(); + } + + FirebugChrome.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 = FirebugChrome.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 = FirebugChrome.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] + ); + + 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() + { + // 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); + + 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(); + + var htmlPanel = chrome.getPanel("HTML"); + htmlPanel.createUI(); + + Firebug.Console.logFormatted( + ["Firebug could not capture console calls during " + + persistDelay + "ms"], + Firebug.context, + "info" + ); + } + 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.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); + + FirebugChrome.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); + + FirebugChrome.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.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 */ + + 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) { + // ************************************************************************************************ + + + 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 = /\s+

([\s\S]+)<\/p>\s+<\/body>$/.exec(source); + if (match) + source = match[1]; + + console.log(source); + }); + } + }; + + // ************************************************************************************************ + + var fetchResource = function(url) + { + var xhr = FBL.Ajax.getXHRObject(); + xhr.open("get", url, false); + xhr.send(); + + return xhr.responseText; + }; + + var fetchProxyResource = function(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."; + } + + return data ? data.contents : ""; + }; + + + // ************************************************************************************************ + }}); + + + /* 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.Style = + { + }; + + // ************************************************************************************************ + }}); + + + /* 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 = ""; + + // 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 = ""; + 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 = "

"; + + // 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 = "
"; + + // 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; + + /**#@-*/ + + // ************************************************************************************************ + }}); + + // 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 "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + 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(',""'); + }, + + 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 = ""+html+"
"; + + 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(""$object""), + + shortTag: OBJECTBOX(""$object|cropString""), + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + 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"}, ""$object""), + + 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( + "<", + SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), + FOR("attr", "$object|attrIterator", + " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ + ), + ">" + ), + + 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