Merge mozilla-central and mozilla-inbound

This commit is contained in:
Matt Brubeck 2012-05-13 08:27:03 -07:00
Родитель 4b86369c76 823701c74f
Коммит 790701eabc
188 изменённых файлов: 14015 добавлений и 7971 удалений

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1335396801000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
<emItems>
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
<versionRange minVersion="0" maxVersion="*">
@ -23,6 +23,24 @@
</emItem>
<emItem blockID="i43" id="supportaccessplugin@gmail.com">
</emItem>
<emItem blockID="i47" id="youtube@youtube2.com">
</emItem>
<emItem blockID="i88" id="anttoolbar@ant.com">
<versionRange minVersion="2.4.6.4" maxVersion="2.4.6.4" severity="1">
</versionRange>
</emItem>
<emItem blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
<versionRange minVersion="0.1" maxVersion="3.3.0.*">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.7a1" maxVersion="*" />
</targetApplication>
</versionRange>
<versionRange minVersion="3.3.1" maxVersion="*">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="5.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i65" id="activity@facebook.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -55,10 +73,29 @@
</emItem>
<emItem blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
</emItem>
<emItem blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
<versionRange minVersion="2.1" maxVersion="3.3">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
<versionRange minVersion=" " maxVersion="6.9.8">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.7a1pre" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i63" id="youtube@youtuber.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
<versionRange minVersion="0.1" maxVersion="*">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="9.0a1" maxVersion="9.0" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i18" id="msntoolbar@msn.com">
<versionRange minVersion=" " maxVersion="6.*">
</versionRange>
@ -73,8 +110,18 @@
<versionRange minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
</versionRange>
</emItem>
<emItem blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
<versionRange minVersion="0" maxVersion="*">
<emItem blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
<versionRange minVersion="1.2" maxVersion="1.2">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i75" os="Darwin,Linux" id="firebug@software.joehewitt.com">
<versionRange minVersion="1.9.0" maxVersion="1.9.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="9.0a1" maxVersion="9.*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
@ -97,16 +144,18 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i70" id="psid-vhvxQHMZBOzUZA@jetpack">
<versionRange minVersion="0" maxVersion="*" severity="1">
<emItem blockID="i51" id="admin@youtubeplayer.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i68" id="flashupdate@adobe.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
</emItem>
<emItem blockID="i90" id="videoplugin@player.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i84" id="pink@rosaplugin.info">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -119,20 +168,35 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i56" id="flash@adobe.com">
<versionRange minVersion="0" maxVersion="*">
<emItem blockID="i23" id="firefox@bandoo.com">
<versionRange minVersion="5.0" maxVersion="5.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.7a1pre" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i55" id="youtube@youtube7.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i47" id="youtube@youtube2.com">
</emItem>
<emItem blockID="i87" os="WINNT" id="afurladvisor@anchorfree.com">
<versionRange minVersion="0" maxVersion="*">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="13.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
</versionRange>
</emItem>
<emItem blockID="i2" id="fdm_ffext@freedownloadmanager.org">
<versionRange minVersion="1.0" maxVersion="1.3.1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i44" id="sigma@labs.mozilla">
</emItem>
<emItem blockID="i5" id="support@daemon-tools.cc">
@ -157,6 +221,10 @@
<versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
</versionRange>
</emItem>
<emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
<versionRange minVersion="2.2" maxVersion="2.2">
</versionRange>
</emItem>
<emItem blockID="i76" id="crossriderapp3924@crossrider.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -169,8 +237,19 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
<versionRange minVersion="2.2" maxVersion="2.2">
<emItem blockID="i70" id="psid-vhvxQHMZBOzUZA@jetpack">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i56" id="flash@adobe.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}">
<versionRange minVersion="0.1" maxVersion="7.6.1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="8.0a1" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i82" id="{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}">
@ -189,31 +268,85 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i51" id="admin@youtubeplayer.com">
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
</emItem>
<emItem blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i11" id="yslow@yahoo-inc.com">
<versionRange minVersion="2.0.5" maxVersion="2.0.5">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.5.7" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i52" id="ff-ext@youtube">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
<versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.7a1pre" maxVersion="*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i15" id="personas@christopher.beard">
<versionRange minVersion="1.6" maxVersion="1.6">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.6" maxVersion="3.6.*" />
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i21" id="support@update-firefox.com">
</emItem>
</emItems>
<pluginItems>
<pluginItem blockID="p26">
<match name="name" exp="^Yahoo Application State Plugin$" /> <match name="description" exp="^Yahoo Application State Plugin$" /> <match name="filename" exp="npYState.dll" /> <versionRange >
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0a1" maxVersion="3.*" />
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p27">
<match name="name" exp="QuickTime Plug-in 7[.]1[.]" /> <match name="filename" exp="npqtplugin.?[.]dll" /> <versionRange >
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0a1" maxVersion="3.*" />
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p28">
<match name="filename" exp="NPFFAddOn.dll" /> </pluginItem>
<pluginItem blockID="p31">
<match name="filename" exp="NPMySrch.dll" /> </pluginItem>
<pluginItem blockID="p32">
<match name="filename" exp="npViewpoint.dll" /> <versionRange >
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.0" maxVersion="*" />
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p33">
<match name="name" exp="[0-6]\.0\.[01]\d{2}\.\d+" /> <match name="filename" exp="npdeploytk.dll" /> <versionRange severity="1"></versionRange>
</pluginItem>
<pluginItem blockID="p34">
<match name="filename" exp="[Nn][Pp][Jj][Pp][Ii]1[56]0_[0-9]+\.[Dd][Ll][Ll]" /> <versionRange >
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="3.6a1pre" maxVersion="*" />
</targetApplication>
</versionRange>
</pluginItem>
<pluginItem blockID="p80">
<match name="description" exp="[^\d\._]((0(\.\d+(\.\d+([_\.]\d+)?)?)?)|(1\.(([0-5](\.\d+([_\.]\d+)?)?)|(6(\.0([_\.](0?\d|1\d|2\d|30))?)?)|(7(\.0([_\.][0-2])?)?))))([^\d\._]|$)" /> <match name="filename" exp="(npjp2\.dll)|(libnpjp2\.so)" /> <versionRange severity="1"></versionRange>
<match name="name" exp="\(TM\)" /> <match name="description" exp="[^\d\._]((0(\.\d+(\.\d+([_\.]\d+)?)?)?)|(1\.(([0-5](\.\d+([_\.]\d+)?)?)|(6(\.0([_\.](0?\d|1\d|2\d|30))?)?)|(7(\.0([_\.][0-2])?)?))))([^\d\._]|$)" /> <match name="filename" exp="(npjp2\.dll)|(libnpjp2\.so)" /> <versionRange severity="1"></versionRange>
</pluginItem>
<pluginItem blockID="p85">
<match name="filename" exp="JavaPlugin2_NPAPI\.plugin" /> <versionRange minVersion="0" maxVersion="12.9.0" severity="1"></versionRange>
<match name="filename" exp="JavaPlugin2_NPAPI\.plugin" /> <versionRange minVersion="0" maxVersion="13.6.0" severity="1"></versionRange>
</pluginItem>
<pluginItem os="Darwin" blockID="p89">
<match name="filename" exp="AdobePDFViewerNPAPI\.plugin" /> <versionRange minVersion="0" maxVersion="10.1.3" severity="1"></versionRange>
</pluginItem>
</pluginItems>

Просмотреть файл

@ -1042,12 +1042,17 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
// Disable the error console
pref("devtools.errorconsole.enabled", false);
// Enable the developer toolbar
pref("devtools.toolbar.enabled", false);
// Enable the Inspector
pref("devtools.inspector.enabled", true);
pref("devtools.inspector.htmlHeight", 112);
pref("devtools.inspector.htmlPanelOpen", false);
pref("devtools.inspector.sidebarOpen", false);
pref("devtools.inspector.activeSidebar", "ruleview");
pref("devtools.inspector.highlighterShowVeil", true);
pref("devtools.inspector.highlighterShowInfobar", true);
// Enable the Layout View
pref("devtools.layoutview.enabled", false);
@ -1088,8 +1093,14 @@ pref("devtools.styleeditor.transitions", true);
// Enable tools for Chrome development.
pref("devtools.chrome.enabled", false);
// Disable the GCLI enhanced command line.
pref("devtools.gcli.enable", false);
// Display the introductory text
pref("devtools.gcli.hideIntro", false);
// How eager are we to show help: never=1, sometimes=2, always=3
pref("devtools.gcli.eagerHelper", 2);
// Do we allow the 'pref set' command
pref("devtools.gcli.allowSet", false);
// The last Web Console height. This is initially 0 which means that the Web
// Console will use the default height next time it shows.

Просмотреть файл

@ -176,8 +176,14 @@
<menuseparator class="appmenu-menuseparator"/>
<menu id="appmenu_webDeveloper"
label="&appMenuWebDeveloper.label;">
<menupopup id="appmenu_webDeveloper_popup"
onpopupshowing="onWebDeveloperMenuShowing();">
<menupopup id="appmenu_webDeveloper_popup">
<menuitem id="appmenu_devToolbar"
type="checkbox"
autocheck="false"
hidden="true"
label="&devToolbarMenu.label;"
command="Tools:DevToolbar"
key="key_devToolbar"/>
<menuitem id="appmenu_webConsole"
label="&webConsoleCmd.label;"
type="checkbox"
@ -191,6 +197,7 @@
key="key_inspect"/>
<menuitem id="appmenu_debugger"
hidden="true"
type="checkbox"
label="&debuggerMenu.label;"
key="key_debugger"
command="Tools:Debugger"/>

Просмотреть файл

@ -531,8 +531,15 @@
<menu id="webDeveloperMenu"
label="&webDeveloperMenu.label;"
accesskey="&webDeveloperMenu.accesskey;">
<menupopup id="menuWebDeveloperPopup"
onpopupshowing="onWebDeveloperMenuShowing();">
<menupopup id="menuWebDeveloperPopup">
<menuitem id="menu_devToolbar"
type="checkbox"
autocheck="false"
hidden="true"
label="&devToolbarMenu.label;"
accesskey="&devToolbarMenu.accesskey;"
key="key_devToolbar"
command="Tools:DevToolbar"/>
<menuitem id="webConsole"
type="checkbox"
label="&webConsoleCmd.label;"
@ -548,6 +555,7 @@
command="Tools:Inspect"/>
<menuitem id="menu_debugger"
hidden="true"
type="checkbox"
label="&debuggerMenu.label;"
key="key_debugger"
command="Tools:Debugger"/>

Просмотреть файл

@ -126,6 +126,7 @@
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/>
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
@ -164,6 +165,10 @@
oncommand="InspectorUI.copyOuterHTML();"/>
<command id="Inspector:DeleteNode"
oncommand="InspectorUI.deleteNode();"/>
<command id="Inspector:ToggleVeil"
oncommand="InspectorUI.toggleVeil();"/>
<command id="Inspector:ToggleInfobar"
oncommand="InspectorUI.toggleInfobar();"/>
</commandset>
<broadcasterset id="mainBroadcasterSet">
@ -257,6 +262,13 @@
#endif
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
<key id="key_devToolbar" key="&devToolbar.commandkey;" command="Tools:DevToolbar"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
#ifdef XP_MACOSX
modifiers="accel,alt"

Просмотреть файл

@ -179,6 +179,12 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
}
});
XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", tmp);
return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
});
XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
let tmp = {};
Cu.import("resource:///modules/inspector.jsm", tmp);
@ -1695,6 +1701,16 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
setUrlAndSearchBarWidthForConditionalForwardButton();
});
// Enable developer toolbar?
let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
if (devToolbarEnabled) {
document.getElementById("menu_devToolbar").hidden = false;
document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_devToolbar").hidden = false;
#endif
}
// Enable Inspector?
let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
if (enabled) {
@ -1703,6 +1719,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_pageInspect").hidden = false;
#endif
document.getElementById("developer-toolbar-inspector").hidden = false;
}
// Enable Debugger?
@ -1713,6 +1730,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_debugger").hidden = false;
#endif
document.getElementById("developer-toolbar-debugger").hidden = false;
}
// Enable Remote Debugger?
@ -9324,10 +9342,6 @@ var StyleEditor = {
}
};
function onWebDeveloperMenuShowing() {
document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null);
}
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
#ifdef XP_WIN

Просмотреть файл

@ -1015,9 +1015,28 @@
hidden="true">
#ifdef XP_MACOSX
<toolbarbutton id="highlighter-closebutton"
class="devtools-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
#endif
<toolbarbutton id="inspector-option-toolbarbutton"
type="menu"
tabindex="0"
tooltiptext="&inspectOptionButton.tooltiptext;">
<menupopup id="inspector-option-popup"
position="before_start">
<menuitem id="inspectorToggleVeil"
type="checkbox"
label="&inspectorToggleVeil.label;"
accesskey="&inspectorToggleVeil.accesskey;"
command="Inspector:ToggleVeil"/>
<menuitem id="inspectorToggleInfobar"
type="checkbox"
label="&inspectorToggleInfobar.label;"
accesskey="&inspectorToggleInfobar.accesskey;"
command="Inspector:ToggleInfobar"/>
</menupopup>
</toolbarbutton>
<toolbarbutton id="inspector-inspect-toolbutton"
class="devtools-toolbarbutton"
command="Inspector:Inspect"/>
@ -1048,10 +1067,46 @@
</hbox>
#ifndef XP_MACOSX
<toolbarbutton id="highlighter-closebutton"
class="devtools-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
#endif
</toolbar>
<toolbar id="developer-toolbar"
class="devtools-toolbar"
hidden="true">
#ifdef XP_MACOSX
<toolbarbutton id="developer-toolbar-closebutton"
oncommand="DeveloperToolbar.hide();"
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
#endif
<stack class="gclitoolbar-stack-node" flex="1">
<description class="gclitoolbar-prompt">&#187;</description>
<description class="gclitoolbar-complete-node"/>
<textbox class="gclitoolbar-input-node" rows="1"/>
</stack>
<toolbarbutton id="developer-toolbar-webconsole"
label="&webConsoleButton.label;"
class="devtools-toolbarbutton"
command="Tools:WebConsole"/>
<toolbarbutton id="developer-toolbar-inspector"
label="&inspectorButton.label;"
class="devtools-toolbarbutton"
hidden="true"
command="Tools:Inspect"/>
<toolbarbutton id="developer-toolbar-debugger"
label="&scriptsButton.label;"
class="devtools-toolbarbutton"
hidden="true"
command="Tools:Debugger"/>
#ifndef XP_MACOSX
<toolbarbutton id="developer-toolbar-closebutton"
oncommand="DeveloperToolbar.hide();"
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
#endif
</toolbar>
<toolbar id="addon-bar"
toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"
collapsed="true"

Просмотреть файл

@ -12,6 +12,11 @@
overflow: hidden;
}
#highlighter-veil-container:not([dim]) > .highlighter-veil,
#highlighter-veil-container:not([dim]) > hbox > .highlighter-veil {
visibility: hidden;
}
#highlighter-veil-container:not([disable-transitions]) > .highlighter-veil,
#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox,
#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > .highlighter-veil,
@ -101,6 +106,10 @@ html|*#highlighter-nodeinfobar-tagname {
display: none;
}
#inspector-option-toolbarbutton > .toolbarbutton-menu-dropmarker {
display: none;
}
#inspector-layoutview-container > iframe {
-moz-transition-property: height;
-moz-transition-duration: 0.1s;

Просмотреть файл

@ -67,6 +67,20 @@ function DebuggerUI(aWindow) {
}
DebuggerUI.prototype = {
/**
* Called by the DebuggerPane to update the Debugger toggle switches with the
* debugger state.
*/
refreshCommand: function DUI_refreshCommand() {
let selectedTab = this.chromeWindow.getBrowser().selectedTab;
let command = this.chromeWindow.document.getElementById("Tools:Debugger");
if (this.getDebugger(selectedTab) != null) {
command.setAttribute("checked", "true");
} else {
command.removeAttribute("checked");
}
},
/**
* Starts a debugger for the current tab, or stops it if already started.
@ -79,7 +93,7 @@ DebuggerUI.prototype = {
tab._scriptDebugger.close();
return null;
}
return new DebuggerPane(tab);
return new DebuggerPane(this, tab);
},
/**
@ -115,7 +129,7 @@ DebuggerUI.prototype = {
* @return DebuggerPane if a debugger exists for the tab, null otherwise.
*/
getDebugger: function DUI_getDebugger(aTab) {
return aTab._scriptDebugger;
return '_scriptDebugger' in aTab ? aTab._scriptDebugger : null;
},
/**
@ -153,7 +167,8 @@ DebuggerUI.prototype = {
* @param XULElement aTab
* The tab in which to create the debugger.
*/
function DebuggerPane(aTab) {
function DebuggerPane(aDebuggerUI, aTab) {
this._globalUI = aDebuggerUI;
this._tab = aTab;
this._initServer();
@ -182,7 +197,7 @@ DebuggerPane.prototype = {
let ownerDocument = gBrowser.parentNode.ownerDocument;
this._splitter = ownerDocument.createElement("splitter");
this._splitter.setAttribute("class", "hud-splitter");
this._splitter.setAttribute("class", "devtools-horizontal-splitter");
this._frame = ownerDocument.createElement("iframe");
this._frame.height = DebuggerPreferences.height;
@ -207,6 +222,7 @@ DebuggerPane.prototype = {
}, true);
this._frame.setAttribute("src", DBG_XUL);
this._globalUI.refreshCommand();
},
/**
@ -229,6 +245,8 @@ DebuggerPane.prototype = {
this._splitter = null;
this._frame = null;
this._nbox = null;
this._globalUI.refreshCommand();
},
/**

Просмотреть файл

@ -98,6 +98,7 @@
<menulist id="scripts" class="devtools-menulist"
label="&debuggerUI.emptyScriptText;"/>
<textbox id="scripts-search" type="search"
class="devtools-searchinput"
emptytext="&debuggerUI.emptyFilterText;"/>
<spacer flex="1"/>
#ifndef XP_MACOSX

Просмотреть файл

@ -168,6 +168,7 @@ TreePanel.prototype = {
this.splitter = this.document.createElement("splitter");
this.splitter.id = "inspector-tree-splitter";
this.splitter.className = "devtools-horizontal-splitter";
let container = this.document.getElementById("appcontent");
container.appendChild(this.splitter);

Просмотреть файл

@ -104,7 +104,13 @@ const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
* // Is a node highlightable.
* boolean isNodeHighlightable(aNode);
*
* // Add/Remove lsiteners
* // Show/hide the veil and the infobar
* void showInfobar();
* void hideInfobar();
* void showVeil();
* void hideVeil();
*
* // Add/Remove listeners
* // @param aEvent - event name
* // @param aListener - function callback
* void addListener(aEvent, aListener);
@ -171,6 +177,7 @@ Highlighter.prototype = {
// The veil will make the whole page darker except
// for the region of the selected box.
this.buildVeil(this.veilContainer);
this.showVeil();
this.buildInfobar(controlsBox);
@ -367,6 +374,36 @@ Highlighter.prototype = {
let nodeName = aNode.nodeName.toLowerCase();
return !INSPECTOR_INVISIBLE_ELEMENTS[nodeName];
},
/**
* Hide the veil
*/
hideVeil: function Highlighter_hideVeil() {
this.veilContainer.removeAttribute("dim");
},
/**
* Show the veil
*/
showVeil: function Highlighter_showVeil() {
this.veilContainer.setAttribute("dim", "true");
},
/**
* Hide the infobar
*/
hideInfobar: function Highlighter_hideInfobar() {
this.nodeInfo.container.setAttribute("hidden", "true");
},
/**
* Show the infobar
*/
showInfobar: function Highlighter_showInfobar() {
this.nodeInfo.container.removeAttribute("hidden");
this.moveInfobar();
},
/**
* Build the veil:
*
@ -383,7 +420,6 @@ Highlighter.prototype = {
* @param nsIDOMElement aParent
* The container of the veil boxes.
*/
buildVeil: function Highlighter_buildVeil(aParent)
{
// We will need to resize these boxes to surround a node.

Просмотреть файл

@ -383,7 +383,7 @@ InspectorUI.prototype = {
/**
* Toggle the TreePanel.
*/
toggleHTMLPanel: function TP_toggle()
toggleHTMLPanel: function TP_toggleHTMLPanel()
{
if (this.treePanel.isOpen()) {
this.treePanel.close();
@ -403,7 +403,39 @@ InspectorUI.prototype = {
*/
get isInspectorOpen()
{
return this.toolbar && !this.toolbar.hidden && this.highlighter;
return !!(this.toolbar && !this.toolbar.hidden && this.highlighter);
},
/**
* Toggle highlighter veil.
*/
toggleVeil: function IUI_toggleVeil()
{
if (this.currentInspector._highlighterShowVeil) {
this.highlighter.hideVeil();
this.currentInspector._highlighterShowVeil = false;
Services.prefs.setBoolPref("devtools.inspector.highlighterShowVeil", false);
} else {
this.highlighter.showVeil();
this.currentInspector._highlighterShowVeil = true;
Services.prefs.setBoolPref("devtools.inspector.highlighterShowVeil", true);
}
},
/**
* Toggle highlighter infobar.
*/
toggleInfobar: function IUI_toggleInfobar()
{
if (this.currentInspector._highlighterShowInfobar) {
this.highlighter.hideInfobar();
this.currentInspector._highlighterShowInfobar = false;
Services.prefs.setBoolPref("devtools.inspector.highlighterShowInfobar", false);
} else {
this.highlighter.showInfobar();
this.currentInspector._highlighterShowInfobar = true;
Services.prefs.setBoolPref("devtools.inspector.highlighterShowInfobar", true);
}
},
/**
@ -502,7 +534,7 @@ InspectorUI.prototype = {
// is limited to some specific elements and has moved the focus somewhere else.
// So in this case, we want to focus the content window.
// See: https://developer.mozilla.org/en/XUL_Tutorial/Focus_and_Selection#Platform_Specific_Behaviors
if (!this.toolbar.querySelector("-moz-focusring")) {
if (!this.toolbar.querySelector(":-moz-focusring")) {
this.win.focus();
}
@ -543,6 +575,12 @@ InspectorUI.prototype = {
inspector._activeSidebar =
Services.prefs.getCharPref("devtools.inspector.activeSidebar");
inspector._highlighterShowVeil =
Services.prefs.getBoolPref("devtools.inspector.highlighterShowVeil");
inspector._highlighterShowInfobar =
Services.prefs.getBoolPref("devtools.inspector.highlighterShowInfobar");
this.win.addEventListener("pagehide", this, true);
this._currentInspector = inspector;
@ -652,7 +690,7 @@ InspectorUI.prototype = {
if (!aKeepInspector)
this.store.deleteInspector(this.winID);
this.inspectMenuitem.setAttribute("checked", false);
this.inspectMenuitem.removeAttribute("checked");
this.browser = this.win = null; // null out references to browser and window
this.winID = null;
this.selection = null;
@ -849,6 +887,23 @@ InspectorUI.prototype = {
this._sidebar.show();
}
let menu = this.chromeDoc.getElementById("inspectorToggleVeil");
if (this.currentInspector._highlighterShowVeil) {
menu.setAttribute("checked", "true");
} else {
menu.removeAttribute("checked");
this.highlighter.hideVeil();
}
menu = this.chromeDoc.getElementById("inspectorToggleInfobar");
if (this.currentInspector._highlighterShowInfobar) {
menu.setAttribute("checked", "true");
this.highlighter.showInfobar();
} else {
menu.removeAttribute("checked");
this.highlighter.hideInfobar();
}
Services.obs.notifyObservers({wrappedJSObject: this},
INSPECTOR_NOTIFICATIONS.OPENED, null);
},

Просмотреть файл

@ -1,6 +1,7 @@
browser.jar:
* content/browser/inspector.html (highlighter/inspector.html)
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
content/browser/devtools/HUDService-content.js (webconsole/HUDService-content.js)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
content/browser/scratchpad.js (scratchpad/scratchpad.js)
content/browser/splitview.css (shared/splitview.css)
@ -17,3 +18,5 @@ browser.jar:
content/browser/debugger.css (debugger/debugger.css)
content/browser/debugger-controller.js (debugger/debugger-controller.js)
content/browser/debugger-view.js (debugger/debugger-view.js)
content/browser/devtools/gcli.css (webconsole/gcli.css)
content/browser/devtools/gcliblank.xhtml (webconsole/gcliblank.xhtml)

Просмотреть файл

@ -0,0 +1,671 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Firefox Developer Toolbar.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com> (Original Author)
* Joe Walker <jwalker@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
let EXPORTED_SYMBOLS = [ "DeveloperToolbar", "loadCommands" ];
const NS_XHTML = 'http://www.w3.org/1999/xhtml';
XPCOMUtils.defineLazyGetter(this, "gcli", function () {
let obj = {};
Components.utils.import("resource:///modules/gcli.jsm", obj);
return obj.gcli;
});
let console = gcli._internal.console;
/**
* Load the various Command JSMs.
* Should be called when the developer toolbar first opens.
*/
function loadCommands()
{
Components.utils.import("resource:///modules/GcliCommands.jsm", {});
Components.utils.import("resource:///modules/GcliTiltCommands.jsm", {});
}
let commandsLoaded = false;
/**
* A component to manage the global developer toolbar, which contains a GCLI
* and buttons for various developer tools.
* @param aChromeWindow The browser window to which this toolbar is attached
* @param aToolbarElement See browser.xul:<toolbar id="developer-toolbar">
*/
function DeveloperToolbar(aChromeWindow, aToolbarElement)
{
if (!commandsLoaded) {
loadCommands();
commandsLoaded = true;
}
this._chromeWindow = aChromeWindow;
this._element = aToolbarElement;
this._element.hidden = true;
this._doc = this._element.ownerDocument;
this._lastState = NOTIFICATIONS.HIDE;
this._pendingShowCallback = undefined;
this._pendingHide = false;
}
/**
* Inspector notifications dispatched through the nsIObserverService
*/
const NOTIFICATIONS = {
/** DeveloperToolbar.show() has been called, and we're working on it */
LOAD: "developer-toolbar-load",
/** DeveloperToolbar.show() has completed */
SHOW: "developer-toolbar-show",
/** DeveloperToolbar.hide() has been called */
HIDE: "developer-toolbar-hide"
};
/**
* Attach notification constants to the object prototype so tests etc can
* use them without needing to import anything
*/
DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS;
/**
* Is the toolbar open?
*/
Object.defineProperty(DeveloperToolbar.prototype, 'visible', {
get: function DT_visible() {
return !this._element.hidden;
},
enumerable: true
});
/**
* Called from browser.xul in response to menu-click or keyboard shortcut to
* toggle the toolbar
*/
DeveloperToolbar.prototype.toggle = function DT_toggle()
{
if (this.visible) {
this.hide();
} else {
this.show();
this._input.focus();
}
};
/**
* Even if the user has not clicked on 'Got it' in the intro, we only show it
* once per session.
* Warning this is slightly messed up because this.DeveloperToolbar is not the
* same as this.DeveloperToolbar when in browser.js context.
*/
DeveloperToolbar.introShownThisSession = false;
/**
* Show the developer toolbar
* @param aCallback show events can be asynchronous. If supplied aCallback will
* be called when the DeveloperToolbar is visible
*/
DeveloperToolbar.prototype.show = function DT_show(aCallback)
{
if (this._lastState != NOTIFICATIONS.HIDE) {
return;
}
this._notify(NOTIFICATIONS.LOAD);
this._pendingShowCallback = aCallback;
this._pendingHide = false;
let checkLoad = function() {
if (this.tooltipPanel && this.tooltipPanel.loaded &&
this.outputPanel && this.outputPanel.loaded) {
this._onload();
}
}.bind(this);
this._input = this._doc.querySelector(".gclitoolbar-input-node");
this.tooltipPanel = new TooltipPanel(this._doc, this._input, checkLoad);
this.outputPanel = new OutputPanel(this._doc, this._input, checkLoad);
};
/**
* Initializing GCLI can only be done when we've got content windows to write
* to, so this needs to be done asynchronously.
*/
DeveloperToolbar.prototype._onload = function DT_onload()
{
this._doc.getElementById("Tools:DevToolbar").setAttribute("checked", "true");
let contentDocument = this._chromeWindow.getBrowser().contentDocument;
this.display = gcli._internal.createDisplay({
contentDocument: contentDocument,
chromeDocument: this._doc,
chromeWindow: this._chromeWindow,
hintElement: this.tooltipPanel.hintElement,
inputElement: this._input,
completeElement: this._doc.querySelector(".gclitoolbar-complete-node"),
backgroundElement: this._doc.querySelector(".gclitoolbar-stack-node"),
outputDocument: this.outputPanel.document,
environment: {
chromeDocument: this._doc,
contentDocument: contentDocument
},
tooltipClass: 'gcliterm-tooltip',
eval: null,
scratchpad: null
});
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel);
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabSelect", this, false);
this._chromeWindow.getBrowser().addEventListener("load", this, true);
this._element.hidden = false;
this._notify(NOTIFICATIONS.SHOW);
if (this._pendingShowCallback) {
this._pendingShowCallback.call();
this._pendingShowCallback = undefined;
}
// If a hide event happened while we were loading, then we need to hide.
// We could make this check earlier, but then cleanup would be complex so
// we're being inefficient for now.
if (this._pendingHide) {
this.hide();
return;
}
if (!DeveloperToolbar.introShownThisSession) {
this.display.maybeShowIntro();
DeveloperToolbar.introShownThisSession = true;
}
};
/**
* Hide the developer toolbar.
*/
DeveloperToolbar.prototype.hide = function DT_hide()
{
if (this._lastState == NOTIFICATIONS.HIDE) {
return;
}
if (this._lastState == NOTIFICATIONS.LOAD) {
this._pendingHide = true;
return;
}
this._element.hidden = true;
this._doc.getElementById("Tools:DevToolbar").setAttribute("checked", "false");
this.destroy();
this._notify(NOTIFICATIONS.HIDE);
};
/**
* Hide the developer toolbar
*/
DeveloperToolbar.prototype.destroy = function DT_destroy()
{
this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabSelect", this, false);
this._chromeWindow.getBrowser().removeEventListener("load", this, true);
this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel);
this.display.destroy();
this.outputPanel.destroy();
this.tooltipPanel.destroy();
delete this._input;
// We could "delete this.display" etc if we have hard-to-track-down memory
// leaks as a belt-and-braces approach, however this prevents our DOM node
// hunter from looking in all the nooks and crannies, so it's better if we
// can be leak-free without
delete this.display;
delete this.outputPanel;
delete this.tooltipPanel;
};
/**
* Utility for sending notifications
* @param aTopic a NOTIFICATION constant
*/
DeveloperToolbar.prototype._notify = function DT_notify(aTopic)
{
this._lastState = aTopic;
let data = { toolbar: this };
data.wrappedJSObject = data;
Services.obs.notifyObservers(data, aTopic, null);
};
/**
* Update various parts of the UI when the current tab changes
* @param aEvent
*/
DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
{
if (aEvent.type == "TabSelect" || aEvent.type == "load") {
this._chromeWindow.HUDConsoleUI.refreshCommand();
this._chromeWindow.DebuggerUI.refreshCommand();
if (this.visible) {
let contentDocument = this._chromeWindow.getBrowser().contentDocument;
this.display.reattach({
contentDocument: contentDocument,
chromeWindow: this._chromeWindow,
environment: {
chromeDocument: this._doc,
contentDocument: contentDocument
},
});
}
}
};
/**
* Add class="gcli-panel-inner-arrowcontent" to a panel's
* |<xul:box class="panel-inner-arrowcontent">| so we can alter the styling
* without complex CSS expressions.
* @param aPanel The panel to affect
*/
function getContentBox(aPanel)
{
let container = aPanel.ownerDocument.getAnonymousElementByAttribute(
aPanel, "anonid", "container");
return container.querySelector(".panel-inner-arrowcontent");
}
/**
* Helper function to calculate the sum of the vertical padding and margins
* between a nested node |aNode| and an ancestor |aRoot|. Iff all of the
* children of aRoot are 'only-childs' until you get to aNode then to avoid
* scroll-bars, the 'correct' height of aRoot is verticalSpacing + aNode.height.
* @param aNode The child node whose height is known.
* @param aRoot The parent height whose height we can affect.
* @return The sum of the vertical padding/margins in between aNode and aRoot.
*/
function getVerticalSpacing(aNode, aRoot)
{
let win = aNode.ownerDocument.defaultView;
function pxToNum(styles, property) {
return parseInt(styles.getPropertyValue(property).replace(/px$/, ''), 10);
}
let vertSpacing = 0;
do {
let styles = win.getComputedStyle(aNode);
vertSpacing += pxToNum(styles, "padding-top");
vertSpacing += pxToNum(styles, "padding-bottom");
vertSpacing += pxToNum(styles, "margin-top");
vertSpacing += pxToNum(styles, "margin-bottom");
vertSpacing += pxToNum(styles, "border-top-width");
vertSpacing += pxToNum(styles, "border-bottom-width");
let prev = aNode.previousSibling;
while (prev != null) {
vertSpacing += prev.clientHeight;
prev = prev.previousSibling;
}
let next = aNode.nextSibling;
while (next != null) {
vertSpacing += next.clientHeight;
next = next.nextSibling;
}
aNode = aNode.parentNode;
} while (aNode !== aRoot);
return vertSpacing + 9;
}
/**
* Panel to handle command line output.
* @param aChromeDoc document from which we can pull the parts we need.
* @param aInput the input element that should get focus.
* @param aLoadCallback called when the panel is loaded properly.
*/
function OutputPanel(aChromeDoc, aInput, aLoadCallback)
{
this._input = aInput;
this._anchor = aChromeDoc.getElementById("developer-toolbar");
this._loadCallback = aLoadCallback;
/*
<panel id="gcli-output"
type="arrow"
noautofocus="true"
noautohide="true"
class="gcli-panel">
<iframe id="gcli-output-frame"
src="chrome://browser/content/devtools/gcliblank.xhtml"
flex="1"/>
</panel>
*/
this._panel = aChromeDoc.createElement("panel");
this._panel.id = "gcli-output";
this._panel.classList.add("gcli-panel");
this._panel.setAttribute("type", "arrow");
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("noautohide", "true");
this._anchor.parentElement.insertBefore(this._panel, this._anchor);
this._frame = aChromeDoc.createElement("iframe");
this._frame.id = "gcli-output-frame";
this._frame.setAttribute("src", "chrome://browser/content/devtools/gcliblank.xhtml");
this._frame.setAttribute("flex", "1");
this._panel.appendChild(this._frame);
this.displayedOutput = undefined;
this._onload = this._onload.bind(this);
this._frame.addEventListener("load", this._onload, true);
this.loaded = false;
}
/**
* Wire up the element from the iframe, and inform the _loadCallback.
*/
OutputPanel.prototype._onload = function OP_onload()
{
this._frame.removeEventListener("load", this._onload, true);
delete this._onload;
this._content = getContentBox(this._panel);
this._content.classList.add("gcli-panel-inner-arrowcontent");
this.document = this._frame.contentDocument;
this.document.body.classList.add("gclichrome-output");
this._div = this.document.querySelector("div");
this._div.classList.add('gcli-row-out');
this._div.setAttribute('aria-live', 'assertive');
this.loaded = true;
if (this._loadCallback) {
this._loadCallback();
delete this._loadCallback;
}
};
/**
* Display the OutputPanel.
*/
OutputPanel.prototype.show = function OP_show()
{
this._panel.ownerDocument.defaultView.setTimeout(function() {
this._resize();
}.bind(this), 0);
this._resize();
this._panel.openPopup(this._anchor, "before_end", -300, 0, false, false, null);
this._input.focus();
};
/**
* Internal helper to set the height of the output panel to fit the available
* content;
*/
OutputPanel.prototype._resize = function CLP_resize()
{
let vertSpacing = getVerticalSpacing(this._content, this._panel);
let idealHeight = this.document.body.scrollHeight + vertSpacing;
this._panel.sizeTo(400, Math.min(idealHeight, 500));
};
/**
* Called by GCLI when a command is executed.
*/
OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent)
{
if (aEvent.output.hidden) {
return;
}
this.remove();
this.displayedOutput = aEvent.output;
this.update();
this.displayedOutput.onChange.add(this.update, this);
this.displayedOutput.onClose.add(this.remove, this);
};
/**
* Called when displayed Output says it's changed or from outputChanged, which
* happens when there is a new displayed Output.
*/
OutputPanel.prototype.update = function OP_update()
{
if (this.displayedOutput.data == null) {
while (this._div.hasChildNodes()) {
this._div.removeChild(this._div.firstChild);
}
} else {
this.displayedOutput.toDom(this._div);
this.show();
}
};
/**
* Detach listeners from the currently displayed Output.
*/
OutputPanel.prototype.remove = function OP_remove()
{
this._panel.hidePopup();
if (this.displayedOutput) {
this.displayedOutput.onChange.remove(this.update, this);
this.displayedOutput.onClose.remove(this.remove, this);
delete this.displayedOutput;
}
};
/**
* Detach listeners from the currently displayed Output.
*/
OutputPanel.prototype.destroy = function OP_destroy()
{
this.remove();
this._panel.removeChild(this._frame);
this._anchor.parentElement.removeChild(this._panel);
delete this._input;
delete this._anchor;
delete this._panel;
delete this._frame;
delete this._content;
delete this._div;
delete this.document;
};
/**
* Called by GCLI to indicate that we should show or hide one either the
* tooltip panel or the output panel.
*/
OutputPanel.prototype._visibilityChanged = function OP_visibilityChanged(aEvent)
{
if (aEvent.outputVisible === true) {
// this.show is called by _outputChanged
} else {
this._panel.hidePopup();
}
};
/**
* Panel to handle tooltips.
* @param aChromeDoc document from which we can pull the parts we need.
* @param aInput the input element that should get focus.
* @param aLoadCallback called when the panel is loaded properly.
*/
function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
{
this._input = aInput;
this._anchor = aChromeDoc.getElementById("developer-toolbar");
this._onload = this._onload.bind(this);
this._loadCallback = aLoadCallback;
/*
<panel id="gcli-tooltip"
type="arrow"
noautofocus="true"
noautohide="true"
class="gcli-panel">
<iframe id="gcli-tooltip-frame"
src="chrome://browser/content/devtools/gcliblank.xhtml"
flex="1"/>
</panel>
*/
this._panel = aChromeDoc.createElement("panel");
this._panel.id = "gcli-tooltip";
this._panel.classList.add("gcli-panel");
this._panel.setAttribute("type", "arrow");
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("noautohide", "true");
this._anchor.parentElement.insertBefore(this._panel, this._anchor);
this._frame = aChromeDoc.createElement("iframe");
this._frame.id = "gcli-tooltip-frame";
this._frame.setAttribute("src", "chrome://browser/content/devtools/gcliblank.xhtml");
this._frame.setAttribute("flex", "1");
this._panel.appendChild(this._frame);
this._frame.addEventListener("load", this._onload, true);
this.loaded = false;
}
/**
* Wire up the element from the iframe, and inform the _loadCallback.
*/
TooltipPanel.prototype._onload = function TP_onload()
{
this._frame.removeEventListener("load", this._onload, true);
this._content = getContentBox(this._panel);
this._content.classList.add("gcli-panel-inner-arrowcontent");
this.document = this._frame.contentDocument;
this.document.body.classList.add("gclichrome-tooltip");
this.hintElement = this.document.querySelector("div");
this.loaded = true;
if (this._loadCallback) {
this._loadCallback();
delete this._loadCallback;
}
};
/**
* Display the TooltipPanel.
*/
TooltipPanel.prototype.show = function TP_show()
{
let vertSpacing = getVerticalSpacing(this._content, this._panel);
let idealHeight = this.document.body.scrollHeight + vertSpacing;
this._panel.sizeTo(350, Math.min(idealHeight, 500));
this._panel.openPopup(this._anchor, "before_start", 0, 0, false, false, null);
this._input.focus();
};
/**
* Hide the TooltipPanel.
*/
TooltipPanel.prototype.remove = function TP_remove()
{
this._panel.hidePopup();
};
/**
* Hide the TooltipPanel.
*/
TooltipPanel.prototype.destroy = function TP_destroy()
{
this.remove();
this._panel.removeChild(this._frame);
this._anchor.parentElement.removeChild(this._panel);
delete this._input;
delete this._onload;
delete this._panel;
delete this._frame;
delete this._anchor;
delete this._content;
delete this.document;
delete this.hintElement;
};
/**
* Called by GCLI to indicate that we should show or hide one either the
* tooltip panel or the output panel.
*/
TooltipPanel.prototype._visibilityChanged = function TP_visibilityChanged(aEvent)
{
if (aEvent.tooltipVisible === true) {
this.show();
} else {
this._panel.hidePopup();
}
};

Просмотреть файл

@ -49,11 +49,21 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_promise_basic.js \
browser_templater_basic.js \
browser_toolbar_basic.js \
browser_gcli_commands.js \
browser_gcli_inspect.js \
browser_gcli_integrate.js \
browser_gcli_require.js \
browser_gcli_web.js \
browser_gcli_break.js \
head.js \
$(NULL)
_BROWSER_TEST_PAGES = \
browser_templater_basic.html \
browser_toolbar_basic.html \
browser_gcli_inspect.html \
browser_gcli_break.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

Просмотреть файл

@ -1,8 +1,8 @@
<!DOCTYPE HTML>
<html>
<head>
<head>
<meta charset="utf-8">
<title>Browser GCLI break command test</title>
<title>Browser GCLI break command test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
@ -13,7 +13,7 @@
eval("debugger;");
}
</script>
</head>
<body>
</body>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the break command works as it should
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_break.html";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
testBreakCommands();
});
}
function testBreakCommands() {
DeveloperToolbarTest.checkInputStatus({
typed: "brea",
directTabText: "k",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "break",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "break add",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "break add line",
emptyParameters: [ " <file>", " <line>" ],
status: "ERROR"
});
let pane = DebuggerUI.toggleDebugger();
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume.
let client = pane.contentWindow.gClient;
client.addOneTimeListener("resumed", function() {
client.activeThread.addOneTimeListener("framesadded", function() {
DeveloperToolbarTest.checkInputStatus({
typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0,
status: "VALID"
});
DeveloperToolbarTest.exec({
args: {
type: 'line',
file: TEST_URI,
line: content.wrappedJSObject.line0
},
completed: false
});
DeveloperToolbarTest.checkInputStatus({
typed: "break list",
status: "VALID"
});
DeveloperToolbarTest.exec();
client.activeThread.resume(function() {
DeveloperToolbarTest.checkInputStatus({
typed: "break del 0",
status: "VALID"
});
DeveloperToolbarTest.exec({
args: { breakid: 0 },
completed: false
});
finish();
});
});
// Trigger newScript notifications using eval.
content.wrappedJSObject.firstCall();
});
}, true);
}

Просмотреть файл

@ -0,0 +1,55 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test various GCLI commands
let imported = {};
Components.utils.import("resource:///modules/HUDService.jsm", imported);
const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
testEcho();
testConsoleClear();
testConsoleOpenClose(tab);
imported = undefined;
finish();
});
}
function testEcho() {
DeveloperToolbarTest.exec({
typed: "echo message",
args: { message: "message" },
outputMatch: /^message$/,
});
}
function testConsoleClear() {
DeveloperToolbarTest.exec({
typed: "console clear",
args: {},
blankOutput: true,
});
}
function testConsoleOpenClose(tab) {
DeveloperToolbarTest.exec({
typed: "console open",
args: {},
blankOutput: true,
});
let hud = imported.HUDService.getHudByWindow(content);
ok(hud.hudId in imported.HUDService.hudReferences, "console open");
DeveloperToolbarTest.exec({
typed: "console close",
args: {},
blankOutput: true,
});
ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
}

Просмотреть файл

@ -0,0 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the inspect command works as it should
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_inspect.html";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
testInspect();
finish();
});
}
function testInspect() {
DeveloperToolbarTest.checkInputStatus({
typed: "inspec",
directTabText: "t",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect",
emptyParameters: [ " <node>" ],
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect h1",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect span",
status: "ERROR"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect div",
status: "VALID"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect .someclass",
status: "VALID"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect #someid",
status: "VALID"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect button[disabled]",
status: "VALID"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect p>strong",
status: "VALID"
});
DeveloperToolbarTest.checkInputStatus({
typed: "inspect :root",
status: "VALID"
});
}

Просмотреть файл

@ -0,0 +1,40 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that source URLs in the Web Console can be clicked to display the
// standard View Source window.
function test() {
testCreateCommands();
testRemoveCommands();
}
let tselarr = {
name: 'tselarr',
params: [
{ name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
{ name: 'arr', type: { name: 'array', subtype: 'string' } },
],
exec: function(args, env) {
return "flu " + args.num + "-" + args.arr.join("_");
}
};
function testCreateCommands() {
let gcliIndex = require("gcli/index");
gcliIndex.addCommand(tselarr);
let canon = require("gcli/canon");
let tselcmd = canon.getCommand("tselarr");
ok(tselcmd != null, "tselarr exists in the canon");
ok(tselcmd instanceof canon.Command, "canon storing commands");
}
function testRemoveCommands() {
let gcliIndex = require("gcli/index");
gcliIndex.removeCommand(tselarr);
let canon = require("gcli/canon");
let tselcmd = canon.getCommand("tselarr");
ok(tselcmd == null, "tselcmd removed from the canon");
}

Просмотреть файл

@ -1,25 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
// Tests that source URLs in the Web Console can be clicked to display the
// standard View Source window.
var modules = { gcli: null };
Components.utils.import("resource:///modules/gcli.jsm", modules);
var define, require, console;
function test() {
define = modules.gcli._internal.define;
require = modules.gcli._internal.require;
console = modules.gcli._internal.console;
define('gclitest/requirable', [], function(require, exports, module) {
exports.thing1 = 'thing1';
exports.thing2 = 2;
@ -43,8 +28,6 @@ function test() {
testRecursive();
testUncompilable();
finishTest();
delete define.modules['gclitest/requirable'];
delete define.globalDomain.modules['gclitest/requirable'];
delete define.modules['gclitest/unrequirable'];
@ -52,11 +35,7 @@ function test() {
delete define.modules['gclitest/recurse'];
delete define.globalDomain.modules['gclitest/recurse'];
define = null;
require = null;
console = null;
modules = null;
finish();
}
function testWorking() {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,35 @@
<!doctype html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<meta charset="UTF-8">
<title>Developer Toolbar Tests</title>
<style type="text/css">
#single { color: red; }
</style>
<script type="text/javascript">var a=1;</script>
</head>
<body>
<p id=single>
1
</p>
<p class=twin>
2a
</p>
<p class=twin>
2b
</p>
<style>
.twin { color: blue; }
</style>
<script>var b=2;</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the developer toolbar works properly
const URL = "http://example.com/browser/browser/devtools/shared/test/browser_toolbar_basic.html";
function test() {
addTab(URL, function(browser, tab) {
info("Starting browser_toolbar_basic.js");
runTest();
});
}
function runTest() {
Services.obs.addObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false);
// TODO: reopen the window so the pref has a chance to take effect
// EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true });
DeveloperToolbarTest.show();
}
function checkOpen() {
Services.obs.removeObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false);
ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
Services.obs.addObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false);
// EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true });
DeveloperToolbarTest.hide();
}
function checkClosed() {
Services.obs.removeObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false);
ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible");
finish();
}

Просмотреть файл

@ -36,23 +36,37 @@
*
* ***** END LICENSE BLOCK ***** */
let tab;
let browser;
let console;
let define;
let require;
let gcli;
let tempScope = {};
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
gcli = tempScope.gcli;
console = gcli._internal.console;
define = gcli._internal.define;
require = gcli._internal.require;
/**
* Open a new tab at a URL and call a callback on load
*/
function addTab(aURL, aCallback)
{
waitForExplicitFinish();
function onTabLoad() {
browser.removeEventListener("load", onTabLoad, true);
aCallback();
}
gBrowser.selectedTab = gBrowser.addTab();
content.location = aURL;
tab = gBrowser.selectedTab;
browser = gBrowser.getBrowserForTab(tab);
let tab = gBrowser.selectedTab;
let browser = gBrowser.getBrowserForTab(tab);
function onTabLoad() {
browser.removeEventListener("load", onTabLoad, true);
aCallback(browser, tab, browser.contentDocument);
}
browser.addEventListener("load", onTabLoad, true);
}
@ -62,6 +76,246 @@ registerCleanupFunction(function tearDown() {
gBrowser.removeCurrentTab();
}
tab = undefined;
browser = undefined;
console = undefined;
define = undefined;
require = undefined;
gcli = undefined;
});
/**
* Various functions for testing DeveloperToolbar
*/
let DeveloperToolbarTest = {
/**
* Paranoid DeveloperToolbar.show();
*/
show: function DTT_show(aCallback) {
if (DeveloperToolbar.visible) {
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
}
else {
DeveloperToolbar.show(aCallback);
}
},
/**
* Paranoid DeveloperToolbar.hide();
*/
hide: function DTT_hide() {
if (!DeveloperToolbar.visible) {
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
}
else {
DeveloperToolbar.display.inputter.setInput("");
DeveloperToolbar.hide();
}
},
/**
* Check that we can parse command input.
* Doesn't execute the command, just checks that we grok the input properly:
*
* DeveloperToolbarTest.checkInputStatus({
* // Test inputs
* typed: "ech", // Required
* cursor: 3, // Optional cursor position
*
* // Thing to check
* status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE"
* emptyParameters: [ "<message>" ], // Still to type
* directTabText: "o", // Simple completion text
* arrowTabText: "", // When the completion is not an extension
* });
*/
checkInputStatus: function DTT_checkInputStatus(test) {
if (test.typed) {
DeveloperToolbar.display.inputter.setInput(test.typed);
}
else {
ok(false, "Missing typed for " + JSON.stringify(test));
return;
}
if (test.cursor) {
DeveloperToolbar.display.inputter.setCursor(test.cursor)
}
if (test.status) {
is(DeveloperToolbar.display.requisition.getStatus().toString(),
test.status,
"status for " + test.typed);
}
if (test.emptyParameters == null) {
test.emptyParameters = [];
}
let completer = DeveloperToolbar.display.completer;
let realParams = completer.emptyParameters;
is(realParams.length, test.emptyParameters.length,
'emptyParameters.length for \'' + test.typed + '\'');
if (realParams.length === test.emptyParameters.length) {
for (let i = 0; i < realParams.length; i++) {
is(realParams[i].replace(/\u00a0/g, ' '), test.emptyParameters[i],
'emptyParameters[' + i + '] for \'' + test.typed + '\'');
}
}
if (test.directTabText) {
is(completer.directTabText, test.directTabText,
'directTabText for \'' + test.typed + '\'');
}
else {
is(completer.directTabText, '', 'directTabText for \'' + test.typed + '\'');
}
if (test.arrowTabText) {
is(completer.arrowTabText, ' \u00a0\u21E5 ' + test.arrowTabText,
'arrowTabText for \'' + test.typed + '\'');
}
else {
is(completer.arrowTabText, '', 'arrowTabText for \'' + test.typed + '\'');
}
},
/**
* Execute a command:
*
* DeveloperToolbarTest.exec({
* // Test inputs
* typed: "echo hi", // Optional, uses existing if undefined
*
* // Thing to check
* args: { message: "hi" }, // Check that the args were understood properly
* outputMatch: /^hi$/, // Regex to test against textContent of output
* blankOutput: true, // Special checks when there is no output
* });
*/
exec: function DTT_exec(test) {
test = test || {};
if (test.typed) {
DeveloperToolbar.display.inputter.setInput(test.typed);
}
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
let output = DeveloperToolbar.display.requisition.exec();
is(typed, output.typed, 'output.command for: ' + typed);
if (test.completed !== false) {
ok(output.completed, 'output.completed false for: ' + typed);
}
else {
// It is actually an error if we say something is async and it turns
// out not to be? For now we're saying 'no'
// ok(!output.completed, 'output.completed true for: ' + typed);
}
if (test.args != null) {
is(Object.keys(test.args).length, Object.keys(output.args).length,
'arg count for ' + typed);
Object.keys(output.args).forEach(function(arg) {
let expectedArg = test.args[arg];
let actualArg = output.args[arg];
if (Array.isArray(expectedArg)) {
if (!Array.isArray(actualArg)) {
ok(false, 'actual is not an array. ' + typed + '/' + arg);
return;
}
is(expectedArg.length, actualArg.length,
'array length: ' + typed + '/' + arg);
for (let i = 0; i < expectedArg.length; i++) {
is(expectedArg[i], actualArg[i],
'member: "' + typed + '/' + arg + '/' + i);
}
}
else {
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
}
});
}
let displayed = DeveloperToolbar.outputPanel._div.textContent;
if (test.outputMatch) {
if (!test.outputMatch.test(displayed)) {
ok(false, "html output for " + typed + " (textContent sent to info)");
info("Actual textContent");
info(displayed);
}
}
if (test.blankOutput != null) {
if (!/^$/.test(displayed)) {
ok(false, "html output for " + typed + " (textContent sent to info)");
info("Actual textContent");
info(displayed);
}
}
},
/**
* Quick wrapper around the things you need to do to run DeveloperToolbar
* command tests:
* - Set the pref 'devtools.toolbar.enabled' to true
* - Add a tab pointing at |uri|
* - Open the DeveloperToolbar
* - Register a cleanup function to undo the above
* - Run the tests
*
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
* @param testFunc A function containing the tests to run. This should
* arrange for 'finish()' to be called on completion.
*/
test: function DTT_test(uri, testFunc) {
let menuItem = document.getElementById("menu_devToolbar");
let command = document.getElementById("Tools:DevToolbar");
let appMenuItem = document.getElementById("appmenu_devToolbar");
registerCleanupFunction(function() {
DeveloperToolbarTest.hide();
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
if (menuItem) {
menuItem.hidden = true;
}
if (command) {
command.setAttribute("disabled", "true");
}
if (appMenuItem) {
appMenuItem.hidden = true;
}
});
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
if (menuItem) {
menuItem.hidden = false;
}
if (command) {
command.removeAttribute("disabled");
}
if (appMenuItem) {
appMenuItem.hidden = false;
}
addTab(uri, function(browser, tab) {
DeveloperToolbarTest.show(function() {
try {
testFunc(browser, tab);
}
catch (ex) {
ok(false, "" + ex);
console.error(ex);
finish();
throw ex;
}
});
});
},
};

Просмотреть файл

@ -438,8 +438,13 @@ Rule.prototype = {
* Reapply all the properties in this rule, and update their
* computed styles. Store disabled properties in the element
* style's store. Will re-mark overridden properties.
*
* @param {string} [aName]
* A text property name (such as "background" or "border-top") used
* when calling from setPropertyValue & setPropertyName to signify that
* the property should be saved in store.userProperties.
*/
applyProperties: function Rule_applyProperties()
applyProperties: function Rule_applyProperties(aName)
{
let disabledProps = [];
let store = this.elementStyle.store;
@ -454,7 +459,9 @@ Rule.prototype = {
continue;
}
store.userProperties.setProperty(this.style, prop.name, prop.value);
if (aName && prop.name == aName) {
store.userProperties.setProperty(this.style, prop.name, prop.value);
}
this.style.setProperty(prop.name, prop.value, prop.priority);
// Refresh the property's priority from the style, to reflect
@ -486,7 +493,7 @@ Rule.prototype = {
}
this.style.removeProperty(aProperty.name);
aProperty.name = aName;
this.applyProperties();
this.applyProperties(aName);
},
/**
@ -506,7 +513,7 @@ Rule.prototype = {
}
aProperty.value = aValue;
aProperty.priority = aPriority;
this.applyProperties();
this.applyProperties(aProperty.name);
},
/**
@ -1422,7 +1429,8 @@ TextPropertyEditor.prototype = {
this.element.classList.remove("ruleview-overridden");
}
this.nameSpan.textContent = this.prop.name;
let name = this.prop.name;
this.nameSpan.textContent = name;
// Combine the property's value and priority into one string for
// the value.
@ -1433,6 +1441,14 @@ TextPropertyEditor.prototype = {
this.valueSpan.textContent = val;
this.warning.hidden = this._validate();
let store = this.prop.rule.elementStyle.store;
let propDirty = store.userProperties.contains(this.prop.rule.style, name);
if (propDirty) {
this.element.setAttribute("dirty", "");
} else {
this.element.removeAttribute("dirty");
}
// Populate the computed styles.
this._updateComputed();
},
@ -1879,6 +1895,19 @@ UserProperties.prototype = {
this.weakMap.set(aStyle, props);
}
},
/**
* Check whether a named property for a given CSSStyleDeclaration is stored.
*
* @param {CSSStyleDeclaration} aStyle
* The CSSStyleDeclaration against which the property would be mapped.
* @param {String} aName
* The name of the property to check.
*/
contains: function UP_contains(aStyle, aName) {
let entry = this.weakMap.get(aStyle, null);
return !!entry && aName in entry;
},
};
/**

Просмотреть файл

@ -155,6 +155,12 @@ function testEditProperty()
expectChange();
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
"border-color should have been set.");
let props = ruleView.element.querySelectorAll(".ruleview-property");
for (let i = 0; i < props.length; i++) {
is(props[i].hasAttribute("dirty"), i <= 1,
"props[" + i + "] marked dirty as appropriate");
}
testDisableProperty();
});

Просмотреть файл

@ -101,11 +101,23 @@ gcli.addCommand({
name: "console close",
description: gcli.lookup("consolecloseDesc"),
exec: function Command_consoleClose(args, context) {
let tab = HUDService.getHudReferenceById(context.environment.hudId).tab;
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
HUDService.deactivateHUDForContext(tab);
}
});
/**
* 'console open' command
*/
gcli.addCommand({
name: "console open",
description: gcli.lookup("consoleopenDesc"),
exec: function Command_consoleOpen(args, context) {
let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
HUDService.activateHUDForContext(tab);
}
});
/**
* 'inspect' command
*/

Просмотреть файл

@ -0,0 +1,790 @@
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// This code is appended to the browser content script.
(function _HUDServiceContent() {
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
let tempScope = {};
Cu.import("resource://gre/modules/XPCOMUtils.jsm", tempScope);
Cu.import("resource://gre/modules/Services.jsm", tempScope);
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", tempScope);
Cu.import("resource:///modules/WebConsoleUtils.jsm", tempScope);
let XPCOMUtils = tempScope.XPCOMUtils;
let Services = tempScope.Services;
let gConsoleStorage = tempScope.ConsoleAPIStorage;
let WebConsoleUtils = tempScope.WebConsoleUtils;
let l10n = WebConsoleUtils.l10n;
tempScope = null;
let _alive = true; // Track if this content script should still be alive.
/**
* The Web Console content instance manager.
*/
let Manager = {
get window() content,
get console() this.window.console,
sandbox: null,
hudId: null,
_sequence: 0,
_messageListeners: ["WebConsole:Init", "WebConsole:EnableFeature",
"WebConsole:DisableFeature", "WebConsole:Destroy"],
_messageHandlers: null,
_enabledFeatures: null,
/**
* Getter for a unique ID for the current Web Console content instance.
*/
get sequenceId() "HUDContent-" + (++this._sequence),
/**
* Initialize the Web Console manager.
*/
init: function Manager_init()
{
this._enabledFeatures = [];
this._messageHandlers = {};
this._messageListeners.forEach(function(aName) {
addMessageListener(aName, this);
}, this);
// Need to track the owner XUL window to listen to the unload and TabClose
// events, to avoid memory leaks.
let xulWindow = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler.ownerDocument.defaultView;
xulWindow.addEventListener("unload", this._onXULWindowClose, false);
let tabContainer = xulWindow.gBrowser.tabContainer;
tabContainer.addEventListener("TabClose", this._onTabClose, false);
// Need to track private browsing change and quit application notifications,
// again to avoid memory leaks. The Web Console main process cannot notify
// this content script when the XUL window close, tab close, private
// browsing change and quit application events happen, so we must call
// Manager.destroy() on our own.
Services.obs.addObserver(this, "private-browsing-change-granted", false);
Services.obs.addObserver(this, "quit-application-granted", false);
},
/**
* The message handler. This method forwards all the remote messages to the
* appropriate code.
*/
receiveMessage: function Manager_receiveMessage(aMessage)
{
if (!_alive) {
return;
}
if (!aMessage.json || (aMessage.name != "WebConsole:Init" &&
aMessage.json.hudId != this.hudId)) {
Cu.reportError("Web Console content script: received message " +
aMessage.name + " from wrong hudId!");
return;
}
switch (aMessage.name) {
case "WebConsole:Init":
this._onInit(aMessage.json);
break;
case "WebConsole:EnableFeature":
this.enableFeature(aMessage.json.feature, aMessage.json);
break;
case "WebConsole:DisableFeature":
this.disableFeature(aMessage.json.feature);
break;
case "WebConsole:Destroy":
this.destroy();
break;
default: {
let handler = this._messageHandlers[aMessage.name];
handler && handler(aMessage.json);
break;
}
}
},
/**
* Observe notifications from the nsIObserverService.
*
* @param mixed aSubject
* @param string aTopic
* @param mixed aData
*/
observe: function Manager_observe(aSubject, aTopic, aData)
{
if (_alive && (aTopic == "quit-application-granted" ||
(aTopic == "private-browsing-change-granted" &&
(aData == "enter" || aData == "exit")))) {
this.destroy();
}
},
/**
* The manager initialization code. This method is called when the Web Console
* remote process initializes the content process (this code!).
*
* @param object aMessage
* The object received from the remote process. The WebConsole:Init
* message properties:
* - hudId - (required) the remote Web Console instance ID.
* - features - (optional) array of features you want to enable from
* the start. For each feature you enable you can pass feature-specific
* options in a property on the JSON object you send with the same name
* as the feature. See this.enableFeature() for the list of available
* features.
* - cachedMessages - (optional) an array of cached messages you want
* to receive. See this._sendCachedMessages() for the list of available
* message types.
*
* Example message:
* {
* hudId: "foo1",
* features: ["JSTerm", "ConsoleAPI"],
* ConsoleAPI: { ... }, // ConsoleAPI-specific options
* cachedMessages: ["ConsoleAPI"],
* }
*/
_onInit: function Manager_onInit(aMessage)
{
this.hudId = aMessage.hudId;
if (aMessage.features) {
aMessage.features.forEach(function(aFeature) {
this.enableFeature(aFeature, aMessage[aFeature]);
}, this);
}
if (aMessage.cachedMessages) {
this._sendCachedMessages(aMessage.cachedMessages);
}
},
/**
* Add a remote message handler. This is used by other components of the Web
* Console content script.
*
* @param string aName
* Message name to listen for.
* @param function aCallback
* Function to execute when the message is received. This function is
* given the JSON object that came from the remote Web Console
* instance.
* Only one callback per message name is allowed!
*/
addMessageHandler: function Manager_addMessageHandler(aName, aCallback)
{
if (aName in this._messageHandlers) {
Cu.reportError("Web Console content script: addMessageHandler() called for an existing message handler: " + aName);
return;
}
this._messageHandlers[aName] = aCallback;
addMessageListener(aName, this);
},
/**
* Remove the message handler for the given name.
*
* @param string aName
* Message name for the handler you want removed.
*/
removeMessageHandler: function Manager_removeMessageHandler(aName)
{
if (!(aName in this._messageHandlers)) {
return;
}
delete this._messageHandlers[aName];
removeMessageListener(aName, this);
},
/**
* Send a message to the remote Web Console instance.
*
* @param string aName
* The name of the message you want to send.
* @param object aMessage
* The message object you want to send.
*/
sendMessage: function Manager_sendMessage(aName, aMessage)
{
aMessage.hudId = this.hudId;
if (!("id" in aMessage)) {
aMessage.id = this.sequenceId;
}
sendAsyncMessage(aName, aMessage);
},
/**
* Enable a feature in the Web Console content script. A feature is generally
* a set of observers/listeners that are added in the content process. This
* content script exposes the data via the message manager for the features
* you enable.
*
* Supported features:
* - JSTerm - a JavaScript "terminal" which allows code execution.
* - ConsoleAPI - support for routing the window.console API to the remote
* process.
* - PageError - route all the nsIScriptErrors from the nsIConsoleService
* to the remote process.
*
* @param string aFeature
* One of the supported features: JSTerm, ConsoleAPI.
* @param object [aMessage]
* Optional JSON message object coming from the remote Web Console
* instance. This can be used for feature-specific options.
*/
enableFeature: function Manager_enableFeature(aFeature, aMessage)
{
if (this._enabledFeatures.indexOf(aFeature) != -1) {
return;
}
switch (aFeature) {
case "JSTerm":
JSTerm.init(aMessage);
break;
case "ConsoleAPI":
ConsoleAPIObserver.init(aMessage);
break;
case "PageError":
ConsoleListener.init(aMessage);
break;
default:
Cu.reportError("Web Console content: unknown feature " + aFeature);
break;
}
this._enabledFeatures.push(aFeature);
},
/**
* Disable a Web Console content script feature.
*
* @see this.enableFeature
* @param string aFeature
* One of the supported features - see this.enableFeature() for the
* list of supported features.
*/
disableFeature: function Manager_disableFeature(aFeature)
{
let index = this._enabledFeatures.indexOf(aFeature);
if (index == -1) {
return;
}
this._enabledFeatures.splice(index, 1);
switch (aFeature) {
case "JSTerm":
JSTerm.destroy();
break;
case "ConsoleAPI":
ConsoleAPIObserver.destroy();
break;
case "PageError":
ConsoleListener.destroy();
break;
default:
Cu.reportError("Web Console content: unknown feature " + aFeature);
break;
}
},
/**
* Send the cached messages to the remote Web Console instance.
*
* @private
* @param array aMessageTypes
* An array that lists which kinds of messages you want. Supported
* message types: "ConsoleAPI" and "PageError".
*/
_sendCachedMessages: function Manager__sendCachedMessages(aMessageTypes)
{
let messages = [];
while (aMessageTypes.length > 0) {
switch (aMessageTypes.shift()) {
case "ConsoleAPI":
messages.push.apply(messages, ConsoleAPIObserver.getCachedMessages());
break;
case "PageError":
messages.push.apply(messages, ConsoleListener.getCachedMessages());
break;
}
}
messages.sort(function(a, b) { return a.timeStamp - b.timeStamp; });
this.sendMessage("WebConsole:CachedMessages", {messages: messages});
},
/**
* The XUL window "unload" event handler which destroys this content script
* instance.
* @private
*/
_onXULWindowClose: function Manager__onXULWindowClose()
{
if (_alive) {
Manager.destroy();
}
},
/**
* The "TabClose" event handler which destroys this content script
* instance, if needed.
* @private
*/
_onTabClose: function Manager__onTabClose(aEvent)
{
let tab = aEvent.target;
if (_alive && tab.linkedBrowser.contentWindow === Manager.window) {
Manager.destroy();
}
},
/**
* Destroy the Web Console content script instance.
*/
destroy: function Manager_destroy()
{
Services.obs.removeObserver(this, "private-browsing-change-granted");
Services.obs.removeObserver(this, "quit-application-granted");
_alive = false;
let xulWindow = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler.ownerDocument.defaultView;
xulWindow.removeEventListener("unload", this._onXULWindowClose, false);
let tabContainer = xulWindow.gBrowser.tabContainer;
tabContainer.removeEventListener("TabClose", this._onTabClose, false);
this._messageListeners.forEach(function(aName) {
removeMessageListener(aName, this);
}, this);
this._enabledFeatures.slice().forEach(this.disableFeature, this);
this.hudId = null;
this._messageHandlers = null;
Manager = ConsoleAPIObserver = JSTerm = ConsoleListener = null;
Cc = Ci = Cu = XPCOMUtils = Services = gConsoleStorage =
WebConsoleUtils = l10n = null;
},
};
/**
* The JavaScript terminal is meant to allow remote code execution for the Web
* Console.
*/
let JSTerm = {
/**
* Evaluation result objects are cached in this object. The chrome process can
* request any object based on its ID.
*/
_objectCache: null,
/**
* Initialize the JavaScript terminal feature.
*/
init: function JST_init()
{
this._objectCache = {};
Manager.addMessageHandler("JSTerm:GetEvalObject",
this.handleGetEvalObject.bind(this));
Manager.addMessageHandler("JSTerm:ClearObjectCache",
this.handleClearObjectCache.bind(this));
},
/**
* Handler for the remote "JSTerm:GetEvalObject" message. This allows the
* remote Web Console instance to retrieve an object from the content process.
*
* @param object aRequest
* The message that requests the content object. Properties: cacheId,
* objectId and resultCacheId.
*
* Evaluated objects are stored in "buckets" (cache IDs). Each object
* is assigned an ID (object ID). You can request a specific object
* (objectId) from a specific cache (cacheId) and tell where the result
* should be cached (resultCacheId). The requested object can have
* further references to other objects - those references will be
* cached in the "bucket" of your choice (based on resultCacheId). If
* you do not provide any resultCacheId in the request message, then
* cacheId will be used.
*/
handleGetEvalObject: function JST_handleGetEvalObject(aRequest)
{
if (aRequest.cacheId in this._objectCache &&
aRequest.objectId in this._objectCache[aRequest.cacheId]) {
let object = this._objectCache[aRequest.cacheId][aRequest.objectId];
let resultCacheId = aRequest.resultCacheId || aRequest.cacheId;
let message = {
id: aRequest.id,
cacheId: aRequest.cacheId,
objectId: aRequest.objectId,
object: this.prepareObjectForRemote(object, resultCacheId),
childrenCacheId: resultCacheId,
};
Manager.sendMessage("JSTerm:EvalObject", message);
}
else {
Cu.reportError("JSTerm:GetEvalObject request " + aRequest.id +
": stale object.");
}
},
/**
* Handler for the remote "JSTerm:ClearObjectCache" message. This allows the
* remote Web Console instance to clear the cache of objects that it no longer
* uses.
*
* @param object aRequest
* An object that holds one property: the cacheId you want cleared.
*/
handleClearObjectCache: function JST_handleClearObjectCache(aRequest)
{
if (aRequest.cacheId in this._objectCache) {
delete this._objectCache[aRequest.cacheId];
}
},
/**
* Prepare an object to be sent to the remote Web Console instance.
*
* @param object aObject
* The object you want to send to the remote Web Console instance.
* @param number aCacheId
* Cache ID where you want object references to be stored into. The
* given object may include references to other objects - those
* references will be stored in the given cache ID so the remote
* process can later retrieve them as well.
* @return array
* An array that holds one element for each enumerable property and
* method in aObject. Each element describes the property. For details
* see WebConsoleUtils.namesAndValuesOf().
*/
prepareObjectForRemote:
function JST_prepareObjectForRemote(aObject, aCacheId)
{
// Cache the properties that have inspectable values.
let propCache = this._objectCache[aCacheId] || {};
let result = WebConsoleUtils.namesAndValuesOf(aObject, propCache);
if (!(aCacheId in this._objectCache) && Object.keys(propCache).length > 0) {
this._objectCache[aCacheId] = propCache;
}
return result;
},
/**
* Destroy the JSTerm instance.
*/
destroy: function JST_destroy()
{
Manager.removeMessageHandler("JSTerm:GetEvalObject");
Manager.removeMessageHandler("JSTerm:ClearObjectCache");
delete this._objectCache;
},
};
/**
* The window.console API observer. This allows the window.console API messages
* to be sent to the remote Web Console instance.
*/
let ConsoleAPIObserver = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
/**
* Initialize the window.console API observer.
*/
init: function CAO_init()
{
// Note that the observer is process-wide. We will filter the messages as
// needed, see CAO_observe().
Services.obs.addObserver(this, "console-api-log-event", false);
Manager.addMessageHandler("ConsoleAPI:ClearCache",
this.handleClearCache.bind(this));
},
/**
* The console API message observer. When messages are received from the
* observer service we forward them to the remote Web Console instance.
*
* @param object aMessage
* The message object receives from the observer service.
* @param string aTopic
* The message topic received from the observer service.
*/
observe: function CAO_observe(aMessage, aTopic)
{
if (!_alive || !aMessage || aTopic != "console-api-log-event") {
return;
}
let apiMessage = aMessage.wrappedJSObject;
let msgWindow =
WebConsoleUtils.getWindowByOuterId(apiMessage.ID, Manager.window);
if (!msgWindow || msgWindow.top != Manager.window) {
// Not the same window!
return;
}
let messageToChrome = {};
this._prepareApiMessageForRemote(apiMessage, messageToChrome);
Manager.sendMessage("WebConsole:ConsoleAPI", messageToChrome);
},
/**
* Prepare a message from the console APi to be sent to the remote Web Console
* instance.
*
* @param object aOriginalMessage
* The original message received from console-api-log-event.
* @param object aRemoteMessage
* The object you want to send to the remote Web Console. This object
* is updated to hold information from the original message. New
* properties added:
* - timeStamp
* Message timestamp (same as the aOriginalMessage.timeStamp property).
* - apiMessage
* An object that copies almost all the properties from
* aOriginalMessage. Arguments might be skipped if it holds references
* to objects that cannot be sent as they are to the remote Web Console
* instance.
* - argumentsToString
* Optional: the aOriginalMessage.arguments object stringified.
*
* The apiMessage.arguments property is set to hold data appropriate
* to the message level. A similar approach is used for
* argumentsToString.
*/
_prepareApiMessageForRemote:
function CAO__prepareApiMessageForRemote(aOriginalMessage, aRemoteMessage)
{
aRemoteMessage.apiMessage =
WebConsoleUtils.cloneObject(aOriginalMessage, true,
function(aKey, aValue, aObject) {
// We need to skip the arguments property from the original object.
if (aKey == "wrappedJSObject" || aObject === aOriginalMessage &&
aKey == "arguments") {
return false;
}
return true;
});
aRemoteMessage.timeStamp = aOriginalMessage.timeStamp;
switch (aOriginalMessage.level) {
case "trace":
case "time":
case "timeEnd":
case "group":
case "groupCollapsed":
aRemoteMessage.apiMessage.arguments =
WebConsoleUtils.cloneObject(aOriginalMessage.arguments, true);
break;
case "log":
case "info":
case "warn":
case "error":
case "debug":
case "groupEnd":
aRemoteMessage.argumentsToString =
Array.map(aOriginalMessage.arguments || [],
this._formatObject.bind(this));
break;
case "dir": {
aRemoteMessage.objectsCacheId = Manager.sequenceId;
aRemoteMessage.argumentsToString = [];
let mapFunction = function(aItem) {
aRemoteMessage.argumentsToString.push(this._formatObject(aItem));
if (WebConsoleUtils.isObjectInspectable(aItem)) {
return JSTerm.prepareObjectForRemote(aItem,
aRemoteMessage.objectsCacheId);
}
return aItem;
}.bind(this);
aRemoteMessage.apiMessage.arguments =
Array.map(aOriginalMessage.arguments || [], mapFunction);
break;
}
default:
Cu.reportError("Unknown Console API log level: " +
aOriginalMessage.level);
break;
}
},
/**
* Format an object's value to be displayed in the Web Console.
*
* @private
* @param object aObject
* The object you want to display.
* @return string
* The string you can display for the given object.
*/
_formatObject: function CAO__formatObject(aObject)
{
return typeof aObject == "string" ?
aObject : WebConsoleUtils.formatResult(aObject);
},
/**
* Get the cached messages for the current inner window.
*
* @see this._prepareApiMessageForRemote()
* @return array
* The array of cached messages. Each element is a Console API
* prepared to be sent to the remote Web Console instance.
*/
getCachedMessages: function CAO_getCachedMessages()
{
let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
let messages = gConsoleStorage.getEvents(innerWindowId);
let result = messages.map(function(aMessage) {
let remoteMessage = { _type: "ConsoleAPI" };
this._prepareApiMessageForRemote(aMessage.wrappedJSObject, remoteMessage);
return remoteMessage;
}, this);
return result;
},
/**
* Handler for the "ConsoleAPI:ClearCache" message.
*/
handleClearCache: function CAO_handleClearCache()
{
let windowId = WebConsoleUtils.getInnerWindowId(Manager.window);
gConsoleStorage.clearEvents(windowId);
},
/**
* Destroy the ConsoleAPIObserver listeners.
*/
destroy: function CAO_destroy()
{
Manager.removeMessageHandler("ConsoleAPI:ClearCache");
Services.obs.removeObserver(this, "console-api-log-event");
},
};
/**
* The nsIConsoleService listener. This is used to send all the page errors
* (JavaScript, CSS and more) to the remote Web Console instance.
*/
let ConsoleListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
/**
* Initialize the nsIConsoleService listener.
*/
init: function CL_init()
{
Services.console.registerListener(this);
},
/**
* The nsIConsoleService observer. This method takes all the script error
* messages belonging to the current window and sends them to the remote Web
* Console instance.
*
* @param nsIScriptError aScriptError
* The script error object coming from the nsIConsoleService.
*/
observe: function CL_observe(aScriptError)
{
if (!_alive || !(aScriptError instanceof Ci.nsIScriptError) ||
!aScriptError.outerWindowID) {
return;
}
switch (aScriptError.category) {
// We ignore chrome-originating errors as we only care about content.
case "XPConnect JavaScript":
case "component javascript":
case "chrome javascript":
case "chrome registration":
case "XBL":
case "XBL Prototype Handler":
case "XBL Content Sink":
case "xbl javascript":
return;
}
let errorWindow =
WebConsoleUtils.getWindowByOuterId(aScriptError.outerWindowID,
Manager.window);
if (!errorWindow || errorWindow.top != Manager.window) {
return;
}
Manager.sendMessage("WebConsole:PageError", { pageError: aScriptError });
},
/**
* Get the cached page errors for the current inner window.
*
* @return array
* The array of cached messages. Each element is an nsIScriptError
* with an added _type property so the remote Web Console instance can
* tell the difference between various types of cached messages.
*/
getCachedMessages: function CL_getCachedMessages()
{
let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
let result = [];
let errors = {};
Services.console.getMessageArray(errors, {});
(errors.value || []).forEach(function(aError) {
if (!(aError instanceof Ci.nsIScriptError) ||
aError.innerWindowID != innerWindowId) {
return;
}
let remoteMessage = WebConsoleUtils.cloneObject(aError);
remoteMessage._type = "PageError";
result.push(remoteMessage);
});
return result;
},
/**
* Remove the nsIConsoleService listener.
*/
destroy: function CL_destroy()
{
Services.console.unregisterListener(this);
},
};
Manager.init();
})();

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -46,8 +46,10 @@ include $(DEPTH)/config/autoconf.mk
EXTRA_JS_MODULES = \
PropertyPanel.jsm \
PropertyPanelAsync.jsm \
NetworkHelper.jsm \
AutocompletePopup.jsm \
WebConsoleUtils.jsm \
gcli.jsm \
GcliCommands.jsm \
GcliTiltCommands.jsm \

Просмотреть файл

@ -0,0 +1,466 @@
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "WebConsoleUtils", function () {
let obj = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", obj);
return obj.WebConsoleUtils;
});
var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView"];
///////////////////////////////////////////////////////////////////////////
//// PropertyTreeView.
/**
* This is an implementation of the nsITreeView interface. For comments on the
* interface properties, see the documentation:
* https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsITreeView
*/
var PropertyTreeView = function() {
this._rows = [];
this._objectCache = {};
};
PropertyTreeView.prototype = {
/**
* Stores the visible rows of the tree.
* @private
*/
_rows: null,
/**
* Stores the nsITreeBoxObject for this tree.
* @private
*/
_treeBox: null,
/**
* Stores cached information about local objects being inspected.
* @private
*/
_objectCache: null,
/**
* Use this setter to update the content of the tree.
*
* @param object aObject
* An object that holds information about the object you want to
* display in the property panel. Object properties:
* - object:
* This is the raw object you want to display. You can only provide
* this object if you want the property panel to work in sync mode.
* - remoteObject:
* An array that holds information on the remote object being
* inspected. Each element in this array describes each property in the
* remote object. See WebConsoleUtils.namesAndValuesOf() for details.
* - rootCacheId:
* The cache ID where the objects referenced in remoteObject are found.
* - panelCacheId:
* The cache ID where any object retrieved by this property panel
* instance should be stored into.
* - remoteObjectProvider:
* A function that is invoked when a new object is needed. This is
* called when the user tries to expand an inspectable property. The
* callback must take four arguments:
* - fromCacheId:
* Tells from where to retrieve the object the user picked (from
* which cache ID).
* - objectId:
* The object ID the user wants.
* - panelCacheId:
* Tells in which cache ID to store the objects referenced by
* objectId so they can be retrieved later.
* - callback:
* The callback function to be invoked when the remote object is
* received. This function takes one argument: the raw message
* received from the Web Console content script.
*/
set data(aData) {
let oldLen = this._rows.length;
this._cleanup();
if (!aData) {
return;
}
if (aData.remoteObject) {
this._rootCacheId = aData.rootCacheId;
this._panelCacheId = aData.panelCacheId;
this._remoteObjectProvider = aData.remoteObjectProvider;
this._rows = [].concat(aData.remoteObject);
this._updateRemoteObject(this._rows, 0);
}
else if (aData.object) {
this._rows = this._inspectObject(aData.object);
}
else {
throw new Error("First argument must have a .remoteObject or " +
"an .object property!");
}
if (this._treeBox) {
this._treeBox.beginUpdateBatch();
if (oldLen) {
this._treeBox.rowCountChanged(0, -oldLen);
}
this._treeBox.rowCountChanged(0, this._rows.length);
this._treeBox.endUpdateBatch();
}
},
/**
* Update a remote object so it can be used with the tree view. This method
* adds properties to each array element.
*
* @private
* @param array aObject
* The remote object you want prepared for use with the tree view.
* @param number aLevel
* The level you want to give to each property in the remote object.
*/
_updateRemoteObject: function PTV__updateRemoteObject(aObject, aLevel)
{
aObject.forEach(function(aElement) {
aElement.level = aLevel;
aElement.isOpened = false;
aElement.children = null;
});
},
/**
* Inspect a local object.
*
* @private
* @param object aObject
* The object you want to inspect.
*/
_inspectObject: function PTV__inspectObject(aObject)
{
this._objectCache = {};
this._remoteObjectProvider = this._localObjectProvider.bind(this);
let children = WebConsoleUtils.namesAndValuesOf(aObject, this._objectCache);
this._updateRemoteObject(children, 0);
return children;
},
/**
* An object provider for when the user inspects local objects (not remote
* ones).
*
* @private
* @param string aFromCacheId
* The cache ID from where to retrieve the desired object.
* @param string aObjectId
* The ID of the object you want.
* @param string aDestCacheId
* The ID of the cache where to store any objects referenced by the
* desired object.
* @param function aCallback
* The function you want to receive the object.
*/
_localObjectProvider:
function PTV__localObjectProvider(aFromCacheId, aObjectId, aDestCacheId,
aCallback)
{
let object = WebConsoleUtils.namesAndValuesOf(this._objectCache[aObjectId],
this._objectCache);
aCallback({cacheId: aFromCacheId,
objectId: aObjectId,
object: object,
childrenCacheId: aDestCacheId || aFromCacheId,
});
},
/** nsITreeView interface implementation **/
selection: null,
get rowCount() { return this._rows.length; },
setTree: function(treeBox) { this._treeBox = treeBox; },
getCellText: function(idx, column) {
let row = this._rows[idx];
return row.name + ": " + row.value;
},
getLevel: function(idx) {
return this._rows[idx].level;
},
isContainer: function(idx) {
return !!this._rows[idx].inspectable;
},
isContainerOpen: function(idx) {
return this._rows[idx].isOpened;
},
isContainerEmpty: function(idx) { return false; },
isSeparator: function(idx) { return false; },
isSorted: function() { return false; },
isEditable: function(idx, column) { return false; },
isSelectable: function(row, col) { return true; },
getParentIndex: function(idx)
{
if (this.getLevel(idx) == 0) {
return -1;
}
for (var t = idx - 1; t >= 0; t--) {
if (this.isContainer(t)) {
return t;
}
}
return -1;
},
hasNextSibling: function(idx, after)
{
var thisLevel = this.getLevel(idx);
return this._rows.slice(after + 1).some(function (r) r.level == thisLevel);
},
toggleOpenState: function(idx)
{
let item = this._rows[idx];
if (!item.inspectable) {
return;
}
if (item.isOpened) {
this._treeBox.beginUpdateBatch();
item.isOpened = false;
var thisLevel = item.level;
var t = idx + 1, deleteCount = 0;
while (t < this._rows.length && this.getLevel(t++) > thisLevel) {
deleteCount++;
}
if (deleteCount) {
this._rows.splice(idx + 1, deleteCount);
this._treeBox.rowCountChanged(idx + 1, -deleteCount);
}
this._treeBox.invalidateRow(idx);
this._treeBox.endUpdateBatch();
}
else {
let levelUpdate = true;
let callback = function _onRemoteResponse(aResponse) {
this._treeBox.beginUpdateBatch();
item.isOpened = true;
if (levelUpdate) {
this._updateRemoteObject(aResponse.object, item.level + 1);
item.children = aResponse.object;
}
this._rows.splice.apply(this._rows, [idx + 1, 0].concat(item.children));
this._treeBox.rowCountChanged(idx + 1, item.children.length);
this._treeBox.invalidateRow(idx);
this._treeBox.endUpdateBatch();
}.bind(this);
if (!item.children) {
let fromCacheId = item.level > 0 ? this._panelCacheId :
this._rootCacheId;
this._remoteObjectProvider(fromCacheId, item.objectId,
this._panelCacheId, callback);
}
else {
levelUpdate = false;
callback({object: item.children});
}
}
},
getImageSrc: function(idx, column) { },
getProgressMode : function(idx,column) { },
getCellValue: function(idx, column) { },
cycleHeader: function(col, elem) { },
selectionChanged: function() { },
cycleCell: function(idx, column) { },
performAction: function(action) { },
performActionOnCell: function(action, index, column) { },
performActionOnRow: function(action, row) { },
getRowProperties: function(idx, column, prop) { },
getCellProperties: function(idx, column, prop) { },
getColumnProperties: function(column, element, prop) { },
setCellValue: function(row, col, value) { },
setCellText: function(row, col, value) { },
drop: function(index, orientation, dataTransfer) { },
canDrop: function(index, orientation, dataTransfer) { return false; },
_cleanup: function PTV__cleanup()
{
if (this._rows.length) {
// Reset the existing _rows children to the initial state.
this._updateRemoteObject(this._rows, 0);
this._rows = [];
}
delete this._objectCache;
delete this._rootCacheId;
delete this._panelCacheId;
delete this._remoteObjectProvider;
},
};
///////////////////////////////////////////////////////////////////////////
//// Helper for creating the panel.
/**
* Creates a DOMNode and sets all the attributes of aAttributes on the created
* element.
*
* @param nsIDOMDocument aDocument
* Document to create the new DOMNode.
* @param string aTag
* Name of the tag for the DOMNode.
* @param object aAttributes
* Attributes set on the created DOMNode.
* @returns nsIDOMNode
*/
function createElement(aDocument, aTag, aAttributes)
{
let node = aDocument.createElement(aTag);
for (var attr in aAttributes) {
node.setAttribute(attr, aAttributes[attr]);
}
return node;
}
/**
* Creates a new DOMNode and appends it to aParent.
*
* @param nsIDOMDocument aDocument
* Document to create the new DOMNode.
* @param nsIDOMNode aParent
* A parent node to append the created element.
* @param string aTag
* Name of the tag for the DOMNode.
* @param object aAttributes
* Attributes set on the created DOMNode.
* @returns nsIDOMNode
*/
function appendChild(aDocument, aParent, aTag, aAttributes)
{
let node = createElement(aDocument, aTag, aAttributes);
aParent.appendChild(node);
return node;
}
///////////////////////////////////////////////////////////////////////////
//// PropertyPanel
/**
* Creates a new PropertyPanel.
*
* @see PropertyTreeView
* @param nsIDOMNode aParent
* Parent node to append the created panel to.
* @param string aTitle
* Title for the panel.
* @param string aObject
* Object to display in the tree. For details about this object please
* see the PropertyTreeView.data property in this file.
* @param array of objects aButtons
* Array with buttons to display at the bottom of the panel.
*/
function PropertyPanel(aParent, aTitle, aObject, aButtons)
{
let document = aParent.ownerDocument;
// Create the underlying panel
this.panel = createElement(document, "panel", {
label: aTitle,
titlebar: "normal",
noautofocus: "true",
noautohide: "true",
close: "true",
});
// Create the tree.
let tree = this.tree = createElement(document, "tree", {
flex: 1,
hidecolumnpicker: "true"
});
let treecols = document.createElement("treecols");
appendChild(document, treecols, "treecol", {
primary: "true",
flex: 1,
hideheader: "true",
ignoreincolumnpicker: "true"
});
tree.appendChild(treecols);
tree.appendChild(document.createElement("treechildren"));
this.panel.appendChild(tree);
// Create the footer.
let footer = createElement(document, "hbox", { align: "end" });
appendChild(document, footer, "spacer", { flex: 1 });
// The footer can have butttons.
let self = this;
if (aButtons) {
aButtons.forEach(function(button) {
let buttonNode = appendChild(document, footer, "button", {
label: button.label,
accesskey: button.accesskey || "",
class: button.class || "",
});
buttonNode.addEventListener("command", button.oncommand, false);
});
}
appendChild(document, footer, "resizer", { dir: "bottomend" });
this.panel.appendChild(footer);
aParent.appendChild(this.panel);
// Create the treeView object.
this.treeView = new PropertyTreeView();
this.treeView.data = aObject;
// Set the treeView object on the tree view. This has to be done *after* the
// panel is shown. This is because the tree binding must be attached first.
this.panel.addEventListener("popupshown", function onPopupShow()
{
self.panel.removeEventListener("popupshown", onPopupShow, false);
self.tree.view = self.treeView;
}, false);
this.panel.addEventListener("popuphidden", function onPopupHide()
{
self.panel.removeEventListener("popuphidden", onPopupHide, false);
self.destroy();
}, false);
}
/**
* Destroy the PropertyPanel. This closes the panel and removes it from the
* browser DOM.
*/
PropertyPanel.prototype.destroy = function PP_destroy()
{
this.treeView.data = null;
this.panel.parentNode.removeChild(this.panel);
this.treeView = null;
this.panel = null;
this.tree = null;
}

Просмотреть файл

@ -0,0 +1,706 @@
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["WebConsoleUtils"];
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
const TYPES = { OBJECT: 0,
FUNCTION: 1,
ARRAY: 2,
OTHER: 3,
ITERATOR: 4,
GETTER: 5,
GENERATOR: 6,
STRING: 7
};
var gObjectId = 0;
var WebConsoleUtils = {
TYPES: TYPES,
/**
* Convenience function to unwrap a wrapped object.
*
* @param aObject the object to unwrap.
* @return aObject unwrapped.
*/
unwrap: function WCU_unwrap(aObject)
{
try {
return XPCNativeWrapper.unwrap(aObject);
}
catch (ex) {
return aObject;
}
},
/**
* Wrap a string in an nsISupportsString object.
*
* @param string aString
* @return nsISupportsString
*/
supportsString: function WCU_supportsString(aString)
{
let str = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
str.data = aString;
return str;
},
/**
* Clone an object.
*
* @param object aObject
* The object you want cloned.
* @param boolean aRecursive
* Tells if you want to dig deeper into the object, to clone
* recursively.
* @param function [aFilter]
* Optional, filter function, called for every property. Three
* arguments are passed: key, value and object. Return true if the
* property should be added to the cloned object. Return false to skip
* the property.
* @return object
* The cloned object.
*/
cloneObject: function WCU_cloneObject(aObject, aRecursive, aFilter)
{
if (typeof aObject != "object") {
return aObject;
}
let temp;
if (Array.isArray(aObject)) {
temp = [];
Array.forEach(aObject, function(aValue, aIndex) {
if (!aFilter || aFilter(aIndex, aValue, aObject)) {
temp.push(aRecursive ? WCU_cloneObject(aValue) : aValue);
}
});
}
else {
temp = {};
for (let key in aObject) {
let value = aObject[key];
if (aObject.hasOwnProperty(key) &&
(!aFilter || aFilter(key, value, aObject))) {
temp[key] = aRecursive ? WCU_cloneObject(value) : value;
}
}
}
return temp;
},
/**
* Gets the ID of the inner window of this DOM window.
*
* @param nsIDOMWindow aWindow
* @return integer
* Inner ID for the given aWindow.
*/
getInnerWindowId: function WCU_getInnerWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
},
/**
* Gets the ID of the outer window of this DOM window.
*
* @param nsIDOMWindow aWindow
* @return integer
* Outer ID for the given aWindow.
*/
getOuterWindowId: function WCU_getOuterWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
},
/**
* Gets the window that has the given outer ID.
*
* @param integer aOuterId
* @param nsIDOMWindow [aHintWindow]
* Optional, the window object used to QueryInterface to
* nsIDOMWindowUtils. If this is not given,
* Services.wm.getMostRecentWindow() is used.
* @return nsIDOMWindow|null
* The window object with the given outer ID.
*/
getWindowByOuterId: function WCU_getWindowByOuterId(aOuterId, aHintWindow)
{
let someWindow = aHintWindow || Services.wm.getMostRecentWindow(null);
let content = null;
if (someWindow) {
let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
content = windowUtils.getOuterWindowWithId(aOuterId);
}
return content;
},
/**
* Gets the window that has the given inner ID.
*
* @param integer aInnerId
* @param nsIDOMWindow [aHintWindow]
* Optional, the window object used to QueryInterface to
* nsIDOMWindowUtils. If this is not given,
* Services.wm.getMostRecentWindow() is used.
* @return nsIDOMWindow|null
* The window object with the given inner ID.
*/
getWindowByInnerId: function WCU_getWindowByInnerId(aInnerId, aHintWindow)
{
let someWindow = aHintWindow || Services.wm.getMostRecentWindow(null);
let content = null;
if (someWindow) {
let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
content = windowUtils.getInnerWindowWithId(aInnerId);
}
return content;
},
/**
* Abbreviates the given source URL so that it can be displayed flush-right
* without being too distracting.
*
* @param string aSourceURL
* The source URL to shorten.
* @return string
* The abbreviated form of the source URL.
*/
abbreviateSourceURL: function WCU_abbreviateSourceURL(aSourceURL)
{
// Remove any query parameters.
let hookIndex = aSourceURL.indexOf("?");
if (hookIndex > -1) {
aSourceURL = aSourceURL.substring(0, hookIndex);
}
// Remove a trailing "/".
if (aSourceURL[aSourceURL.length - 1] == "/") {
aSourceURL = aSourceURL.substring(0, aSourceURL.length - 1);
}
// Remove all but the last path component.
let slashIndex = aSourceURL.lastIndexOf("/");
if (slashIndex > -1) {
aSourceURL = aSourceURL.substring(slashIndex + 1);
}
return aSourceURL;
},
/**
* Format the jsterm execution result based on its type.
*
* @param mixed aResult
* The evaluation result object you want displayed.
* @return string
* The string that can be displayed.
*/
formatResult: function WCU_formatResult(aResult)
{
let output = "";
let type = this.getResultType(aResult);
switch (type) {
case "string":
output = this.formatResultString(aResult);
break;
case "boolean":
case "date":
case "error":
case "number":
case "regexp":
output = aResult.toString();
break;
case "null":
case "undefined":
output = type;
break;
default:
if (aResult.toSource) {
try {
output = aResult.toSource();
} catch (ex) { }
}
if (!output || output == "({})") {
output = aResult.toString();
}
break;
}
return output;
},
/**
* Format a string for output.
*
* @param string aString
* The string you want to display.
* @return string
* The string that can be displayed.
*/
formatResultString: function WCU_formatResultString(aString)
{
function isControlCode(c) {
// See http://en.wikipedia.org/wiki/C0_and_C1_control_codes
// C0 is 0x00-0x1F, C1 is 0x80-0x9F (inclusive).
// We also include DEL (U+007F) and NBSP (U+00A0), which are not strictly
// in C1 but border it.
return (c <= 0x1F) || (0x7F <= c && c <= 0xA0);
}
function replaceFn(aMatch, aType, aHex) {
// Leave control codes escaped, but unescape the rest of the characters.
let c = parseInt(aHex, 16);
return isControlCode(c) ? aMatch : String.fromCharCode(c);
}
let output = uneval(aString).replace(/\\(x)([0-9a-fA-F]{2})/g, replaceFn)
.replace(/\\(u)([0-9a-fA-F]{4})/g, replaceFn);
return output;
},
/**
* Determine if an object can be inspected or not.
*
* @param mixed aObject
* The object you want to check if it can be inspected.
* @return boolean
* True if the object is inspectable or false otherwise.
*/
isObjectInspectable: function WCU_isObjectInspectable(aObject)
{
let isEnumerable = false;
// Skip Iterators and Generators.
if (this.isIteratorOrGenerator(aObject)) {
return false;
}
try {
for (let p in aObject) {
isEnumerable = true;
break;
}
}
catch (ex) {
// Proxy objects can lack an enumerable method.
}
return isEnumerable && typeof(aObject) != "string";
},
/**
* Determine the type of the jsterm execution result.
*
* @param mixed aResult
* The evaluation result object you want to check.
* @return string
* Constructor name or type: string, number, boolean, regexp, date,
* function, object, null, undefined...
*/
getResultType: function WCU_getResultType(aResult)
{
let type = aResult === null ? "null" : typeof aResult;
if (type == "object" && aResult.constructor && aResult.constructor.name) {
type = aResult.constructor.name;
}
return type.toLowerCase();
},
/**
* Figures out the type of aObject and the string to display as the object
* value.
*
* @see TYPES
* @param object aObject
* The object to operate on.
* @return object
* An object of the form:
* {
* type: TYPES.OBJECT || TYPES.FUNCTION || ...
* display: string for displaying the object
* }
*/
presentableValueFor: function WCU_presentableValueFor(aObject)
{
let type = this.getResultType(aObject);
let presentable;
switch (type) {
case "undefined":
case "null":
return {
type: TYPES.OTHER,
display: type
};
case "array":
return {
type: TYPES.ARRAY,
display: "Array"
};
case "string":
return {
type: TYPES.STRING,
display: "\"" + aObject + "\""
};
case "date":
case "regexp":
case "number":
case "boolean":
return {
type: TYPES.OTHER,
display: aObject.toString()
};
case "iterator":
return {
type: TYPES.ITERATOR,
display: "Iterator"
};
case "function":
presentable = aObject.toString();
return {
type: TYPES.FUNCTION,
display: presentable.substring(0, presentable.indexOf(')') + 1)
};
default:
presentable = String(aObject);
let m = /^\[object (\S+)\]/.exec(presentable);
try {
if (type == "object" && typeof aObject.next == "function" &&
m && m[1] == "Generator") {
return {
type: TYPES.GENERATOR,
display: m[1]
};
}
}
catch (ex) {
// window.history.next throws in the typeof check above.
return {
type: TYPES.OBJECT,
display: m ? m[1] : "Object"
};
}
if (type == "object" && typeof aObject.__iterator__ == "function") {
return {
type: TYPES.ITERATOR,
display: "Iterator"
};
}
return {
type: TYPES.OBJECT,
display: m ? m[1] : "Object"
};
}
},
/**
* Tells if the given function is native or not.
*
* @param function aFunction
* The function you want to check if it is native or not.
* @return boolean
* True if the given function is native, false otherwise.
*/
isNativeFunction: function WCU_isNativeFunction(aFunction)
{
return typeof aFunction == "function" && !("prototype" in aFunction);
},
/**
* Tells if the given property of the provided object is a non-native getter or
* not.
*
* @param object aObject
* The object that contains the property.
* @param string aProp
* The property you want to check if it is a getter or not.
* @return boolean
* True if the given property is a getter, false otherwise.
*/
isNonNativeGetter: function WCU_isNonNativeGetter(aObject, aProp)
{
if (typeof aObject != "object") {
return false;
}
let desc;
while (aObject) {
try {
if (desc = Object.getOwnPropertyDescriptor(aObject, aProp)) {
break;
}
}
catch (ex) {
// Native getters throw here. See bug 520882.
if (ex.name == "NS_ERROR_XPC_BAD_CONVERT_JS" ||
ex.name == "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO") {
return false;
}
throw ex;
}
aObject = Object.getPrototypeOf(aObject);
}
if (desc && desc.get && !this.isNativeFunction(desc.get)) {
return true;
}
return false;
},
/**
* Get an array that describes the properties of the given object.
*
* @param object aObject
* The object to get the properties from.
* @param object aObjectCache
* Optional object cache where to store references to properties of
* aObject that are inspectable. See this.isObjectInspectable().
* @return array
* An array that describes each property from the given object. Each
* array element is an object (a property descriptor). Each property
* descriptor has the following properties:
* - name - property name
* - value - a presentable property value representation (see
* this.presentableValueFor())
* - type - value type (see this.presentableValueFor())
* - inspectable - tells if the property value holds further
* properties (see this.isObjectInspectable()).
* - objectId - optional, available only if aObjectCache is given and
* if |inspectable| is true. You can do
* aObjectCache[propertyDescriptor.objectId] to get the actual object
* referenced by the property of aObject.
*/
namesAndValuesOf: function WCU_namesAndValuesOf(aObject, aObjectCache)
{
let pairs = [];
let value, presentable;
let isDOMDocument = aObject instanceof Ci.nsIDOMDocument;
for (let propName in aObject) {
// See bug 632275: skip deprecated width and height properties.
if (isDOMDocument && (propName == "width" || propName == "height")) {
continue;
}
// Also skip non-native getters.
if (this.isNonNativeGetter(aObject, propName)) {
value = "";
presentable = {type: TYPES.GETTER, display: "Getter"};
}
else {
value = aObject[propName];
presentable = this.presentableValueFor(value);
}
let pair = {};
pair.name = propName;
pair.value = presentable.display;
pair.inspectable = false;
pair.type = presentable.type;
switch (presentable.type) {
case TYPES.GETTER:
case TYPES.ITERATOR:
case TYPES.GENERATOR:
case TYPES.STRING:
break;
default:
try {
for (let p in value) {
pair.inspectable = true;
break;
}
}
catch (ex) { }
break;
}
// Store the inspectable object.
if (pair.inspectable && aObjectCache) {
pair.objectId = ++gObjectId;
aObjectCache[pair.objectId] = value;
}
pairs.push(pair);
}
pairs.sort(function(a, b)
{
// Convert the pair.name to a number for later sorting.
let aNumber = parseFloat(a.name);
let bNumber = parseFloat(b.name);
// Sort numbers.
if (!isNaN(aNumber) && isNaN(bNumber)) {
return -1;
}
else if (isNaN(aNumber) && !isNaN(bNumber)) {
return 1;
}
else if (!isNaN(aNumber) && !isNaN(bNumber)) {
return aNumber - bNumber;
}
// Sort string.
else if (a.name < b.name) {
return -1;
}
else if (a.name > b.name) {
return 1;
}
else {
return 0;
}
});
return pairs;
},
/**
* Check if the given object is an iterator or a generator.
*
* @param object aObject
* The object you want to check.
* @return boolean
* True if the given object is an iterator or a generator, otherwise
* false is returned.
*/
isIteratorOrGenerator: function WCU_isIteratorOrGenerator(aObject)
{
if (aObject === null) {
return false;
}
if (typeof aObject == "object") {
if (typeof aObject.__iterator__ == "function" ||
aObject.constructor && aObject.constructor.name == "Iterator") {
return true;
}
try {
let str = aObject.toString();
if (typeof aObject.next == "function" &&
str.indexOf("[object Generator") == 0) {
return true;
}
}
catch (ex) {
// window.history.next throws in the typeof check above.
return false;
}
}
return false;
},
};
//////////////////////////////////////////////////////////////////////////
// Localization
//////////////////////////////////////////////////////////////////////////
WebConsoleUtils.l10n = {
/**
* Generates a formatted timestamp string for displaying in console messages.
*
* @param integer [aMilliseconds]
* Optional, allows you to specify the timestamp in milliseconds since
* the UNIX epoch.
* @return string
* The timestamp formatted for display.
*/
timestampString: function WCU_l10n_timestampString(aMilliseconds)
{
let d = new Date(aMilliseconds ? aMilliseconds : null);
let hours = d.getHours(), minutes = d.getMinutes();
let seconds = d.getSeconds(), milliseconds = d.getMilliseconds();
let parameters = [hours, minutes, seconds, milliseconds];
return this.getFormatStr("timestampFormat", parameters);
},
/**
* Retrieve a localized string.
*
* @param string aName
* The string name you want from the Web Console string bundle.
* @return string
* The localized string.
*/
getStr: function WCU_l10n_getStr(aName)
{
let result;
try {
result = this.stringBundle.GetStringFromName(aName);
}
catch (ex) {
Cu.reportError("Failed to get string: " + aName);
throw ex;
}
return result;
},
/**
* Retrieve a localized string formatted with values coming from the given
* array.
*
* @param string aName
* The string name you want from the Web Console string bundle.
* @param array aArray
* The array of values you want in the formatted string.
* @return string
* The formatted local string.
*/
getFormatStr: function WCU_l10n_getFormatStr(aName, aArray)
{
let result;
try {
result = this.stringBundle.formatStringFromName(aName, aArray, aArray.length);
}
catch (ex) {
Cu.reportError("Failed to format string: " + aName);
throw ex;
}
return result;
},
};
XPCOMUtils.defineLazyGetter(WebConsoleUtils.l10n, "stringBundle", function() {
return Services.strings.createBundle(STRINGS_URI);
});

Просмотреть файл

@ -0,0 +1,74 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the GCLI.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joe Walker <jwalker@mozilla.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
.gclichrome-output {
max-width: 350px;
}
.gclichrome-tooltip {
max-width: 350px;
}
.gcli-help-name {
text-align: end;
}
.gcli-help-synopsis {
cursor: pointer;
display: inline-block;
}
.gcli-help-synopsis:before {
content: '\bb';
}
.gcli-menu-option {
overflow: hidden;
white-space: nowrap;
cursor: pointer;
}
.gcli-menu-template {
border-collapse: collapse;
width: 100%;
}
.gcli-menu-error {
overflow: hidden;
white-space: nowrap;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
[
<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
%webConsoleDTD;
]
>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is GCLI.
-
- The Initial Developer of the Original Code is
- Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Joe Walker <jwalker@mozilla.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
</head>
<body id="gclichrome-body">
<div>
</div>
</body>
</html>

Просмотреть файл

@ -144,17 +144,10 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_678816.js \
browser_webconsole_bug_664131_console_group.js \
browser_webconsole_bug_704295.js \
browser_gcli_commands.js \
browser_gcli_helpers.js \
browser_gcli_inspect.js \
browser_gcli_integrate.js \
browser_gcli_require.js \
browser_gcli_web.js \
browser_webconsole_bug_658368_time_methods.js \
browser_webconsole_bug_622303_persistent_filters.js \
browser_webconsole_window_zombie.js \
browser_cached_messages.js \
browser_gcli_break.js \
head.js \
$(NULL)
@ -225,11 +218,9 @@ _BROWSER_TEST_PAGES = \
test-bug-646025-console-file-location.html \
test-bug-678816-content.js \
test-file-location.js \
browser_gcli_inspect.html \
test-bug-658368-time-methods.html \
test-webconsole-error-observer.html \
test-for-of.html \
browser_gcli_break.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

Просмотреть файл

@ -44,8 +44,7 @@ function test()
expectUncaughtException();
gBrowser.selectedTab = gBrowser.addTab(TEST_URI);
addTab(TEST_URI);
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
testOpenUI(true);
@ -57,27 +56,26 @@ function testOpenUI(aTestReopen)
// test to see if the messages are
// displayed when the console UI is opened
HUDService.activateHUDForContext(gBrowser.selectedTab);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.getHudReferenceById(hudId);
openConsole(null, function(hud) {
testLogEntry(hud.outputNode, "log Bazzle",
"Find a console log entry from before console UI is opened",
false, null);
testLogEntry(hud.outputNode, "log Bazzle",
"Find a console log entry from before console UI is opened",
false, null);
testLogEntry(hud.outputNode, "error Bazzle",
"Find a console error entry from before console UI is opened",
false, null);
testLogEntry(hud.outputNode, "error Bazzle",
"Find a console error entry from before console UI is opened",
false, null);
testLogEntry(hud.outputNode, "bazBug611032", "Found the JavaScript error");
testLogEntry(hud.outputNode, "cssColorBug611032", "Found the CSS error");
testLogEntry(hud.outputNode, "bazBug611032", "Found the JavaScript error");
testLogEntry(hud.outputNode, "cssColorBug611032", "Found the CSS error");
HUDService.deactivateHUDForContext(gBrowser.selectedTab);
if (aTestReopen) {
HUDService.deactivateHUDForContext(gBrowser.selectedTab);
executeSoon(testOpenUI);
} else {
executeSoon(finish);
}
if (aTestReopen) {
HUDService.deactivateHUDForContext(gBrowser.selectedTab);
executeSoon(testOpenUI);
}
else {
executeSoon(finish);
}
});
}

Просмотреть файл

@ -1,105 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
// Tests that the break command works as it should
let tempScope = {};
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
let gcli = tempScope.gcli;
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_break.html";
registerCleanupFunction(function() {
gcliterm = undefined;
requisition = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
let gcliterm;
let requisition;
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
try {
openConsole();
let hud = HUDService.getHudByWindow(content);
gcliterm = hud.gcliterm;
requisition = gcliterm.opts.requisition;
testSetup();
testCreateCommands();
}
catch (ex) {
ok(false, "Caught exception: " + ex)
gcli._internal.console.error("Test Failure", ex);
closeConsole();
finishTest();
}
}
function testSetup() {
ok(gcliterm, "We have a GCLI term");
ok(requisition, "We have a Requisition");
}
function testCreateCommands() {
type("brea");
is(gcliterm.completeNode.textContent, " break", "Completion for 'brea'");
is(requisition.getStatus().toString(), "ERROR", "brea is ERROR");
type("break");
is(requisition.getStatus().toString(), "ERROR", "break is ERROR");
type("break add");
is(requisition.getStatus().toString(), "ERROR", "break add is ERROR");
type("break add line");
is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR");
let pane = DebuggerUI.toggleDebugger();
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume.
pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
pane.contentWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
requisition.exec();
type("break list");
is(requisition.getStatus().toString(), "VALID", "break list is VALID");
requisition.exec();
pane.contentWindow.gClient.activeThread.resume(function() {
type("break del 0");
is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
requisition.exec();
closeConsole();
finishTest();
});
});
// Trigger newScript notifications using eval.
content.wrappedJSObject.firstCall();
});
}, true);
}
function type(command) {
gcliterm.inputNode.value = command.slice(0, -1);
gcliterm.inputNode.focus();
EventUtils.synthesizeKey(command.slice(-1), {});
}

Просмотреть файл

@ -1,80 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
let tmp = {};
Components.utils.import("resource:///modules/gcli.jsm", tmp);
let gcli = tmp.gcli;
let hud;
let gcliterm;
registerCleanupFunction(function() {
gcliterm = undefined;
hud = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab("http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_inspect.html");
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
openConsole();
hud = HUDService.getHudByWindow(content);
gcliterm = hud.gcliterm;
testEcho();
// gcli._internal.console.error("Command Tests Completed");
}
function testEcho() {
let nodes = exec("echo message");
is(nodes.length, 2, "after echo");
is(nodes[0].textContent, "echo message", "output 0");
is(nodes[1].textContent.trim(), "message", "output 1");
testConsoleClear();
}
function testConsoleClear() {
let nodes = exec("console clear");
is(nodes.length, 1, "after console clear 1");
executeSoon(function() {
let nodes = hud.outputNode.querySelectorAll("richlistitem");
is(nodes.length, 0, "after console clear 2");
testConsoleClose();
});
}
function testConsoleClose() {
ok(hud.hudId in HUDService.hudReferences, "console open");
exec("console close");
ok(!(hud.hudId in HUDService.hudReferences), "console closed");
finishTest();
}
function exec(command) {
gcliterm.clearOutput();
let nodes = hud.outputNode.querySelectorAll("richlistitem");
is(nodes.length, 0, "setup - " + command);
gcliterm.opts.console.inputter.setInput(command);
gcliterm.opts.requisition.exec();
return hud.outputNode.querySelectorAll("richlistitem");
}

Просмотреть файл

@ -1,124 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
let tmp = {};
Components.utils.import("resource:///modules/gcli.jsm", tmp);
let gcli = tmp.gcli;
let hud;
let gcliterm;
registerCleanupFunction(function() {
gcliterm = undefined;
hud = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab("http://example.com/browser/browser/devtools/webconsole/test/test-console.html");
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
openConsole();
hud = HUDService.getHudByWindow(content);
gcliterm = hud.gcliterm;
testHelpers();
testScripts();
closeConsole();
finishTest();
// gcli._internal.console.error("Command Tests Completed");
}
function testScripts() {
check("{ 'id=' + $('header').getAttribute('id')", '"id=header"');
check("{ headerQuery = $$('h1')", "Instance of NodeList");
check("{ 'length=' + headerQuery.length", '"length=1"');
check("{ xpathQuery = $x('.//*', document.body);", 'Instance of Array');
check("{ 'headerFound=' + (xpathQuery[0] == headerQuery[0])", '"headerFound=true"');
check("{ 'keysResult=' + (keys({b:1})[0] == 'b')", '"keysResult=true"');
check("{ 'valuesResult=' + (values({b:1})[0] == 1)", '"valuesResult=true"');
check("{ [] instanceof Array", "true");
check("{ ({}) instanceof Object", "true");
check("{ document", "Instance of HTMLDocument");
check("{ null", "null");
check("{ undefined", undefined);
check("{ for (var x=0; x<9; x++) x;", "8");
}
function check(command, reply) {
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput(command);
gcliterm.opts.requisition.exec();
let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
if (reply === undefined) {
is(labels.length, 0, "results count for: " + command);
}
else {
is(labels.length, 1, "results count for: " + command);
is(labels[0].textContent.trim(), reply, "message for: " + command);
}
gcliterm.opts.console.inputter.setInput("");
}
function testHelpers() {
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput("{ pprint({b:2, a:1})");
gcliterm.opts.requisition.exec();
// Doesn't conform to check() format
let label = hud.outputNode.querySelector(".webconsole-msg-output");
is(label.textContent.trim(), "a: 1\n b: 2", "pprint() worked");
// no gcliterm.clearOutput() here as we clear the output using the clear() fn.
gcliterm.opts.console.inputter.setInput("{ clear()");
gcliterm.opts.requisition.exec();
ok(!hud.outputNode.querySelector(".hud-group"), "clear() worked");
// check that pprint(window) and keys(window) don't throw, bug 608358
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput("{ pprint(window)");
gcliterm.opts.requisition.exec();
let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
is(labels.length, 1, "one line of output for pprint(window)");
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput("{ keys(window)");
gcliterm.opts.requisition.exec();
labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
is(labels.length, 1, "one line of output for keys(window)");
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput("{ pprint('hi')");
gcliterm.opts.requisition.exec();
// Doesn't conform to check() format, bug 614561
label = hud.outputNode.querySelector(".webconsole-msg-output");
is(label.textContent.trim(), '0: "h"\n 1: "i"', 'pprint("hi") worked');
// Causes a memory leak. FIXME Bug 717892
/*
// check that pprint(function) shows function source, bug 618344
gcliterm.clearOutput();
gcliterm.opts.console.inputter.setInput("{ pprint(print)");
gcliterm.opts.requisition.exec();
label = hud.outputNode.querySelector(".webconsole-msg-output");
isnot(label.textContent.indexOf("SEVERITY_LOG"), -1, "pprint(function) shows function source");
*/
gcliterm.clearOutput();
}

Просмотреть файл

@ -1,95 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
// Tests that the inspect command works as it should
let tempScope = {};
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
let gcli = tempScope.gcli;
registerCleanupFunction(function() {
gcliterm = undefined;
requisition = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab("http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_inspect.html");
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
let gcliterm;
let requisition;
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
try {
openConsole();
let hud = HUDService.getHudByWindow(content);
gcliterm = hud.gcliterm;
requisition = gcliterm.opts.requisition;
testSetup();
testCreateCommands();
}
catch (ex) {
ok(false, "Caught exception: " + ex)
gcli._internal.console.error("Test Failure", ex);
}
finally {
closeConsole();
finishTest();
}
}
function testSetup() {
ok(gcliterm, "We have a GCLI term");
ok(requisition, "We have a Requisition");
}
function testCreateCommands() {
type("inspec");
is(gcliterm.completeNode.textContent, " inspect", "Completion for \"inspec\"");
is(requisition.getStatus().toString(), "ERROR", "inspec is ERROR");
type("inspect");
is(requisition.getStatus().toString(), "ERROR", "inspect is ERROR");
type("inspect h1");
is(requisition.getStatus().toString(), "ERROR", "inspect h1 is ERROR");
type("inspect span");
is(requisition.getStatus().toString(), "ERROR", "inspect span is ERROR");
type("inspect div");
is(requisition.getStatus().toString(), "VALID", "inspect div is VALID");
type("inspect .someclass");
is(requisition.getStatus().toString(), "VALID", "inspect .someclass is VALID");
type("inspect #someid");
is(requisition.getStatus().toString(), "VALID", "inspect #someid is VALID");
type("inspect button[disabled]");
is(requisition.getStatus().toString(), "VALID", "inspect button[disabled] is VALID");
type("inspect p>strong");
is(requisition.getStatus().toString(), "VALID", "inspect p>strong is VALID");
type("inspect :root");
is(requisition.getStatus().toString(), "VALID", "inspect :root is VALID");
}
function type(command) {
gcliterm.inputNode.value = command.slice(0, -1);
gcliterm.inputNode.focus();
EventUtils.synthesizeKey(command.slice(-1), {});
}

Просмотреть файл

@ -1,106 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// For more information on GCLI see:
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
// - https://wiki.mozilla.org/DevTools/Features/GCLI
// Tests that source URLs in the Web Console can be clicked to display the
// standard View Source window.
let tempScope = {};
Components.utils.import("resource:///modules/gcli.jsm", tempScope);
let gcli = tempScope.gcli;
let require = gcli._internal.require;
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
require = undefined;
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", true);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
try {
openConsole();
testCreateCommands();
testCallCommands();
testRemoveCommands();
}
catch (ex) {
gcli._internal.console.error('Test Failure', ex);
ok(false, '' + ex);
}
finally {
closeConsole();
finishTest();
}
}
let tselarr = {
name: 'tselarr',
params: [
{ name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } },
{ name: 'arr', type: { name: 'array', subtype: 'string' } },
],
exec: function(args, env) {
return "flu " + args.num + "-" + args.arr.join("_");
}
};
function testCreateCommands() {
let gcli = require("gcli/index");
gcli.addCommand(tselarr);
let canon = require("gcli/canon");
let tselcmd = canon.getCommand("tselarr");
ok(tselcmd != null, "tselarr exists in the canon");
ok(tselcmd instanceof canon.Command, "canon storing commands");
}
function testCallCommands() {
let hud = HUDService.getHudByWindow(content);
let gcliterm = hud.gcliterm;
ok(gcliterm, "We have a GCLI term");
// Test successful auto-completion
gcliterm.inputNode.value = "h";
gcliterm.inputNode.focus();
EventUtils.synthesizeKey("e", {});
is(gcliterm.completeNode.textContent, " help", "Completion for \"he\"");
// Test unsuccessful auto-completion
gcliterm.inputNode.value = "ec";
gcliterm.inputNode.focus();
EventUtils.synthesizeKey("d", {});
is(gcliterm.completeNode.textContent, " ecd", "Completion for \"ecd\"");
// Test a normal command's life cycle
gcliterm.opts.console.inputter.setInput("echo hello world");
gcliterm.opts.requisition.exec();
let nodes = hud.outputNode.querySelectorAll(".gcliterm-msg-body");
is(nodes.length, 1, "Right number of output nodes");
ok(/hello world/.test(nodes[0].textContent), "the command's output is correct.");
gcliterm.clearOutput();
}
function testRemoveCommands() {
let gcli = require("gcli/index");
gcli.removeCommand(tselarr);
let canon = require("gcli/canon");
let tselcmd = canon.getCommand("tselarr");
ok(tselcmd == null, "tselcmd removed from the canon");
}

Просмотреть файл

@ -15,7 +15,7 @@ function test() {
}
function testAbbreviation(aFullURL, aAbbreviatedURL) {
is(ConsoleUtils.abbreviateSourceURL(aFullURL), aAbbreviatedURL, aFullURL +
is(WebConsoleUtils.abbreviateSourceURL(aFullURL), aAbbreviatedURL, aFullURL +
" is abbreviated to " + aAbbreviatedURL);
}

Просмотреть файл

@ -42,12 +42,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testInputFocus, false);
}

Просмотреть файл

@ -43,12 +43,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testClosingAfterCompletion,
false);

Просмотреть файл

@ -51,33 +51,26 @@ function test() {
// see bug 580030: the error handler fails silently after page reload.
// https://bugzilla.mozilla.org/show_bug.cgi?id=580030
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole();
browser.addEventListener("load", testErrorsAfterPageReload, true);
executeSoon(function() {
openConsole(null, function(hud) {
hud.jsterm.clearOutput();
browser.addEventListener("load", testErrorsAfterPageReload, true);
content.location.reload();
});
}
function testErrorsAfterPageReload(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, testErrorsAfterPageReload, true);
// dispatch a click event to the button in the test page and listen for
// errors.
Services.console.registerListener(consoleObserver);
var button = content.document.querySelector("button").wrappedJSObject;
var clickEvent = content.document.createEvent("MouseEvents");
clickEvent.initMouseEvent("click", true, true,
content, 0, 0, 0, 0, 0, false, false,
false, false, 0, null);
executeSoon(function() {
button.dispatchEvent(clickEvent);
});
let button = content.document.querySelector("button").wrappedJSObject;
ok(button, "button found");
EventUtils.sendMouseEvent({type: "click"}, button, content);
}
var consoleObserver = {
@ -95,10 +88,14 @@ var consoleObserver = {
let outputNode = HUDService.getHudByWindow(content).outputNode;
executeSoon(function() {
let msg = "Found the error message after page reload";
testLogEntry(outputNode, "fooBazBaz", msg);
finishTest();
waitForSuccess({
name: "error message after page reload",
validatorFn: function()
{
return outputNode.textContent.indexOf("fooBazBaz") > -1;
},
successFn: finishTest,
failureFn: finishTest,
});
}
};

Просмотреть файл

@ -42,12 +42,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testGroups, false);
}

Просмотреть файл

@ -21,7 +21,7 @@ function test() {
browser.removeEventListener("DOMContentLoaded", testTimestamp, false);
const TEST_TIMESTAMP = 12345678;
let date = new Date(TEST_TIMESTAMP);
let localizedString = ConsoleUtils.timestampString(TEST_TIMESTAMP);
let localizedString = WebConsoleUtils.l10n.timestampString(TEST_TIMESTAMP);
isnot(localizedString.indexOf(date.getHours()), -1, "the localized " +
"timestamp contains the hours");
isnot(localizedString.indexOf(date.getMinutes()), -1, "the localized " +

Просмотреть файл

@ -43,12 +43,7 @@
const TEST_DUPLICATE_ERROR_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-duplicate-error.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
expectUncaughtException();
addTab(TEST_DUPLICATE_ERROR_URI);
browser.addEventListener("DOMContentLoaded", testDuplicateErrors, false);
@ -57,14 +52,14 @@ function test() {
function testDuplicateErrors() {
browser.removeEventListener("DOMContentLoaded", testDuplicateErrors,
false);
openConsole();
openConsole(null, function(hud) {
hud.jsterm.clearOutput();
HUDService.getHudByWindow(content).jsterm.clearOutput();
Services.console.registerListener(consoleObserver);
Services.console.registerListener(consoleObserver);
expectUncaughtException();
content.location.reload();
expectUncaughtException();
content.location.reload();
});
}
var consoleObserver = {
@ -82,18 +77,27 @@ var consoleObserver = {
outputNode = HUDService.getHudByWindow(content).outputNode;
executeSoon(function () {
var text = outputNode.textContent;
var error1pos = text.indexOf("fooDuplicateError1");
ok(error1pos > -1, "found fooDuplicateError1");
if (error1pos > -1) {
ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1,
"no duplicate for fooDuplicateError1");
}
waitForSuccess({
name: "fooDuplicateError1 error displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("fooDuplicateError1") > -1;
},
successFn: function()
{
let text = outputNode.textContent;
let error1pos = text.indexOf("fooDuplicateError1");
ok(error1pos > -1, "found fooDuplicateError1");
if (error1pos > -1) {
ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1,
"no duplicate for fooDuplicateError1");
}
findLogEntry("test-duplicate-error.html");
findLogEntry("test-duplicate-error.html");
finishTest();
finishTest();
},
failureFn: finishTest,
});
}
};

Просмотреть файл

@ -39,12 +39,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testCompletion, false);
}

Просмотреть файл

@ -12,33 +12,67 @@
// Tests that the Web Console limits the number of lines displayed according to
// the user's preferences.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
const TEST_URI = "data:text/html;charset=utf8,test for bug 585237";
let hud, testDriver;
function test() {
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testLineLimit,
false);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, function(aHud) {
hud = aHud;
testDriver = testGen();
testNext();
});
}, true);
}
function testLineLimit() {
browser.removeEventListener("DOMContentLoaded",testLineLimit, false);
function testNext() {
testDriver.next();
}
openConsole();
function testGen() {
let console = content.console;
outputNode = hud.outputNode;
let console = browser.contentWindow.wrappedJSObject.console;
outputNode = HUDService.getHudByWindow(content).outputNode;
hud.jsterm.clearOutput();
let prefBranch = Services.prefs.getBranch("devtools.hud.loglimit.");
prefBranch.setIntPref("console", 20);
for (let i = 0; i < 20; i++) {
for (let i = 0; i < 30; i++) {
console.log("foo #" + i); // must change message to prevent repeats
}
waitForSuccess({
name: "20 console.log messages displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("foo #29") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
is(countMessageNodes(), 20, "there are 20 message nodes in the output " +
"when the log limit is set to 20");
console.log("bar");
console.log("bar bug585237");
waitForSuccess({
name: "another console.log message displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("bar bug585237") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
is(countMessageNodes(), 20, "there are still 20 message nodes in the " +
"output when adding one more");
@ -47,17 +81,41 @@ function testLineLimit() {
console.log("boo #" + i); // must change message to prevent repeats
}
waitForSuccess({
name: "another 20 console.log message displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("boo #19") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
is(countMessageNodes(), 30, "there are 30 message nodes in the output " +
"when the log limit is set to 30");
prefBranch.setIntPref("console", 0);
console.log("baz");
is(countMessageNodes(), 0, "there are no message nodes in the output when " +
"the log limit is set to zero");
waitForSuccess({
name: "clear output",
validatorFn: function()
{
return countMessageNodes() == 0;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
prefBranch.clearUserPref("console");
prefBranch = console = outputNode = null;
hud = testDriver = prefBranch = console = outputNode = null;
finishTest();
yield;
}
function countMessageNodes() {

Просмотреть файл

@ -46,10 +46,10 @@ function test() {
function tabLoaded() {
browser.removeEventListener("load", tabLoaded, true);
openConsole();
browser.addEventListener("load", tabReloaded, true);
content.location.reload();
openConsole(null, function() {
browser.addEventListener("load", tabReloaded, true);
content.location.reload();
});
}
function tabReloaded() {

Просмотреть файл

@ -39,12 +39,7 @@
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete popup keyboard usage test";
let HUD;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}

Просмотреть файл

@ -38,12 +38,7 @@
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 585991 - autocomplete popup test";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}

Просмотреть файл

@ -10,12 +10,7 @@
const TEST_URI = "http://example.com/";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded",
testSelectionWhenMovingBetweenBoxes, false);

Просмотреть файл

@ -10,52 +10,51 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function tabLoaded() {
browser.removeEventListener("load", tabLoaded, true);
openConsole();
function consoleOpened(HUD) {
// See bugs 574036, 586386 and 587617.
let HUD = HUDService.getHudByWindow(content);
outputNode = HUD.outputNode;
let selection = getSelection();
let jstermInput = HUD.jsterm.inputNode;
let console = content.wrappedJSObject.console;
let contentSelection = content.wrappedJSObject.getSelection();
let make_selection = function () {
let controller =
top.document.commandDispatcher.
getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
HUD.jsterm.clearOutput();
console.log("Hello world!");
let controller = top.document.commandDispatcher.
getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), false, "cmd_copy is disabled");
outputNode.selectedIndex = 0;
outputNode.focus();
console.log("Hello world! bug587617");
goUpdateCommand("cmd_copy");
waitForSuccess({
name: "console log 'Hello world!' message",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug587617") > -1;
},
successFn: function()
{
outputNode.selectedIndex = 0;
outputNode.focus();
controller = top.document.commandDispatcher.
getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
let selectedNode = outputNode.getItemAtIndex(0);
waitForClipboard(getExpectedClipboardText(selectedNode), clipboardSetup,
testContextMenuCopy, testContextMenuCopy);
};
make_selection();
goUpdateCommand("cmd_copy");
controller = top.document.commandDispatcher.
getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
let selectedNode = outputNode.getItemAtIndex(0);
waitForClipboard(getExpectedClipboardText(selectedNode), clipboardSetup,
testContextMenuCopy, testContextMenuCopy);
},
failureFn: finishTest,
});
}
// Test that the context menu "Copy" (which has a different code path) works
@ -79,7 +78,7 @@ function testContextMenuCopy() {
}
function getExpectedClipboardText(aItem) {
return "[" + ConsoleUtils.timestampString(aItem.timestamp) + "] " +
return "[" + WebConsoleUtils.l10n.timestampString(aItem.timestamp) + "] " +
aItem.clipboardText;
}

Просмотреть файл

@ -11,12 +11,7 @@
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 588342";
let fm, notificationBox, input;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);

Просмотреть файл

@ -44,18 +44,16 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te
function test() {
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testTextNodeInsertion,
false);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, testTextNodeInsertion);
}, true);
}
// Test for bug 588730: Adding a text node to an existing label element causes
// warnings
function testTextNodeInsertion() {
browser.removeEventListener("DOMContentLoaded", testTextNodeInsertion,
false);
openConsole();
let outputNode = HUDService.getHudByWindow(content).outputNode;
function testTextNodeInsertion(hud) {
let outputNode = hud.outputNode;
let label = document.createElementNS(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label");
@ -71,16 +69,13 @@ function testTextNodeInsertion() {
}
};
let nsIConsoleServiceClass = Cc["@mozilla.org/consoleservice;1"];
let nsIConsoleService =
nsIConsoleServiceClass.getService(Ci.nsIConsoleService);
nsIConsoleService.registerListener(listener);
Services.console.registerListener(listener);
// This shouldn't fail.
label.appendChild(document.createTextNode("foo"));
executeSoon(function() {
nsIConsoleService.unregisterListener(listener);
Services.console.unregisterListener(listener);
ok(!error, "no error when adding text nodes as children of labels");
finishTest();

Просмотреть файл

@ -38,12 +38,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testInputExpansion, false);
}

Просмотреть файл

@ -13,12 +13,7 @@
// Tests that, when the user types an extraneous closing bracket, no error
// appears.
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,test for bug 592442");
browser.addEventListener("load", testExtraneousClosingBrackets, true);
}

Просмотреть файл

@ -50,45 +50,27 @@ function test() {
browser.addEventListener("load", tab1Loaded, true);
}
/**
* Check if a log entry exists in the HUD output node.
*
* @param {Element} aOutputNode the HUD output node.
* @param {string} aMatchString the string you want to check if it exists in the
* output node.
* @param {boolean} [aOnlyVisible=false] find only messages that are visible,
* not hidden by the filter.
* @param {boolean} [aFailIfFound=false] fail the test if the string is found in
* the output node.
*/
function tab1Loaded(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.contentWindow.wrappedJSObject.console.log("FOO");
try {
openConsole();
}
catch (ex) {
log(ex);
log(ex.stack);
}
tab2 = gBrowser.addTab(TEST_DUMMY_URI);
gBrowser.selectedTab = tab2;
gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true);
browser.removeEventListener(aEvent.type, tab1Loaded, true);
content.console.log("FOO");
openConsole(null, function() {
tab2 = gBrowser.addTab(TEST_DUMMY_URI);
gBrowser.selectedTab = tab2;
gBrowser.selectedBrowser.addEventListener("load", tab2Loaded, true);
});
}
function tab2Loaded(aEvent) {
tab2.linkedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
tab2.linkedBrowser.removeEventListener(aEvent.type, tab2Loaded, true);
HUDService.activateHUDForContext(gBrowser.selectedTab);
tab1.linkedBrowser.addEventListener("load", tab1Reloaded, true);
tab1.linkedBrowser.contentWindow.location.reload();
openConsole(gBrowser.selectedTab, function() {
tab1.linkedBrowser.addEventListener("load", tab1Reloaded, true);
tab1.linkedBrowser.contentWindow.location.reload();
});
}
function tab1Reloaded(aEvent) {
tab1.linkedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
tab1.linkedBrowser.removeEventListener(aEvent.type, tab1Reloaded, true);
let hud1 = HUDService.getHudByWindow(tab1.linkedBrowser.contentWindow);
let outputNode1 = hud1.outputNode;
@ -105,8 +87,9 @@ function tab1Reloaded(aEvent) {
msg = "Didn't find the iframe network request in tab2";
testLogEntry(outputNode2, TEST_IFRAME_URI, msg, true, true);
HUDService.deactivateHUDForContext(tab2);
gBrowser.removeTab(tab2);
finishTest();
closeConsole(tab2, function() {
gBrowser.removeTab(tab2);
tab1 = tab2 = null;
executeSoon(finishTest);
});
}

Просмотреть файл

@ -154,12 +154,7 @@ function propertyPanelHidden(aEvent) {
});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad1, true);
}

Просмотреть файл

@ -155,12 +155,7 @@ function performTests() {
executeSoon(finishTest);
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 594497 and bug 619598");
browser.addEventListener("load", tabLoad, true);
}

Просмотреть файл

@ -28,7 +28,7 @@ function test() {
}
function onWindowLoad(aEvent) {
win2.removeEventListener(aEvent.type, arguments.callee, true);
win2.removeEventListener(aEvent.type, onWindowLoad, true);
// Add two tabs in the new window.
addTabs(win2);
@ -39,48 +39,71 @@ function addTabs(aWindow) {
let tab = aWindow.gBrowser.addTab(TEST_URI);
openTabs.push(tab);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener(aEvent.type, arguments.callee,
true);
tab.linkedBrowser.addEventListener("load", function onLoad(aEvent) {
tab.linkedBrowser.removeEventListener(aEvent.type, onLoad, true);
loadedTabCount++;
if (loadedTabCount >= 4) {
executeSoon(performTest);
executeSoon(openConsoles);
}
}, true);
}
}
function performTest() {
function openConsoles() {
// open the Web Console for each of the four tabs and log a message.
let consolesOpen = 0;
for (let i = 0; i < openTabs.length; i++) {
let tab = openTabs[i];
HUDService.activateHUDForContext(tab);
let hudId = HUDService.getHudIdByWindow(tab.linkedBrowser.contentWindow);
ok(hudId, "HUD is open for tab " + i);
let HUD = HUDService.hudReferences[hudId];
HUD.console.log("message for tab " + i);
openConsole(tab, function(index, hud) {
ok(hud, "HUD is open for tab " + index);
hud.console.log("message for tab " + index);
consolesOpen++;
}.bind(null, i));
}
let displays = Object.keys(HUDService.hudReferences);
is(displays.length, 4, "four displays found");
win2.close();
executeSoon(function() {
win1.gBrowser.removeTab(openTabs[0]);
win1.gBrowser.removeTab(openTabs[1]);
executeSoon(function() {
displays = Object.keys(HUDService.hudReferences);
is(displays.length, 0, "no displays found");
ok(!HUDService.storage, "no storage found");
ok(!HUDService.httpObserver, "no httpObserver found");
displays = openTabs = win1 = win2 = null;
finishTest();
});
waitForSuccess({
name: "4 web consoles opened",
validatorFn: function()
{
return consolesOpen == 4;
},
successFn: closeConsoles,
failureFn: closeConsoles,
});
}
function closeConsoles() {
let consolesClosed = 0;
function onWebConsoleClose(aSubject, aTopic) {
if (aTopic == "web-console-destroyed") {
consolesClosed++;
}
}
Services.obs.addObserver(onWebConsoleClose, "web-console-destroyed", false);
win2.close();
win1.gBrowser.removeTab(openTabs[0]);
win1.gBrowser.removeTab(openTabs[1]);
openTabs = win1 = win2 = null;
function onTimeout() {
Services.obs.removeObserver(onWebConsoleClose, "web-console-destroyed");
executeSoon(finishTest);
}
waitForSuccess({
name: "4 web consoles closed",
validatorFn: function()
{
return consolesClosed == 4;
},
successFn: onTimeout,
failureFn: onTimeout,
});
}

Просмотреть файл

@ -89,12 +89,12 @@ const TESTS = [
category: "Image",
matchString: "corrupt",
},
/* Disabled until bug 675221 lands.
{ // #7
{ // #15
file: "test-bug-595934-workers.html",
category: "Web Worker",
matchString: "fooBarWorker",
},*/
expectError: true,
},
];
let pos = -1;
@ -103,13 +103,14 @@ let foundCategory = false;
let foundText = false;
let output = null;
let jsterm = null;
let testEnded = false;
let TestObserver = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
observe: function test_observe(aSubject)
{
if (!(aSubject instanceof Ci.nsIScriptError)) {
if (testEnded || !(aSubject instanceof Ci.nsIScriptError)) {
return;
}
@ -125,24 +126,21 @@ let TestObserver = {
else {
ok(false, aSubject.sourceName + ':' + aSubject.lineNumber + '; ' +
aSubject.errorMessage);
executeSoon(finish);
testEnded = true;
executeSoon(finishTest);
}
}
};
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function consoleOpened(hud) {
output = hud.outputNode;
output.addEventListener("DOMNodeInserted", onDOMNodeInserted, false);
jsterm = hud.jsterm;
Services.console.registerListener(TestObserver);
registerCleanupFunction(testEnd);
executeSoon(testNext);
}
@ -156,27 +154,30 @@ function testNext() {
let test = TESTS[pos];
let testLocation = TESTS_PATH + test.file;
if (test.onload) {
browser.addEventListener("load", function(aEvent) {
browser.addEventListener("load", function onLoad(aEvent) {
if (content.location.href == testLocation) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, onLoad, true);
test.onload(aEvent);
}
}, true);
}
if (test.expectError) {
expectUncaughtException();
}
content.location = testLocation;
}
else {
executeSoon(finish);
testEnded = true;
executeSoon(finishTest);
}
}
function testEnd() {
Services.prefs.clearUserPref("devtools.gcli.enable");
Services.console.unregisterListener(TestObserver);
output.removeEventListener("DOMNodeInserted", onDOMNodeInserted, false);
output = jsterm = null;
finishTest();
TestObserver = output = jsterm = null;
}
function onDOMNodeInserted(aEvent) {
@ -192,10 +193,10 @@ function onDOMNodeInserted(aEvent) {
}
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
registerCleanupFunction(testEnd);
addTab("data:text/html;charset=utf-8,Web Console test for bug 595934 - message categories coverage.");
browser.addEventListener("load", tabLoad, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}

Просмотреть файл

@ -21,25 +21,19 @@ function tabLoaded(aEvent) {
browser.removeEventListener("load", tabLoaded, true);
openConsole();
browser.addEventListener("load", contentLoaded, true);
content.location.reload();
}
function contentLoaded(aEvent) {
browser.removeEventListener("load", contentLoaded, true);
let button = content.document.querySelector("button");
expectUncaughtException();
EventUtils.sendMouseEvent({ type: "click" }, button, content);
executeSoon(buttonClicked);
}
function buttonClicked() {
let outputNode = HUDService.getHudByWindow(content).outputNode;
let msg = "the error from the external script was logged";
testLogEntry(outputNode, "bogus", msg);
expectUncaughtException();
EventUtils.sendMouseEvent({ type: "click" }, button, content);
finishTest();
waitForSuccess({
name: "external script error message",
validatorFn: function()
{
return outputNode.textContent.indexOf("bogus is not defined") > -1;
},
successFn: finishTest,
failureFn: finishTest,
});
}

Просмотреть файл

@ -13,17 +13,17 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te
let newTabIsOpen = false;
function tabLoaded(aEvent) {
gBrowser.selectedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
gBrowser.selectedBrowser.removeEventListener(aEvent.type, tabLoaded, true);
HUDService.activateHUDForContext(gBrowser.selectedTab);
gBrowser.selectedBrowser.addEventListener("load", tabReloaded, true);
expectUncaughtException();
content.location.reload();
openConsole(gBrowser.selectedTab, function() {
gBrowser.selectedBrowser.addEventListener("load", tabReloaded, true);
expectUncaughtException();
content.location.reload();
});
}
function tabReloaded(aEvent) {
gBrowser.selectedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
gBrowser.selectedBrowser.removeEventListener(aEvent.type, tabReloaded, true);
let hudId = HUDService.getHudIdByWindow(content);
let HUD = HUDService.hudReferences[hudId];
@ -34,26 +34,24 @@ function tabReloaded(aEvent) {
executeSoon(function() {
if (newTabIsOpen) {
testEnd();
executeSoon(finishTest);
return;
}
let newTab = gBrowser.addTab();
gBrowser.removeCurrentTab();
gBrowser.selectedTab = newTab;
closeConsole(gBrowser.selectedTab, function() {
gBrowser.removeCurrentTab();
newTabIsOpen = true;
gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
expectUncaughtException();
content.location = TEST_URI;
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
newTabIsOpen = true;
gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
expectUncaughtException();
content.location = TEST_URI;
});
});
}
function testEnd() {
gBrowser.removeCurrentTab();
executeSoon(finishTest);
}
function test() {
expectUncaughtException();
addTab(TEST_URI);

Просмотреть файл

@ -92,29 +92,37 @@ let inputValues = [
let eventHandlers = [];
let popupShown = [];
let HUD;
let testDriver;
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, tabLoad, true);
waitForFocus(function () {
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
HUD = HUDService.hudReferences[hudId];
executeSoon(testNext);
openConsole(null, function(aHud) {
HUD = aHud;
testNext();
});
}, content);
}
function subtestNext() {
testDriver.next();
}
function testNext() {
let cpos = ++pos;
if (cpos == inputValues.length) {
if (popupShown.length == inputValues.length) {
executeSoon(testEnd);
}
pos++;
if (pos == inputValues.length) {
testEnd();
return;
}
testDriver = testGen();
testDriver.next();
}
function testGen() {
let cpos = pos;
let showsPropertyPanel = inputValues[cpos][0];
let inputValue = inputValues[cpos][1];
let expectedOutput = inputValues[cpos][2];
@ -129,13 +137,26 @@ function testNext() {
HUD.jsterm.clearOutput();
// Test the console.log() output.
// Ugly but it does the job.
with (content) {
eval("HUD.console.log(" + consoleTest + ")");
}
let outputItem = HUD.outputNode.
querySelector(".hud-log:last-child");
waitForSuccess({
name: "console.log message for test #" + cpos,
validatorFn: function()
{
return HUD.outputNode.querySelector(".hud-log");
},
successFn: subtestNext,
failureFn: testNext,
});
yield;
let outputItem = HUD.outputNode.querySelector(".hud-log:last-child");
ok(outputItem,
"found the window.console output line for inputValues[" + cpos + "]");
ok(outputItem.textContent.indexOf(consoleOutput) > -1,
@ -143,6 +164,8 @@ function testNext() {
HUD.jsterm.clearOutput();
// Test jsterm print() output.
HUD.jsterm.setInputValue("print(" + inputValue + ")");
HUD.jsterm.execute();
@ -153,6 +176,8 @@ function testNext() {
ok(outputItem.textContent.indexOf(printOutput) > -1,
"jsterm print() output is correct for inputValues[" + cpos + "]");
// Test jsterm execution output.
let eventHandlerID = eventHandlers.length + 1;
let propertyPanelShown = function(aEvent) {
@ -161,7 +186,7 @@ function testNext() {
return;
}
document.removeEventListener(aEvent.type, arguments.callee, false);
document.removeEventListener(aEvent.type, propertyPanelShown, false);
eventHandlers[eventHandlerID] = null;
ok(showsPropertyPanel,
@ -170,8 +195,9 @@ function testNext() {
aEvent.target.hidePopup();
popupShown[cpos] = true;
if (popupShown.length == inputValues.length) {
executeSoon(testEnd);
if (showsPropertyPanel) {
subtestNext();
}
};
@ -192,15 +218,18 @@ function testNext() {
let messageBody = outputItem.querySelector(".webconsole-msg-body");
ok(messageBody, "we have the message body for inputValues[" + cpos + "]");
messageBody.addEventListener("click", function(aEvent) {
this.removeEventListener(aEvent.type, arguments.callee, false);
executeSoon(testNext);
}, false);
// Send the mousedown, mouseup and click events to check if the property
// panel opens.
EventUtils.sendMouseEvent({ type: "mousedown" }, messageBody, window);
EventUtils.sendMouseEvent({ type: "click" }, messageBody, window);
if (showsPropertyPanel) {
yield; // wait for the panel to open if we need to.
}
testNext();
yield;
}
function testEnd() {
@ -222,15 +251,11 @@ function testEnd() {
}
}
testDriver = null;
executeSoon(finishTest);
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);
}

Просмотреть файл

@ -8,13 +8,8 @@
*
* ***** END LICENSE BLOCK ***** */
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let HUD = HUDService.hudReferences[hudId];
function consoleOpened(HUD) {
HUD.jsterm.clearOutput();
let longMessage = "";
for (let i = 0; i < 50; i++) {
@ -33,7 +28,7 @@ function tabLoad(aEvent) {
HUD.jsterm.execute("1+1");
executeSoon(function() {
function performTest() {
let scrollBox = HUD.outputNode.scrollBoxObject.element;
isnot(scrollBox.scrollTop, 0, "scroll location is not at the top");
@ -54,16 +49,24 @@ function tabLoad(aEvent) {
"last message is visible");
finishTest();
};
waitForSuccess({
name: "console output displayed",
validatorFn: function()
{
return HUD.outputNode.itemCount == 103;
},
successFn: performTest,
failureFn: finishTest,
});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 601352");
browser.addEventListener("load", tabLoad, true);
browser.addEventListener("load", function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole(null, consoleOpened);
}, true);
}

Просмотреть файл

@ -16,21 +16,20 @@ function test()
addTab("data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 1");
tabs.push(tab);
browser.addEventListener("load", function(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.addEventListener("load", function onLoad1(aEvent) {
browser.removeEventListener(aEvent.type, onLoad1, true);
openConsole();
openConsole(null, function() {
// open tab 2
addTab("data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 2");
tabs.push(tab);
// open tab 2
addTab("data:text/html;charset=utf-8,Web Console test for bug 602572: log bodies checkbox. tab 2");
tabs.push(tab);
browser.addEventListener("load", function onLoad2(aEvent) {
browser.removeEventListener(aEvent.type, onLoad2, true);
browser.addEventListener("load", function(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
executeSoon(startTest);
}, true);
openConsole(null, startTest);
}, true);
});
}, true);
}
@ -52,7 +51,7 @@ function startTest()
function onpopupshown2(aEvent)
{
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].removeEventListener(aEvent.type, onpopupshown2, false);
// By default bodies are not logged.
isnot(menuitems[1].getAttribute("checked"), "true",
@ -63,8 +62,8 @@ function onpopupshown2(aEvent)
// Enable body logging.
HUDService.saveRequestAndResponseBodies = true;
menupopups[1].addEventListener("popuphidden", function(aEvent) {
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
// Reopen the context menu.
menupopups[1].addEventListener("popupshown", onpopupshown2b, false);
@ -75,11 +74,11 @@ function onpopupshown2(aEvent)
function onpopupshown2b(aEvent)
{
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].removeEventListener(aEvent.type, onpopupshown2b, false);
is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
menupopups[1].addEventListener("popuphidden", function(aEvent) {
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
// Switch to tab 1 and open the Web Console context menu from there.
gBrowser.selectedTab = tabs[0];
@ -102,7 +101,7 @@ function onpopupshown2b(aEvent)
function onpopupshown1(aEvent)
{
menupopups[0].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[0].removeEventListener(aEvent.type, onpopupshown1, false);
// The menuitem checkbox must be in sync with the other tabs.
is(menuitems[0].getAttribute("checked"), "true", "menuitems[0] is checked");
@ -111,8 +110,8 @@ function onpopupshown1(aEvent)
HUDService.saveRequestAndResponseBodies = false;
// Close the menu, and switch back to tab 2.
menupopups[0].addEventListener("popuphidden", function(aEvent) {
menupopups[0].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[0].addEventListener("popuphidden", function _onhidden(aEvent) {
menupopups[0].removeEventListener(aEvent.type, _onhidden, false);
gBrowser.selectedTab = tabs[1];
waitForFocus(function() {
@ -126,19 +125,20 @@ function onpopupshown1(aEvent)
function onpopupshown2c(aEvent)
{
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].removeEventListener(aEvent.type, onpopupshown2c, false);
isnot(menuitems[1].getAttribute("checked"), "true",
"menuitems[1] is not checked");
menupopups[1].addEventListener("popuphidden", function(aEvent) {
menupopups[1].removeEventListener(aEvent.type, arguments.callee, false);
menupopups[1].addEventListener("popuphidden", function _onhidden(aEvent) {
menupopups[1].removeEventListener(aEvent.type, _onhidden, false);
// Done!
huds = menuitems = menupopups = tabs = null;
HUDService.deactivateHUDForContext(gBrowser.selectedTab);
gBrowser.removeCurrentTab();
executeSoon(finishTest);
closeConsole(gBrowser.selectedTab, function() {
gBrowser.removeCurrentTab();
executeSoon(finishTest);
});
}, false);
menupopups[1].hidePopup();
}

Просмотреть файл

@ -39,7 +39,7 @@ let TestObserver = {
};
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole();
@ -52,15 +52,20 @@ function tabLoad(aEvent) {
}
function performTest() {
let textContent = hud.outputNode.textContent;
isnot(textContent.indexOf("ws://0.0.0.0:81"), -1,
"first error message found");
isnot(textContent.indexOf("ws://0.0.0.0:82"), -1,
"second error message found");
Services.console.unregisterListener(TestObserver);
Services.prefs.setBoolPref(pref_ws, oldPref_ws);
finishTest();
waitForSuccess({
name: "websocket error messages displayed",
validatorFn: function()
{
let textContent = hud.outputNode.textContent;
return textContent.indexOf("ws://0.0.0.0:81") > -1 &&
textContent.indexOf("ws://0.0.0.0:82") > -1;
},
successFn: finishTest,
failureFn: finishTest,
});
}
function test() {

Просмотреть файл

@ -7,51 +7,71 @@ const TEST_URI = 'data:text/html;charset=utf-8,<div style="-moz-opacity:0;">test
function onContentLoaded()
{
browser.removeEventListener("load", arguments.callee, true);
browser.removeEventListener("load", onContentLoaded, true);
let HUD = HUDService.getHudByWindow(content);
let jsterm = HUD.jsterm;
let outputNode = HUD.outputNode;
let msg = "The unknown CSS property warning is displayed only once";
let node = outputNode.firstChild;
let cssWarning = "Unknown property '-moz-opacity'. Declaration dropped.";
is(node.childNodes[2].textContent, "Unknown property '-moz-opacity'. Declaration dropped.", "correct node")
is(node.childNodes[3].firstChild.getAttribute("value"), 2, msg);
waitForSuccess({
name: "2 repeated CSS warnings",
validatorFn: function()
{
return outputNode.textContent.indexOf(cssWarning) > -1;
},
successFn: function()
{
let msg = "The unknown CSS property warning is displayed only once";
let node = outputNode.firstChild;
is(node.childNodes[2].textContent, cssWarning, "correct node");
is(node.childNodes[3].firstChild.getAttribute("value"), 2, msg);
testConsoleLogRepeats();
},
failureFn: finishTest,
});
}
function testConsoleLogRepeats()
{
let HUD = HUDService.getHudByWindow(content);
let jsterm = HUD.jsterm;
let outputNode = HUD.outputNode;
jsterm.clearOutput();
jsterm.setInputValue("for (let i = 0; i < 10; ++i) console.log('this is a line of reasonably long text that I will use to verify that the repeated text node is of an appropriate size.');");
jsterm.execute();
let msg = "The console output is repeated 10 times";
let node = outputNode.querySelector(".webconsole-msg-console");
is(node.childNodes[3].firstChild.getAttribute("value"), 10, msg);
jsterm.clearOutput();
finishTest();
waitForSuccess({
name: "10 repeated console.log messages",
validatorFn: function()
{
let node = outputNode.querySelector(".webconsole-msg-console");
return node && node.childNodes[3].firstChild.getAttribute("value") == 10;
},
successFn: finishTest,
failureFn: finishTest,
});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
/**
* Unit test for bug 611795:
* Repeated CSS messages get collapsed into one.
*/
function test()
{
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);
openConsole();
// Clear cached messages that are shown once the Web Console opens.
HUDService.getHudByWindow(content).jsterm.clearOutput(true);
browser.addEventListener("load", onContentLoaded, true);
content.location.reload();
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, function(aHud) {
// Clear cached messages that are shown once the Web Console opens.
aHud.jsterm.clearOutput(true);
browser.addEventListener("load", onContentLoaded, true);
content.location.reload();
});
}, true);
}

Просмотреть файл

@ -8,12 +8,7 @@
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 613280";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}
@ -74,6 +69,6 @@ function tabLoaded() {
}
function getExpectedClipboardText(aItem) {
return "[" + ConsoleUtils.timestampString(aItem.timestamp) + "] " +
return "[" + WebConsoleUtils.l10n.timestampString(aItem.timestamp) + "] " +
aItem.clipboardText;
}

Просмотреть файл

@ -7,13 +7,14 @@
* Mihai Șucan <mihai.sucan@gmail.com>
*/
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
let hud, testDriver;
openConsole();
function testNext() {
testDriver.next();
}
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function testGen() {
hud.jsterm.clearOutput();
let outputNode = hud.outputNode;
let scrollBox = outputNode.scrollBoxObject.element;
@ -21,6 +22,18 @@ function tabLoad(aEvent) {
hud.console.log("test message " + i);
}
waitForSuccess({
name: "150 console.log messages displayed",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-log").length == 150;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
let oldScrollTop = scrollBox.scrollTop;
ok(oldScrollTop > 0, "scroll location is not at the top");
@ -32,30 +45,60 @@ function tabLoad(aEvent) {
let topPosition = scrollBox.scrollTop;
isnot(topPosition, oldScrollTop, "scroll location updated (moved to top)");
executeSoon(function() {
// add a message and make sure scroll doesn't change
hud.console.log("test message 150");
// add a message and make sure scroll doesn't change
hud.console.log("test message 150");
is(scrollBox.scrollTop, topPosition, "scroll location is still at the top");
// scroll back to the bottom
outputNode.lastChild.focus();
EventUtils.synthesizeKey("VK_END", {});
executeSoon(function() {
oldScrollTop = outputNode.scrollTop;
hud.console.log("test message 151");
isnot(scrollBox.scrollTop, oldScrollTop,
"scroll location updated (moved to bottom)");
finishTest();
});
waitForSuccess({
name: "console.log message no. 151 displayed",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-log").length == 151;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
is(scrollBox.scrollTop, topPosition, "scroll location is still at the top");
// scroll back to the bottom
outputNode.lastChild.focus();
EventUtils.synthesizeKey("VK_END", {});
oldScrollTop = outputNode.scrollTop;
hud.console.log("test message 151");
waitForSuccess({
name: "console.log message no. 152 displayed",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-log").length == 152;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
isnot(scrollBox.scrollTop, oldScrollTop,
"scroll location updated (moved to bottom)");
hud = testDriver = null;
finishTest();
yield;
}
function test() {
addTab("data:text/html;charset=utf-8,Web Console test for bug 613642: remember scroll location");
browser.addEventListener("load", tabLoad, true);
browser.addEventListener("load", function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole(null, function(aHud) {
hud = aHud;
testDriver = testGen();
testDriver.next();
});
}, true);
}

Просмотреть файл

@ -7,13 +7,15 @@
* Mihai Șucan <mihai.sucan@gmail.com>
*/
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
let hud, testDriver;
openConsole();
function testNext() {
testDriver.next();
}
function testGen() {
hud.jsterm.clearOutput();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
let outputNode = hud.outputNode;
let oldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console");
@ -25,6 +27,18 @@ function tabLoad(aEvent) {
hud.console.log("test message " + i);
}
waitForSuccess({
name: "150 console.log messages displayed",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-log").length == 140;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
let oldScrollTop = scrollBoxElement.scrollTop;
ok(oldScrollTop > 0, "scroll location is not at the top");
@ -45,6 +59,18 @@ function tabLoad(aEvent) {
// add a message
hud.console.log("hello world");
waitForSuccess({
name: "console.log message #151 displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("hello world") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
// Scroll location needs to change, because one message is also removed, and
// we need to scroll a bit towards the top, to keep the current view in sync.
isnot(scrollBoxElement.scrollTop, oldScrollTop,
@ -54,10 +80,22 @@ function tabLoad(aEvent) {
"first message removed");
Services.prefs.setIntPref("devtools.hud.loglimit.console", oldPref);
hud = testDriver = null;
finishTest();
yield;
}
function test() {
addTab("data:text/html;charset=utf-8,Web Console test for bug 613642: maintain scroll with pruning of old messages");
browser.addEventListener("load", tabLoad, true);
browser.addEventListener("load", function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole(null, function(aHud) {
hud = aHud;
testDriver = testGen();
testDriver.next();
});
}, true);
}

Просмотреть файл

@ -7,13 +7,9 @@
* Mihai Șucan <mihai.sucan@gmail.com>
*/
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
function consoleOpened(hud) {
hud.jsterm.clearOutput();
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
let outputNode = hud.outputNode;
let boxObject = outputNode.scrollBoxObject.element;
@ -21,28 +17,37 @@ function tabLoad(aEvent) {
hud.console.log("test message " + i);
}
let oldScrollTop = boxObject.scrollTop;
ok(oldScrollTop > 0, "scroll location is not at the top");
waitForSuccess({
name: "console.log messages displayed",
validatorFn: function()
{
return outputNode.itemCount == 150;
},
successFn: function()
{
let oldScrollTop = boxObject.scrollTop;
ok(oldScrollTop > 0, "scroll location is not at the top");
hud.jsterm.execute("'hello world'");
hud.jsterm.execute("'hello world'");
isnot(boxObject.scrollTop, oldScrollTop, "scroll location updated");
isnot(boxObject.scrollTop, oldScrollTop, "scroll location updated");
oldScrollTop = boxObject.scrollTop;
outputNode.scrollBoxObject.ensureElementIsVisible(outputNode.lastChild);
oldScrollTop = boxObject.scrollTop;
outputNode.scrollBoxObject.ensureElementIsVisible(outputNode.lastChild);
is(boxObject.scrollTop, oldScrollTop, "scroll location is the same");
is(boxObject.scrollTop, oldScrollTop, "scroll location is the same");
finishTest();
finishTest();
},
failureFn: finishTest,
});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 614793: jsterm result scroll");
browser.addEventListener("load", tabLoad, true);
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, consoleOpened);
}, true);
}

Просмотреть файл

@ -53,57 +53,50 @@ let TestObserver = {
is(aSubject.category, "content javascript", "error category");
testEnded = true;
if (aSubject.category == "content javascript") {
executeSoon(checkOutput);
}
else {
testEnd();
executeSoon(finishTest);
}
}
};
function checkOutput()
{
if (testEnded) {
return;
}
let textContent = hud.outputNode.textContent;
isnot(textContent.indexOf("bug618078exception"), -1,
"exception message");
testEnd();
waitForSuccess({
name: "exception message",
validatorFn: function()
{
return hud.outputNode.textContent.indexOf("bug618078exception") > -1;
},
successFn: finishTest,
failureFn: finishTest,
});
}
function testEnd()
{
if (testEnded) {
return;
}
testEnded = true;
Services.console.unregisterListener(TestObserver);
finishTest();
}
function test()
{
addTab("data:text/html;charset=utf-8,Web Console test for bug 618078");
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole();
openConsole(null, function(aHud) {
hud = aHud;
Services.console.registerListener(TestObserver);
registerCleanupFunction(testEnd);
let hudId = HUDService.getHudIdByWindow(content);
hud = HUDService.hudReferences[hudId];
Services.console.registerListener(TestObserver);
registerCleanupFunction(testEnd);
executeSoon(function() {
expectUncaughtException();
content.location = TEST_URI;
executeSoon(function() {
expectUncaughtException();
content.location = TEST_URI;
});
});
}, true);
}

Просмотреть файл

@ -38,12 +38,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);

Просмотреть файл

@ -41,16 +41,11 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 618311 (private browsing)");
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
registerCleanupFunction(function() {
pb.privateBrowsingEnabled = false;
@ -62,9 +57,10 @@ function test() {
togglePBAndThen(function() {
ok(pb.privateBrowsingEnabled, "private browsing is enabled");
HUDService.activateHUDForContext(gBrowser.selectedTab);
content.location = TEST_URI;
gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
openConsole(gBrowser.selectedTab, function() {
content.location = TEST_URI;
gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
});
});
}, true);
}
@ -133,6 +129,7 @@ function tabLoaded() {
ok(!pb.privateBrowsingEnabled, "private browsing is not enabled");
gBrowser.removeCurrentTab();
executeSoon(finishTest);
});
}

Просмотреть файл

@ -10,14 +10,9 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-621644-jsterm-dollar.html";
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
waitForFocus(function () {
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let HUD = HUDService.hudReferences[hudId];
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole(null, function(HUD) {
HUD.jsterm.clearOutput();
HUD.jsterm.setInputValue("$(document.body)");
@ -39,15 +34,10 @@ function tabLoad(aEvent) {
"jsterm output is correct for $$()");
executeSoon(finishTest);
}, content);
});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);
}

Просмотреть файл

@ -1,42 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let itemsSet, HUD;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
let itemsSet, HUD, outputNode;
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 626484");
browser.addEventListener("load", tabLoaded, true);
browser.addEventListener("load", function tabLoaded(aEvent) {
browser.removeEventListener(aEvent.type, tabLoaded, true);
openConsole(null, consoleOpened);
}, true);
}
function tabLoaded(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
let console = browser.contentWindow.wrappedJSObject.console;
function consoleOpened(aHud) {
HUD = aHud;
outputNode = HUD.outputNode;
HUD.jsterm.clearOutput();
let console = content.wrappedJSObject.console;
console.log("The first line.");
console.log("The second line.");
console.log("The last line.");
let hudId = HUDService.getHudIdByWindow(content);
HUD = HUDService.hudReferences[hudId];
outputNode = HUD.outputNode;
itemsSet = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1],
[2, 1, 0]];
nextTest();
waitForSuccess({
name: "console.log messages displayed",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-log").length == 3;
},
successFn: nextTest,
failureFn: finishTest,
});
}
function nextTest() {
if (itemsSet.length === 0) {
outputNode.clearSelection();
HUD.jsterm.clearOutput();
HUD = null;
finish();
HUD = outputNode = null;
executeSoon(finishTest);
}
else {
outputNode.clearSelection();
@ -55,7 +58,7 @@ function getExpectedClipboardText(aItemCount) {
for (let i = 0; i < aItemCount; i++) {
let item = outputNode.getItemAtIndex(i);
expectedClipboardText.push("[" +
ConsoleUtils.timestampString(item.timestamp) + "] " +
WebConsoleUtils.l10n.timestampString(item.timestamp) + "] " +
item.clipboardText);
}
return expectedClipboardText.join("\n");

Просмотреть файл

@ -3,12 +3,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-632275-getters.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}

Просмотреть файл

@ -38,18 +38,18 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-632347-iterators-generators.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}
function tabLoaded() {
browser.removeEventListener("load", tabLoaded, true);
let tmp = {};
Cu.import("resource:///modules/WebConsoleUtils.jsm", tmp);
let WCU = tmp.WebConsoleUtils;
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
@ -62,7 +62,7 @@ function tabLoaded() {
let result = win.gen1.next();
let completion = jsterm.propertyProvider(win, "gen1.");
is(completion, null, "no matchees for gen1");
ok(!jsterm.isResultInspectable(win.gen1),
ok(!WCU.isObjectInspectable(win.gen1),
"gen1 is not inspectable");
is(result+1, win.gen1.next(), "gen1.next() did not execute");
@ -71,7 +71,7 @@ function tabLoaded() {
completion = jsterm.propertyProvider(win, "gen2.");
is(completion, null, "no matchees for gen2");
ok(!jsterm.isResultInspectable(win.gen2),
ok(!WCU.isObjectInspectable(win.gen2),
"gen2 is not inspectable");
is((result/2+1)*2, win.gen2.next(),
@ -83,7 +83,7 @@ function tabLoaded() {
completion = jsterm.propertyProvider(win, "iter1.");
is(completion, null, "no matchees for iter1");
ok(!jsterm.isResultInspectable(win.iter1),
ok(!WCU.isObjectInspectable(win.iter1),
"iter1 is not inspectable");
result = win.iter1.next();
@ -92,13 +92,13 @@ function tabLoaded() {
completion = jsterm.propertyProvider(content, "iter2.");
is(completion, null, "no matchees for iter2");
ok(!jsterm.isResultInspectable(win.iter2),
ok(!WCU.isObjectInspectable(win.iter2),
"iter2 is not inspectable");
completion = jsterm.propertyProvider(win, "window.");
ok(completion, "matches available for window");
ok(completion.matches.length, "matches available for window (length)");
ok(jsterm.isResultInspectable(win),
ok(WCU.isObjectInspectable(win),
"window is inspectable");
let panel = jsterm.openPropertyPanel("Test", win);

Просмотреть файл

@ -76,12 +76,7 @@ function tabLoad(aEvent) {
EventUtils.synthesizeKey("u", {});
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);
}

Просмотреть файл

@ -10,67 +10,91 @@
const TEST_URI = "http://example.com/browser/browser/devtools/" +
"webconsole/test/test-bug-644419-log-limits.html";
var gOldPref, gHudId;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
var gOldPref;
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 644419: Console should " +
"have user-settable log limits for each message category");
browser.addEventListener("load", onLoad, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole();
openConsole(null, function(aHud) {
aHud.jsterm.clearOutput();
hud = aHud;
outputNode = aHud.outputNode;
gHudId = HUDService.getHudIdByWindow(content);
browser.addEventListener("load", testWebDevLimits, true);
expectUncaughtException();
content.location = TEST_URI;
}
function testWebDevLimits(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console");
Services.prefs.setIntPref("devtools.hud.loglimit.console", 10);
let hud = HUDService.hudReferences[gHudId];
outputNode = hud.outputNode;
executeSoon(function() {
// Find the sentinel entry.
findLogEntry("bar is not defined");
// Fill the log with Web Developer errors.
for (let i = 0; i < 11; i++) {
hud.console.log("test message " + i);
}
testLogEntry(outputNode, "test message 0", "first message is pruned", false, true);
findLogEntry("test message 1");
// Check if the sentinel entry is still there.
findLogEntry("bar is not defined");
Services.prefs.setIntPref("devtools.hud.loglimit.console", gOldPref);
testJsLimits();
browser.addEventListener("load", testWebDevLimits, true);
expectUncaughtException();
content.location = TEST_URI;
});
}
function testJsLimits(aEvent) {
function testWebDevLimits(aEvent) {
browser.removeEventListener(aEvent.type, testWebDevLimits, true);
gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console");
Services.prefs.setIntPref("devtools.hud.loglimit.console", 10);
// Find the sentinel entry.
waitForSuccess({
name: "bar is not defined",
validatorFn: function()
{
return outputNode.textContent.indexOf("bar is not defined") > -1;
},
successFn: testWebDevLimits2,
failureFn: testWebDevLimits2,
});
}
function testWebDevLimits2() {
// Fill the log with Web Developer errors.
for (let i = 0; i < 11; i++) {
hud.console.log("test message " + i);
}
waitForSuccess({
name: "11 console.log messages displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("test message 10") > -1;
},
successFn: function()
{
testLogEntry(outputNode, "test message 0", "first message is pruned", false, true);
findLogEntry("test message 1");
// Check if the sentinel entry is still there.
findLogEntry("bar is not defined");
Services.prefs.setIntPref("devtools.hud.loglimit.console", gOldPref);
testJsLimits();
},
failureFn: testJsLimits,
});
}
function testJsLimits() {
gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.exception");
Services.prefs.setIntPref("devtools.hud.loglimit.exception", 10);
let hud = HUDService.hudReferences[gHudId];
hud.jsterm.clearOutput();
outputNode = hud.outputNode;
hud.console.log("testing JS limits");
// Find the sentinel entry.
findLogEntry("testing JS limits");
waitForSuccess({
name: "console.log 'testing JS limits'",
validatorFn: function()
{
return outputNode.textContent.indexOf("testing JS limits") > -1;
},
successFn: testJsLimits2,
failureFn: testNetLimits,
});
}
function testJsLimits2() {
// Fill the log with JS errors.
let head = content.document.getElementsByTagName("head")[0];
for (let i = 0; i < 11; i++) {
@ -80,33 +104,50 @@ function testJsLimits(aEvent) {
head.insertBefore(script, head.firstChild);
}
executeSoon(function() {
testLogEntry(outputNode, "fubar0 is not defined", "first message is pruned", false, true);
findLogEntry("fubar1 is not defined");
// Check if the sentinel entry is still there.
findLogEntry("testing JS limits");
waitForSuccess({
name: "10 JS errors shown",
validatorFn: function()
{
return outputNode.textContent.indexOf("fubar10 is not defined") > -1;
},
successFn: function()
{
testLogEntry(outputNode, "fubar0 is not defined", "first message is pruned", false, true);
findLogEntry("fubar1 is not defined");
// Check if the sentinel entry is still there.
findLogEntry("testing JS limits");
Services.prefs.setIntPref("devtools.hud.loglimit.exception", gOldPref);
testNetLimits();
Services.prefs.setIntPref("devtools.hud.loglimit.exception", gOldPref);
testNetLimits();
},
failureFn: testNetLimits,
});
}
var gCounter, gImage;
function testNetLimits(aEvent) {
function testNetLimits() {
gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.network");
Services.prefs.setIntPref("devtools.hud.loglimit.network", 10);
let hud = HUDService.hudReferences[gHudId];
hud.jsterm.clearOutput();
outputNode = hud.outputNode;
hud.console.log("testing Net limits");
// Find the sentinel entry.
findLogEntry("testing Net limits");
// Fill the log with network messages.
gCounter = 0;
loadImage();
waitForSuccess({
name: "console.log 'testing Net limits'",
validatorFn: function()
{
return outputNode.textContent.indexOf("testing Net limits") > -1;
},
successFn: function()
{
// Fill the log with network messages.
gCounter = 0;
loadImage();
},
failureFn: testCssLimits,
});
}
function loadImage() {
@ -130,18 +171,26 @@ function loadImage() {
testCssLimits();
}
function testCssLimits(aEvent) {
function testCssLimits() {
gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.cssparser");
Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", 10);
let hud = HUDService.hudReferences[gHudId];
hud.jsterm.clearOutput();
outputNode = hud.outputNode;
hud.console.log("testing CSS limits");
// Find the sentinel entry.
findLogEntry("testing CSS limits");
waitForSuccess({
name: "console.log 'testing CSS limits'",
validatorFn: function()
{
return outputNode.textContent.indexOf("testing CSS limits") > -1;
},
successFn: testCssLimits2,
failureFn: finishTest,
});
}
function testCssLimits2() {
// Fill the log with CSS errors.
let body = content.document.getElementsByTagName("body")[0];
for (let i = 0; i < 11; i++) {
@ -149,13 +198,24 @@ function testCssLimits(aEvent) {
div.setAttribute("style", "-moz-foobar" + i + ": 42;");
body.insertBefore(div, body.firstChild);
}
executeSoon(function() {
testLogEntry(outputNode, "Unknown property '-moz-foobar0'", "first message is pruned", false, true);
findLogEntry("Unknown property '-moz-foobar1'");
// Check if the sentinel entry is still there.
findLogEntry("testing CSS limits");
Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", gOldPref);
finishTest();
waitForSuccess({
name: "10 CSS errors shown",
validatorFn: function()
{
return outputNode.textContent.indexOf("-moz-foobar10") > -1;
},
successFn: function()
{
testLogEntry(outputNode, "Unknown property '-moz-foobar0'",
"first message is pruned", false, true);
findLogEntry("Unknown property '-moz-foobar1'");
// Check if the sentinel entry is still there.
findLogEntry("testing CSS limits");
Services.prefs.setIntPref("devtools.hud.loglimit.cssparser", gOldPref);
finishTest();
},
failureFn: finishTest,
});
}

Просмотреть файл

@ -13,12 +13,7 @@ let PropertyTreeView = tempScope.PropertyTreeView;
let namesAndValuesOf = tempScope.namesAndValuesOf;
let isNonNativeGetter = tempScope.isNonNativeGetter;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console autocompletion bug in document.body");
browser.addEventListener("load", onLoad, true);
}

Просмотреть файл

@ -97,7 +97,7 @@ function runSelectionTests()
});
}
function performTestComparisons(evt)
function performTestComparisons()
{
InspectorUI.highlighter.removeListener("nodeselected", performTestComparisons);
@ -105,9 +105,11 @@ function performTestComparisons(evt)
is(InspectorUI.highlighter.node, h1, "node selected");
is(InspectorUI.selection, h1, "selection matches node");
HUDService.activateHUDForContext(gBrowser.selectedTab);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
openConsole(gBrowser.selectedTab, performWebConsoleTests);
}
function performWebConsoleTests(hud)
{
let jsterm = hud.jsterm;
outputNode = hud.outputNode;
@ -127,17 +129,11 @@ function performTestComparisons(evt)
function finishUp() {
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
finishTest();
}
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test()
{
Services.prefs.setBoolPref("devtools.gcli.enable", false);
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {

Просмотреть файл

@ -6,23 +6,16 @@
// Tests that the Console API implements the time() and timeEnd() methods.
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("http://example.com/browser/browser/devtools/webconsole/" +
"test/test-bug-658368-time-methods.html");
openConsole();
browser.addEventListener("load", onLoad, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function consoleOpened(hud) {
outputNode = hud.outputNode;
executeSoon(function() {
@ -33,16 +26,14 @@ function onLoad(aEvent) {
// tabs, do not contain the same value.
addTab("data:text/html;charset=utf-8,<script type='text/javascript'>" +
"console.timeEnd('bTimer');</script>");
openConsole();
browser.addEventListener("load", testTimerIndependenceInTabs, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, testTimerIndependenceInTabs);
}, true);
});
}
function testTimerIndependenceInTabs(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInTabs, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function testTimerIndependenceInTabs(hud) {
outputNode = hud.outputNode;
executeSoon(function() {
@ -51,15 +42,16 @@ function testTimerIndependenceInTabs(aEvent) {
// The next test makes sure that timers with the same name but in separate
// pages, do not contain the same value.
browser.addEventListener("load", testTimerIndependenceInSameTab, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
executeSoon(testTimerIndependenceInSameTab);
}, true);
content.location = "data:text/html;charset=utf-8,<script type='text/javascript'>" +
"console.time('bTimer');</script>";
});
}
function testTimerIndependenceInSameTab(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTab, true);
function testTimerIndependenceInSameTab() {
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
@ -70,15 +62,16 @@ function testTimerIndependenceInSameTab(aEvent) {
// Now the following console.timeEnd() call shouldn't display anything,
// if the timers in different pages are not related.
browser.addEventListener("load", testTimerIndependenceInSameTabAgain, true);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
executeSoon(testTimerIndependenceInSameTabAgain);
}, true);
content.location = "data:text/html;charset=utf-8,<script type='text/javascript'>" +
"console.timeEnd('bTimer');</script>";
});
}
function testTimerIndependenceInSameTabAgain(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTabAgain, true);
function testTimerIndependenceInSameTabAgain(hud) {
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
@ -87,6 +80,9 @@ function testTimerIndependenceInSameTabAgain(aEvent) {
testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
false, true);
finishTest();
closeConsole(gBrowser.selectedTab, function() {
gBrowser.removeCurrentTab();
executeSoon(finishTest);
});
});
}

Просмотреть файл

@ -9,37 +9,48 @@
function test() {
addTab("data:text/html;charset=utf-8,Web Console test for bug 659907: Expand console " +
"object with a dir method");
browser.addEventListener("load", onLoad, true);
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function consoleOpened(hud) {
outputNode = hud.outputNode;
content.console.dir(content.document);
findLogEntry("[object HTMLDocument");
waitForSuccess({
name: "console.dir displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("[object HTMLDocument") > -1;
},
successFn: testConsoleDir.bind(null, outputNode),
failureFn: finishTest,
});
}
function testConsoleDir(outputNode) {
let msg = outputNode.querySelectorAll(".webconsole-msg-inspector");
is(msg.length, 1, "one message node displayed");
let rows = msg[0].propertyTreeView._rows;
let view = msg[0].propertyTreeView;
let foundQSA = false;
let foundLocation = false;
let foundWrite = false;
for (let i = 0; i < rows.length; i++) {
if (rows[i].display == "querySelectorAll: function querySelectorAll()") {
for (let i = 0; i < view.rowCount; i++) {
let text = view.getCellText(i);
if (text == "querySelectorAll: function querySelectorAll()") {
foundQSA = true;
}
else if (rows[i].display == "location: Object") {
else if (text == "location: Object") {
foundLocation = true;
}
else if (rows[i].display == "write: function write()") {
else if (text == "write: function write()") {
foundWrite = true;
}
}
ok(foundQSA, "found document.querySelectorAll");
ok(foundLocation, "found document.location");
ok(foundWrite, "found document.write");
finishTest();
msg = view = outputNode = null;
executeSoon(finishTest);
}

Просмотреть файл

@ -4,12 +4,7 @@
const TEST_URI = "data:text/html;charset=utf-8,<p>bug 660806 - history navigation must not show the autocomplete popup";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}

Просмотреть файл

@ -7,55 +7,127 @@
// Tests that console.group/groupEnd works as intended.
const GROUP_INDENT = 12;
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
let testDriver, hud;
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab("data:text/html;charset=utf-8,Web Console test for bug 664131: Expand console " +
"object with group methods");
browser.addEventListener("load", onLoad, true);
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, function(aHud) {
hud = aHud;
testDriver = testGen();
testNext();
});
}, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
function testNext() {
testDriver.next();
}
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
function testGen() {
outputNode = hud.outputNode;
content.console.group("a");
findLogEntry("a");
hud.jsterm.clearOutput();
content.console.group("bug664131a");
waitForSuccess({
name: "console.group displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug664131a") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 1, "one message node displayed");
is(msg[0].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
content.console.log("inside");
findLogEntry("inside");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
content.console.log("bug664131a-inside");
waitForSuccess({
name: "console.log message displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug664131a-inside") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 2, "two message nodes displayed");
is(msg[1].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
content.console.groupEnd("a");
content.console.log("outside");
findLogEntry("outside");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
content.console.groupEnd("bug664131a");
content.console.log("bug664131-outside");
waitForSuccess({
name: "console.log message displayed after groupEnd()",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug664131-outside") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 3, "three message nodes displayed");
is(msg[2].style.marginLeft, "0px", "correct group indent found");
content.console.groupCollapsed("b");
findLogEntry("b");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
content.console.groupCollapsed("bug664131b");
waitForSuccess({
name: "console.groupCollapsed displayed",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug664131b") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 4, "four message nodes displayed");
is(msg[3].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
// Test that clearing the console removes the indentation.
hud.jsterm.clearOutput();
content.console.log("cleared");
findLogEntry("cleared");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
content.console.log("bug664131-cleared");
waitForSuccess({
name: "console.log displayed after clearOutput",
validatorFn: function()
{
return outputNode.textContent.indexOf("bug664131-cleared") > -1;
},
successFn: testNext,
failureFn: finishTest,
});
yield;
msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 1, "one message node displayed");
is(msg[0].style.marginLeft, "0px", "correct group indent found");
testDriver = hud = null;
finishTest();
yield;
}

Просмотреть файл

@ -40,12 +40,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testCompletion, false);
}

Просмотреть файл

@ -40,22 +40,16 @@
// Tests that code completion works properly.
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(getBrowserURL());
browser.addEventListener("DOMContentLoaded", testChrome, false);
browser.addEventListener("DOMContentLoaded", function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, true);
openConsole();
testChrome(HUDService.getHudByWindow(content));
}, true);
}
function testChrome() {
browser.removeEventListener("DOMContentLoaded", testChrome, false);
openConsole();
let hud = HUDService.getHudByWindow(content);
function testChrome(hud) {
ok(hud, "we have a console");
ok(hud.HUDBox, "we have the console display");
@ -72,6 +66,7 @@ function testChrome() {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
is(jsterm.completeNode.value, " ment", "'docu' completion");
finishTest();
gBrowser.removeCurrentTab();
executeSoon(finishTest);
}

Просмотреть файл

@ -42,12 +42,7 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", testCompletion, false);
}

Просмотреть файл

@ -41,25 +41,31 @@ const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/te
function test() {
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", onLoad, false);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
let doc = content.document;
openConsole();
let button = doc.querySelector("button");
function consoleOpened(hud) {
waitForSuccess({
name: "two nodes displayed",
validatorFn: function()
{
return hud.outputNode.querySelectorAll(".hud-msg-node").length == 2;
},
successFn: function()
{
let nodes = hud.outputNode.querySelectorAll(".hud-msg-node");
ok(/start/.test(nodes[0].textContent), "start found");
ok(/end/.test(nodes[1].textContent), "end found - complete!");
finishTest();
},
failureFn: finishTest,
});
let button = content.document.querySelector("button");
ok(button, "we have the button");
EventUtils.sendMouseEvent({ type: "click" }, button, content);
executeSoon(testButtonClicked);
}
function testButtonClicked()
{
let outputNode = HUDService.getHudByWindow(content).outputNode;
let nodes = outputNode.querySelectorAll(".hud-msg-node");
is(nodes.length, 2, "two nodes");
ok(/start/.test(nodes[0].textContent), "start found");
ok(/end/.test(nodes[1].textContent), "end found - complete!");
finishTest();
}

Просмотреть файл

@ -42,32 +42,52 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
let testDriver = null;
let subtestDriver = null;
function test() {
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("DOMContentLoaded", onLoad, false);
}
function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
openConsole();
openConsole(null, function(aHud) {
hud = aHud;
hudId = hud.hudId;
outputNode = hud.outputNode;
testDriver = testGen();
testDriver.next();
});
}
hud = HUDService.getHudByWindow(content);
hudId = hud.hudId;
outputNode = hud.outputNode;
function testGen() {
subtestGen("log");
yield;
testConsoleLoggingAPI("log");
testConsoleLoggingAPI("info");
testConsoleLoggingAPI("warn");
testConsoleLoggingAPI("error");
testConsoleLoggingAPI("debug"); // bug 616742
subtestGen("info");
yield;
subtestGen("warn");
yield;
subtestGen("error");
yield;
subtestGen("debug"); // bug 616742
yield;
testDriver = subtestDriver = null;
finishTest();
yield;
}
function subtestGen(aMethod) {
subtestDriver = testConsoleLoggingAPI(aMethod);
subtestDriver.next();
}
function testConsoleLoggingAPI(aMethod) {
@ -79,9 +99,21 @@ function testConsoleLoggingAPI(aMethod) {
console[aMethod]("foo-bar-baz");
console[aMethod]("bar-baz");
var nodes = outputNode.querySelectorAll(".hud-filtered-by-string");
function nextTest() {
subtestDriver.next();
}
is(nodes.length, 1, "1 hidden " + aMethod + " node found (via classList)");
waitForSuccess({
name: "1 hidden " + aMethod + " node via string filtering",
validatorFn: function()
{
return outputNode.querySelectorAll(".hud-filtered-by-string").length == 1;
},
successFn: nextTest,
failureFn: nextTest,
});
yield;
hud.jsterm.clearOutput();
@ -91,16 +123,34 @@ function testConsoleLoggingAPI(aMethod) {
setStringFilter(hudId, "");
HUDService.setFilterState(hudId, aMethod, false);
console[aMethod]("foo-bar-baz");
nodes = outputNode.querySelectorAll("description");
is(nodes.length, 1, aMethod + " logging turned off, 1 message hidden");
waitForSuccess({
name: "1 message hidden for " + aMethod + " (logging turned off)",
validatorFn: function()
{
return outputNode.querySelectorAll("description").length == 1;
},
successFn: nextTest,
failureFn: nextTest,
});
yield;
hud.jsterm.clearOutput();
HUDService.setFilterState(hudId, aMethod, true);
console[aMethod]("foo-bar-baz");
nodes = outputNode.querySelectorAll("description");
is(nodes.length, 1, aMethod + " logging turned on, 1 message shown");
waitForSuccess({
name: "1 message shown for " + aMethod + " (logging turned on)",
validatorFn: function()
{
return outputNode.querySelectorAll("description").length == 1;
},
successFn: nextTest,
failureFn: nextTest,
});
yield;
hud.jsterm.clearOutput();
setStringFilter(hudId, "");
@ -108,9 +158,20 @@ function testConsoleLoggingAPI(aMethod) {
// test for multiple arguments.
console[aMethod]("foo", "bar");
let node = outputNode.querySelector(".hud-msg-node");
ok(/foo bar/.test(node.textContent),
"Emitted both console arguments");
waitForSuccess({
name: "show both console arguments for " + aMethod,
validatorFn: function()
{
let node = outputNode.querySelector(".hud-msg-node");
return node && /foo bar/.test(node.textContent);
},
successFn: nextTest,
failureFn: nextTest,
});
yield;
testDriver.next();
yield;
}
function setStringFilter(aId, aValue) {

Просмотреть файл

@ -11,13 +11,8 @@
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-own-console.html";
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.gcli.enable");
});
function test()
{
Services.prefs.setBoolPref("devtools.gcli.enable", false);
addTab(TEST_URI);
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше