This commit is contained in:
Doug Turner 2011-11-07 10:20:27 -08:00
commit 6cda9cb5f1
381 changed files with 5898 additions and 2898 deletions

View File

@ -213,6 +213,8 @@ maybe_clobber_profiledbuild:
endif
else
maybe_clobber_profiledbuild:
$(RM) $(DIST)/bin/*.pgc
find $(DIST)/$(MOZ_APP_NAME) -name "*.pgc" -exec mv {} $(DIST)/bin \;
endif
.PHONY: maybe_clobber_profiledbuild

View File

@ -1008,6 +1008,9 @@ pref("devtools.inspector.enabled", true);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);
// Enable the rules view
pref("devtools.ruleview.enabled", true);
// Enable the Scratchpad tool.
pref("devtools.scratchpad.enabled", true);

View File

@ -3908,12 +3908,29 @@ var FullScreen = {
}
},
exitDomFullScreen : function(e) {
document.mozCancelFullScreen();
},
enterDomFullScreen : function(event) {
if (!document.mozFullScreen) {
// We receive "mozfullscreenchange" events for each subdocument which
// is an ancestor of the document containing the element which requested
// full-screen. Only add listeners and show warning etc when the event we
// receive is targeted at the chrome document, i.e. only once every time
// we enter DOM full-screen mode.
if (!document.mozFullScreen || event.target.ownerDocument != document) {
return;
}
this.showWarning(true);
// Exit DOM full-screen mode upon open, close, or change tab.
gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen);
gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen);
// Exit DOM full-screen mode when the browser window loses focus (ALT+TAB, etc).
window.addEventListener("deactivate", this.exitDomFullScreen, true);
// Cancel any "hide the toolbar" animation which is in progress, and make
// the toolbar hide immediately.
clearInterval(this._animationInterval);
@ -3946,6 +3963,10 @@ var FullScreen = {
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
}
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
window.removeEventListener("deactivate", this.exitDomFullScreen, true);
}
},
@ -8169,7 +8190,7 @@ let DownloadMonitorPanel = {
let maxTime = -Infinity;
let dls = gDownloadMgr.activeDownloads;
while (dls.hasMoreElements()) {
let dl = dls.getNext().QueryInterface(Ci.nsIDownload);
let dl = dls.getNext();
if (dl.state == gDownloadMgr.DOWNLOAD_DOWNLOADING) {
// Figure out if this download takes longer
if (dl.speed > 0 && dl.size > 0)

View File

@ -967,7 +967,7 @@
<statuspanel id="statusbar-display" inactive="true"/>
</vbox>
<splitter id="devtools-side-splitter" hidden="true"/>
<vbox id="devtools-sidebar-box" hidden="true" flex="1"
<vbox id="devtools-sidebar-box" hidden="true"
style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
<toolbar id="devtools-sidebar-toolbar" nowindowdrag="true"/>
<deck id="devtools-sidebar-deck" flex="1"/>

View File

@ -1108,6 +1108,7 @@
<![CDATA[
var aFromExternal;
var aRelatedToCurrent;
var aIsUTF8;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
@ -1119,6 +1120,7 @@
aAllowThirdPartyFixup = params.allowThirdPartyFixup;
aFromExternal = params.fromExternal;
aRelatedToCurrent = params.relatedToCurrent;
aIsUTF8 = params.isUTF8;
}
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
@ -1131,7 +1133,8 @@
ownerTab: owner,
allowThirdPartyFixup: aAllowThirdPartyFixup,
fromExternal: aFromExternal,
relatedToCurrent: aRelatedToCurrent});
relatedToCurrent: aRelatedToCurrent,
isUTF8: aIsUTF8});
if (!bgLoad)
this.selectedTab = tab;
@ -1204,6 +1207,7 @@
var aFromExternal;
var aRelatedToCurrent;
var aSkipAnimation;
var aIsUTF8;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
@ -1216,6 +1220,7 @@
aFromExternal = params.fromExternal;
aRelatedToCurrent = params.relatedToCurrent;
aSkipAnimation = params.skipAnimation;
aIsUTF8 = params.isUTF8;
}
this._browsers = null; // invalidate cache
@ -1363,6 +1368,8 @@
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
if (aFromExternal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
if (aIsUTF8)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
try {
b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
} catch (ex) {

View File

@ -206,6 +206,7 @@ _BROWSER_FILES = \
browser_tabs_isActive.js \
browser_tabs_owner.js \
browser_urlbarCopying.js \
browser_urlbarEnter.js \
browser_urlbarTrimURLs.js \
browser_urlHighlight.js \
browser_visibleFindSelection.js \

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_VALUE = "example.com/\xF7?\xF7";
const START_VALUE = "example.com/%C3%B7?%C3%B7";
function test() {
waitForExplicitFinish();
runNextTest();
}
function locationBarEnter(aEvent, aClosure) {
executeSoon(function() {
gURLBar.focus();
EventUtils.synthesizeKey("VK_RETURN", aEvent);
addPageShowListener(aClosure);
});
}
function runNextTest() {
let test = gTests.shift();
if (!test) {
finish();
return;
}
info("Running test: " + test.desc);
let tab = gBrowser.selectedTab = gBrowser.addTab(START_VALUE);
addPageShowListener(function() {
locationBarEnter(test.event, function() {
test.check(tab);
// Clean up
while (gBrowser.tabs.length > 1)
gBrowser.removeTab(gBrowser.selectedTab)
runNextTest();
});
});
}
let gTests = [
{ desc: "Simple return keypress",
event: {},
check: checkCurrent
},
{ desc: "Alt+Return keypress",
event: { altKey: true },
check: checkNewTab,
},
]
function checkCurrent(aTab) {
is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
is(gBrowser.selectedTab, aTab, "New URL was loaded in the current tab");
}
function checkNewTab(aTab) {
is(gURLBar.value, TEST_VALUE, "Urlbar should preserve the value on return keypress");
isnot(gBrowser.selectedTab, aTab, "New URL was loaded in a new tab");
}
function addPageShowListener(aFunc) {
gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
aFunc();
});
}

View File

@ -326,6 +326,10 @@
// keyword).
if (!mayInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
// If the value wasn't typed, we know that we decoded the value as
// UTF-8 (see losslessDecodeURI)
if (!this.valueIsTyped)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
gBrowser.loadURIWithFlags(url, flags, null, null, postData);
}
@ -361,6 +365,8 @@
let params = { allowThirdPartyFixup: true, postData: postData };
if (altEnter)
params.inBackground = false;
if (!this.valueIsTyped)
params.isUTF8 = true;
openUILinkIn(url, where, params);
}
} else {

View File

@ -199,6 +199,8 @@ function openLinkIn(url, where, params) {
var aRelatedToCurrent = params.relatedToCurrent;
var aInBackground = params.inBackground;
var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
// Currently, this parameter works only for where=="tab" or "current"
var aIsUTF8 = params.isUTF8;
if (where == "save") {
saveURL(url, null, null, true, null, aReferrerURI);
@ -272,6 +274,8 @@ function openLinkIn(url, where, params) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
if (aDisallowInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
if (aIsUTF8)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);
break;
case "tabshifted":
@ -285,7 +289,8 @@ function openLinkIn(url, where, params) {
postData: aPostData,
inBackground: loadInBackground,
allowThirdPartyFixup: aAllowThirdPartyFixup,
relatedToCurrent: aRelatedToCurrent});
relatedToCurrent: aRelatedToCurrent,
isUTF8: aIsUTF8});
break;
}

View File

@ -761,6 +761,7 @@ BrowserGlue.prototype = {
_showTelemetryNotification: function BG__showTelemetryNotification() {
const PREF_TELEMETRY_PROMPTED = "toolkit.telemetry.prompted";
const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
const PREF_TELEMETRY_REJECTED = "toolkit.telemetry.rejected";
const PREF_TELEMETRY_INFOURL = "toolkit.telemetry.infoURL";
const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner";
// This is used to reprompt users when privacy message changes
@ -803,7 +804,9 @@ BrowserGlue.prototype = {
label: browserBundle.GetStringFromName("telemetryNoButtonLabel"),
accessKey: browserBundle.GetStringFromName("telemetryNoButtonAccessKey"),
popup: null,
callback: function(aNotificationBar, aButton) {}
callback: function(aNotificationBar, aButton) {
Services.prefs.setBoolPref(PREF_TELEMETRY_REJECTED, true);
}
}
];
@ -811,6 +814,7 @@ BrowserGlue.prototype = {
Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV);
var notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons);
notification.setAttribute("hideclose", true);
notification.persistence = 6; // arbitrary number, just so bar sticks around for a bit
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

View File

@ -458,6 +458,9 @@ TreePanel.prototype = {
editorInput.value = aAttrVal;
editorInput.select();
// remove tree key navigation events
this.treeIFrame.removeEventListener("keypress", this.IUI, false);
// listen for editor specific events
this.bindEditorEvent(editor, "click", function(aEvent) {
aEvent.stopPropagation();
@ -515,8 +518,12 @@ TreePanel.prototype = {
{
if (aEvent.which == this.window.KeyEvent.DOM_VK_RETURN) {
this.saveEditor();
aEvent.preventDefault();
aEvent.stopPropagation();
} else if (aEvent.keyCode == this.window.KeyEvent.DOM_VK_ESCAPE) {
this.closeEditor();
aEvent.preventDefault();
aEvent.stopPropagation();
}
},
@ -546,6 +553,9 @@ TreePanel.prototype = {
this.editingContext = null;
this.editingEvents = {};
// re-add navigation listener
this.treeIFrame.addEventListener("keypress", this.IUI, false);
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
null);
@ -567,6 +577,7 @@ TreePanel.prototype = {
this.editingContext.attrObj.innerHTML = editorInput.value;
this.IUI.isDirty = true;
this.IUI.nodeChanged(this.registrationObject);
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,

View File

@ -50,6 +50,7 @@ var EXPORTED_SYMBOLS = ["InspectorUI"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/TreePanel.jsm");
Cu.import("resource:///modules/devtools/CssRuleView.jsm");
const INSPECTOR_INVISIBLE_ELEMENTS = {
"head": true,
@ -78,9 +79,15 @@ const INSPECTOR_NOTIFICATIONS = {
// Fires once the Inspector is closed.
CLOSED: "inspector-closed",
// Fires when the Inspector is reopened after tab-switch.
STATE_RESTORED: "inspector-state-restored",
// Fires when the Tree Panel is opened and initialized.
TREEPANELREADY: "inspector-treepanel-ready",
// Fires when the CSS Rule View is opened and initialized.
RULEVIEWREADY: "inspector-ruleview-ready",
// Event notifications for the attribute-value editor
EDITOR_OPENED: "inspector-editor-opened",
EDITOR_CLOSED: "inspector-editor-closed",
@ -740,6 +747,7 @@ InspectorUI.prototype = {
toolEvents: null,
inspecting: false,
treePanelEnabled: true,
ruleViewEnabled: true,
isDirty: false,
store: null,
@ -891,6 +899,11 @@ InspectorUI.prototype = {
this.treePanel = new TreePanel(this.chromeWin, this);
}
if (Services.prefs.getBoolPref("devtools.ruleview.enabled") &&
!this.toolRegistered("ruleview")) {
this.registerRuleView();
}
if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") &&
!this.toolRegistered("styleinspector")) {
this.stylePanel = new StyleInspector(this.chromeWin, this);
@ -910,6 +923,31 @@ InspectorUI.prototype = {
this.initializeHighlighter();
},
/**
* Register the Rule View in the Sidebar.
*/
registerRuleView: function IUI_registerRuleView()
{
let isOpen = this.isRuleViewOpen.bind(this);
this.ruleViewObject = {
id: "ruleview",
label: this.strings.GetStringFromName("ruleView.label"),
tooltiptext: this.strings.GetStringFromName("ruleView.tooltiptext"),
accesskey: this.strings.GetStringFromName("ruleView.accesskey"),
context: this,
get isOpen() isOpen(),
show: this.openRuleView,
hide: this.closeRuleView,
onSelect: this.selectInRuleView,
panel: null,
unregister: this.destroyRuleView,
sidebar: true,
};
this.registerTool(this.ruleViewObject);
},
/**
* Register and initialize any included tools.
*/
@ -1120,6 +1158,19 @@ InspectorUI.prototype = {
this.toolsSelect(aScroll);
},
/**
* Called when the highlighted node is changed by a tool.
*
* @param object aUpdater
* The tool that triggered the update (if any), that tool's
* onChanged will not be called.
*/
nodeChanged: function IUI_nodeChanged(aUpdater)
{
this.highlighter.highlight();
this.toolsOnChanged(aUpdater);
},
/////////////////////////////////////////////////////////////////////////
//// Event Handling
@ -1271,6 +1322,94 @@ InspectorUI.prototype = {
}
},
/////////////////////////////////////////////////////////////////////////
//// CssRuleView methods
/**
* Is the cssRuleView open?
*/
isRuleViewOpen: function IUI_isRuleViewOpen()
{
return this.isSidebarOpen && this.ruleButton.hasAttribute("checked") &&
(this.sidebarDeck.selectedPanel == this.getToolIframe(this.ruleViewObject));
},
/**
* Convenience getter to retrieve the Rule Button.
*/
get ruleButton()
{
return this.chromeDoc.getElementById(
this.getToolbarButtonId(this.ruleViewObject.id));
},
/**
* Open the CssRuleView.
*/
openRuleView: function IUI_openRuleView()
{
let iframe = this.getToolIframe(this.ruleViewObject);
let boundLoadListener = function() {
iframe.removeEventListener("load", boundLoadListener, true);
let doc = iframe.contentDocument;
this.ruleView = new CssRuleView(doc);
this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
this.ruleView.element.addEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
doc.documentElement.appendChild(this.ruleView.element);
this.ruleView.highlight(this.selection);
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, null);
}.bind(this);
iframe.addEventListener("load", boundLoadListener, true);
iframe.setAttribute("src", "chrome://browser/content/devtools/cssruleview.xul");
},
/**
* Stub to Close the CSS Rule View. Does nothing currently because the
* Rule View lives in the sidebar.
*/
closeRuleView: function IUI_closeRuleView()
{
// do nothing for now
},
/**
* Update the selected node in the Css Rule View.
* @param {nsIDOMnode} the selected node.
*/
selectInRuleView: function IUI_selectInRuleView(aNode)
{
if (this.ruleView)
this.ruleView.highlight(aNode);
},
ruleViewChanged: function IUI_ruleViewChanged()
{
this.isDirty = true;
this.nodeChanged(this.ruleViewObject);
},
/**
* Destroy the rule view.
*/
destroyRuleView: function IUI_destroyRuleView()
{
let iframe = this.getToolIframe(this.ruleViewObject);
iframe.parentNode.removeChild(iframe);
if (this.ruleView) {
this.ruleView.element.removeEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
delete boundRuleViewChanged;
this.ruleView.clear();
delete this.ruleView;
}
},
/////////////////////////////////////////////////////////////////////////
//// Utility Methods
@ -1552,10 +1691,6 @@ InspectorUI.prototype = {
// wire up button to show the iframe
this.bindToolEvent(btn, "click", function showIframe() {
let visible = this.sidebarDeck.selectedPanel == iframe;
if (!visible) {
sidebarDeck.selectedPanel = iframe;
}
this.toolShow(aRegObj);
}.bind(this));
},
@ -1576,10 +1711,18 @@ InspectorUI.prototype = {
*/
toolShow: function IUI_toolShow(aTool)
{
aTool.show.call(aTool.context, this.selection);
let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
btn.setAttribute("checked", "true");
if (aTool.sidebar) {
this.sidebarDeck.selectedPanel = this.getToolIframe(aTool);
this.sidebarTools.forEach(function(other) {
if (other != aTool)
this.chromeDoc.getElementById(
this.getToolbarButtonId(other.id)).removeAttribute("checked");
}.bind(this));
}
aTool.show.call(aTool.context, this.selection);
},
/**
@ -1689,16 +1832,24 @@ InspectorUI.prototype = {
restoreToolState: function IUI_restoreToolState(aWinID)
{
let openTools = this.store.getValue(aWinID, "openTools");
let activeSidebarTool;
if (openTools) {
this.toolsDo(function IUI_toolsOnShow(aTool) {
if (aTool.id in openTools) {
if (aTool.sidebar && !this.isSidebarOpen) {
this.showSidebar();
activeSidebarTool = aTool;
}
this.toolShow(aTool);
}
}.bind(this));
this.sidebarTools.forEach(function(tool) {
if (tool != activeSidebarTool)
this.chromeDoc.getElementById(
this.getToolbarButtonId(tool.id)).removeAttribute("checked");
}.bind(this));
}
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.STATE_RESTORED, null);
},
/**
@ -1723,13 +1874,29 @@ InspectorUI.prototype = {
*/
toolsDim: function IUI_toolsDim(aState)
{
this.toolsDo(function IUI_toolsOnSelect(aTool) {
this.toolsDo(function IUI_toolsDim(aTool) {
if (aTool.isOpen && "dim" in aTool) {
aTool.dim.call(aTool.context, aState);
}
});
},
/**
* Notify registered tools of changes to the highlighted element.
*
* @param object aUpdater
* The tool that triggered the update (if any), that tool's
* onChanged will not be called.
*/
toolsOnChanged: function IUI_toolsChanged(aUpdater)
{
this.toolsDo(function IUI_toolsOnChanged(aTool) {
if (aTool.isOpen && ("onChanged" in aTool) && aTool != aUpdater) {
aTool.onChanged.call(aTool.context);
}
});
},
/**
* Loop through all registered tools and pass each into the provided function
* @param aFunction The function to which each tool is to be passed
@ -1937,8 +2104,13 @@ InspectorProgressListener.prototype = {
return;
}
// Skip non-start states.
if (!(aFlag & Ci.nsIWebProgressListener.STATE_START)) {
let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
let isNetwork = aFlag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
let isRequest = aFlag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
// Skip non-interesting states.
if (!isStart || !isDocument || !isRequest || !isNetwork) {
return;
}

View File

@ -65,6 +65,8 @@ _BROWSER_FILES = \
browser_inspector_keybindings.js \
browser_inspector_breadcrumbs.html \
browser_inspector_breadcrumbs.js \
browser_inspector_bug_699308_iframe_navigation.js \
browser_inspector_changes.js \
$(NULL)
# Disabled due to constant failures

View File

@ -0,0 +1,77 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let iframe;
let iframeLoads = 0;
let checksAfterLoads = false;
function startTest() {
ok(window.InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
InspectorUI.toggleInspectorUI();
}
function runInspectorTests() {
Services.obs.removeObserver(runInspectorTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
iframe = content.document.querySelector("iframe");
ok(iframe, "found the iframe element");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isInspectorOpen, "Inspector is open");
Services.obs.addObserver(finishTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
iframe.addEventListener("load", onIframeLoad, false);
executeSoon(function() {
iframe.contentWindow.location = "javascript:location.reload()";
});
}
function onIframeLoad() {
if (++iframeLoads != 2) {
executeSoon(function() {
iframe.contentWindow.location = "javascript:location.reload()";
});
return;
}
iframe.removeEventListener("load", onIframeLoad, false);
ok(InspectorUI.inspecting, "Inspector is highlighting after iframe nav");
ok(InspectorUI.isInspectorOpen, "Inspector Panel is open after iframe nav");
checksAfterLoads = true;
InspectorUI.closeInspectorUI();
}
function finishTest() {
Services.obs.removeObserver(finishTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
is(iframeLoads, 2, "iframe loads");
ok(checksAfterLoads, "the Inspector tests got the chance to run after iframe reloads");
ok(!InspectorUI.isInspectorOpen, "Inspector Panel is not open");
iframe = null;
gBrowser.removeCurrentTab();
executeSoon(finish);
}
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
waitForFocus(startTest, content);
}, true);
content.location = "data:text/html,<p>bug 699308 - test iframe navigation" +
"<iframe src='data:text/html,hello world'></iframe>";
}

View File

@ -0,0 +1,158 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** 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 Inspect Tests.
*
* 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):
* Dave Camp <dcamp@mozilla.com>
* Rob Campbell <rcampbell@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 ***** */
let doc;
let testDiv;
function createDocument()
{
doc.body.innerHTML = '<div id="testdiv">Test div!</div>';
doc.title = "Inspector Change Test";
startInspectorTests();
}
function getInspectorProp(aName)
{
for each (let view in InspectorUI.stylePanel.cssHtmlTree.propertyViews) {
if (view.name == aName) {
return view;
}
}
return null;
}
function startInspectorTests()
{
ok(InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runInspectorTests()
{
Services.obs.removeObserver(runInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
testDiv = doc.getElementById("testdiv");
testDiv.style.fontSize = "10px";
InspectorUI.inspectNode(testDiv);
InspectorUI.stopInspecting();
// Start up the style inspector panel...
Services.obs.addObserver(stylePanelTests, "StyleInspector-populated", false);
executeSoon(function() {
InspectorUI.showSidebar();
document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
});
}
function stylePanelTests()
{
Services.obs.removeObserver(stylePanelTests, "StyleInspector-populated");
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
let propView = getInspectorProp("font-size");
is(propView.value, "10px", "Style inspector should be showing the correct font size.");
Services.obs.addObserver(stylePanelAfterChange, "StyleInspector-populated", false);
testDiv.style.fontSize = "15px";
InspectorUI.nodeChanged();
}
function stylePanelAfterChange()
{
Services.obs.removeObserver(stylePanelAfterChange, "StyleInspector-populated");
let propView = getInspectorProp("font-size");
is(propView.value, "15px", "Style inspector should be showing the new font size.");
stylePanelNotActive();
}
function stylePanelNotActive()
{
// Tests changes made while the style panel is not active.
InspectorUI.ruleButton.click();
executeSoon(function() {
testDiv.style.fontSize = "20px";
Services.obs.addObserver(stylePanelAfterSwitch, "StyleInspector-populated", false);
document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
});
}
function stylePanelAfterSwitch()
{
Services.obs.removeObserver(stylePanelAfterSwitch, "StyleInspector-populated");
let propView = getInspectorProp("font-size");
is(propView.value, "20px", "Style inspector should be showing the newest font size.");
Services.obs.addObserver(finishTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
executeSoon(function() {
InspectorUI.closeInspectorUI(true);
});
}
function finishTest()
{
Services.obs.removeObserver(finishTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic tests for inspector";
}

View File

@ -34,13 +34,14 @@ function setupHTMLPanel()
{
Services.obs.removeObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.treePanel.open();
InspectorUI.toolShow(InspectorUI.treePanel.registrationObject);
}
function runEditorTests()
{
Services.obs.removeObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
InspectorUI.stopInspecting();
InspectorUI.inspectNode(doc.body, true);
// setup generator for async test steps
editorTestSteps = doEditorTestSteps();
@ -54,6 +55,14 @@ function runEditorTests()
doNextStep();
}
function highlighterTrap()
{
// bug 696107
Services.obs.removeObserver(highlighterTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
ok(false, "Highlighter moved. Shouldn't be here!");
finishUp();
}
function doEditorTestSteps()
{
let treePanel = InspectorUI.treePanel;
@ -78,6 +87,9 @@ function doEditorTestSteps()
// Step 2: validate editing session, enter new attribute value into editor, and save input
ok(InspectorUI.treePanel.editingContext, "Step 2: editor session started");
let selection = InspectorUI.selection;
ok(selection, "Selection is: " + selection);
let editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible");
@ -103,8 +115,13 @@ function doEditorTestSteps()
editorInput.value = "Hello World";
editorInput.focus();
// hit <enter> to save the inputted value
Services.obs.addObserver(highlighterTrap,
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
// hit <enter> to save the textbox value
executeSoon(function() {
// Extra key to test that keyboard handlers have been removed. bug 696107.
EventUtils.synthesizeKey("VK_LEFT", {}, attrValNode_id.ownerDocument.defaultView);
EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView);
});
@ -112,6 +129,8 @@ function doEditorTestSteps()
yield;
yield; // End of Step 2
// remove this from previous step
Services.obs.removeObserver(highlighterTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
// Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
ok(!treePanel.editingContext, "Step 3: editor session ended");
@ -210,16 +229,14 @@ function doEditorTestSteps()
is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
// End of Step 8
// end of all steps, so clean up
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
executeSoon(finishUp);
}
function finishUp() {
// end of all steps, so clean up
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
doc = div = null;
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();

View File

@ -95,22 +95,34 @@ function treePanelTests()
executeSoon(function() {
InspectorUI.showSidebar();
document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
});
}
function stylePanelTests()
{
Services.obs.removeObserver(stylePanelTests, "StyleInspector-opened");
Services.obs.addObserver(runContextMenuTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
InspectorUI.ruleButton.click();
executeSoon(function() {
ruleViewTests();
});
}
function ruleViewTests()
{
Services.obs.addObserver(runContextMenuTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(InspectorUI.isRuleViewOpen(), "Rule View is open");
ok(InspectorUI.ruleView, "InspectorUI has a cssRuleView");
executeSoon(function() {
InspectorUI.closeInspectorUI();
});
}
function runContextMenuTest()
@ -193,6 +205,10 @@ function finishInspectorTests()
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
ok(!InspectorUI.inspecting, "Inspector is not inspecting");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is closed");
ok(!InspectorUI.stylePanel, "Inspector Style Panel is gone");
ok(!InspectorUI.ruleView, "Inspector Rule View is gone");
is(InspectorUI.sidebarToolbar.children.length, 0, "No items in the Sidebar toolbar");
is(InspectorUI.sidebarDeck.children.length, 0, "No items in the Sidebar deck");
ok(!InspectorUI.toolbar, "toolbar is hidden");
gBrowser.removeCurrentTab();

View File

@ -62,6 +62,7 @@ function inspectorUIOpen1()
// Make sure the inspector is open.
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
ok(!InspectorUI.store.isEmpty(), "InspectorUI.store is not empty");
is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
@ -88,6 +89,7 @@ function inspectorTabOpen2()
// Make sure the inspector is closed.
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
// Activate the inspector again.
@ -147,6 +149,26 @@ function inspectorOpenTreePanelTab1()
is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
is(InspectorUI.selection, div, "selection matches the div element");
Services.obs.addObserver(inspectorSidebarStyleView1, "StyleInspector-opened", false);
executeSoon(function() {
InspectorUI.showSidebar();
InspectorUI.toolShow(InspectorUI.stylePanel.registrationObject);
});
}
function inspectorSidebarStyleView1()
{
Services.obs.removeObserver(inspectorSidebarStyleView1, "StyleInspector-opened");
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
ok(InspectorUI.stylePanel, "Inspector Has a Style Panel Instance");
InspectorUI.sidebarTools.forEach(function(aTool) {
let btn = document.getElementById(InspectorUI.getToolbarButtonId(aTool.id));
is(btn.hasAttribute("checked"),
(aTool == InspectorUI.stylePanel.registrationObject),
"Button " + btn.id + " has correct checked attribute");
});
// Switch back to tab 2.
Services.obs.addObserver(inspectorFocusTab2,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
@ -161,6 +183,7 @@ function inspectorFocusTab2()
// Make sure the inspector is still open.
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
isnot(InspectorUI.selection, div, "selection does not match the div element");
@ -180,6 +203,15 @@ function inspectorSecondFocusTab1()
is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
is(InspectorUI.selection, div, "selection matches the div element");
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
ok(InspectorUI.stylePanel, "Inspector Has a Style Panel Instance");
InspectorUI.sidebarTools.forEach(function(aTool) {
let btn = document.getElementById(InspectorUI.getToolbarButtonId(aTool.id));
is(btn.hasAttribute("checked"),
(aTool == InspectorUI.stylePanel.registrationObject),
"Button " + btn.id + " has correct checked attribute");
});
// Switch back to tab 2.
Services.obs.addObserver(inspectorSecondFocusTab2,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
@ -194,6 +226,8 @@ function inspectorSecondFocusTab2()
// Make sure the inspector is still open.
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
isnot(InspectorUI.selection, div, "selection does not match the div element");

View File

@ -3,8 +3,8 @@ browser.jar:
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
* content/browser/scratchpad.js (scratchpad/scratchpad.js)
content/browser/csshtmltree.xhtml (styleinspector/csshtmltree.xhtml)
content/browser/devtools/cssruleview.xhtml (styleinspector/cssruleview.xhtml)
content/browser/devtools/csshtmltree.xul (styleinspector/csshtmltree.xul)
content/browser/devtools/cssruleview.xul (styleinspector/cssruleview.xul)
content/browser/devtools/styleinspector.css (styleinspector/styleinspector.css)
content/browser/orion.js (sourceeditor/orion/orion.js)
content/browser/orion.css (sourceeditor/orion/orion.css)

View File

@ -798,6 +798,8 @@ var Scratchpad = {
*/
onEditPopupShowing: function SP_onEditPopupShowing()
{
goUpdateGlobalEditMenuItems();
let undo = document.getElementById("sp-cmd-undo");
undo.setAttribute("disabled", !this.editor.canUndo());

View File

@ -290,7 +290,8 @@
</menubar>
<popupset id="scratchpad-popups">
<menupopup id="scratchpad-text-popup">
<menupopup id="scratchpad-text-popup"
onpopupshowing="goUpdateGlobalEditMenuItems()">
<menuitem id="menu_cut"/>
<menuitem id="menu_copy"/>
<menuitem id="menu_paste"/>

View File

@ -56,6 +56,7 @@ _BROWSER_TEST_FILES = \
browser_scratchpad_open.js \
browser_scratchpad_restore.js \
browser_scratchpad_bug_679467_falsy.js \
browser_scratchpad_bug_699130_edit_ui_updates.js \
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,193 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource:///modules/source-editor.jsm");
// Reference to the Scratchpad chrome window object.
let gScratchpadWindow;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
gScratchpadWindow = Scratchpad.openScratchpad();
gScratchpadWindow.addEventListener("load", function onScratchpadLoad() {
gScratchpadWindow.removeEventListener("load", onScratchpadLoad, false);
waitForFocus(runTests, gScratchpadWindow);
}, false);
}, true);
content.location = "data:text/html,test Edit menu updates Scratchpad - bug 699130";
}
function runTests()
{
let sp = gScratchpadWindow.Scratchpad;
let doc = gScratchpadWindow.document;
let winUtils = gScratchpadWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
let OS = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
info("will test the Edit menu");
let pass = 0;
sp.setText("bug 699130: hello world! (edit menu)");
let editMenu = doc.getElementById("sp-edit-menu");
ok(editMenu, "the Edit menu");
let menubar = editMenu.parentNode;
ok(menubar, "menubar found");
let editMenuIndex = -1;
for (let i = 0; i < menubar.children.length; i++) {
if (menubar.children[i] === editMenu) {
editMenuIndex = i;
break;
}
}
isnot(editMenuIndex, -1, "Edit menu index is correct");
let menuPopup = editMenu.menupopup;
ok(menuPopup, "the Edit menupopup");
let cutItem = doc.getElementById("sp-menu-cut");
ok(cutItem, "the Cut menuitem");
let pasteItem = doc.getElementById("sp-menu-paste");
ok(pasteItem, "the Paste menuitem");
let anchor = doc.documentElement;
let isContextMenu = false;
let openMenu = function(aX, aY, aCallback) {
if (!editMenu || OS != "Darwin") {
menuPopup.addEventListener("popupshown", function onPopupShown() {
menuPopup.removeEventListener("popupshown", onPopupShown, false);
executeSoon(aCallback);
}, false);
}
executeSoon(function() {
if (editMenu) {
if (OS == "Darwin") {
winUtils.forceUpdateNativeMenuAt(editMenuIndex);
executeSoon(aCallback);
} else {
editMenu.open = true;
}
} else {
menuPopup.openPopup(anchor, "overlap", aX, aY, isContextMenu, false);
}
});
};
let closeMenu = function(aCallback) {
if (!editMenu || OS != "Darwin") {
menuPopup.addEventListener("popuphidden", function onPopupHidden() {
menuPopup.removeEventListener("popuphidden", onPopupHidden, false);
executeSoon(aCallback);
}, false);
}
executeSoon(function() {
if (editMenu) {
if (OS == "Darwin") {
winUtils.forceUpdateNativeMenuAt(editMenuIndex);
executeSoon(aCallback);
} else {
editMenu.open = false;
}
} else {
menuPopup.hidePopup();
}
});
};
let firstShow = function() {
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled");
closeMenu(firstHide);
};
let firstHide = function() {
sp.selectRange(0, 10);
openMenu(11, 11, showAfterSelect);
};
let showAfterSelect = function() {
ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after select");
closeMenu(hideAfterSelect);
};
let hideAfterSelect = function() {
sp.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onCut);
EventUtils.synthesizeKey("x", {accelKey: true}, gScratchpadWindow);
};
let onCut = function() {
sp.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onCut);
openMenu(12, 12, showAfterCut);
};
let showAfterCut = function() {
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after cut");
ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after cut");
closeMenu(hideAfterCut);
};
let hideAfterCut = function() {
sp.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
EventUtils.synthesizeKey("v", {accelKey: true}, gScratchpadWindow);
};
let onPaste = function() {
sp.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onPaste);
openMenu(13, 13, showAfterPaste);
};
let showAfterPaste = function() {
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after paste");
ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after paste");
closeMenu(hideAfterPaste);
};
let hideAfterPaste = function() {
if (pass == 0) {
pass++;
testContextMenu();
} else {
finishTest();
}
};
let testContextMenu = function() {
info("will test the context menu");
editMenu = null;
isContextMenu = true;
menuPopup = doc.getElementById("scratchpad-text-popup");
ok(menuPopup, "the context menupopup");
cutItem = doc.getElementById("menu_cut");
ok(cutItem, "the Cut menuitem");
pasteItem = doc.getElementById("menu_paste");
ok(pasteItem, "the Paste menuitem");
sp.setText("bug 699130: hello world! (context menu)");
openMenu(10, 10, firstShow);
};
let finishTest = function() {
gScratchpadWindow.close();
gScratchpadWindow = null;
gBrowser.removeCurrentTab();
finish();
};
openMenu(10, 10, firstShow);
}

View File

@ -22,6 +22,9 @@ Orion version: git clone from 2011-10-26
+ patch for Eclipse Bug 362428 - _getXToOffset() throws:
https://github.com/mihaisucan/orion.client/tree/bug-362428
see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362428
+ patch for Eclipse Bug 362835 - Pasted HTML shows twice:
https://github.com/mihaisucan/orion.client/tree/bug-362835
see https://bugs.eclipse.org/bugs/show_bug.cgi?id=362835
# License

View File

@ -1952,7 +1952,7 @@ if (typeof window !== "undefined" && typeof window.define !== "undefined") {
* Contributors:
* Felipe Heidrich (IBM Corporation) - initial API and implementation
* Silenio Quarti (IBM Corporation) - initial API and implementation
* Mihai Sucan (Mozilla Foundation) - fix for Bug#334583 Bug#348471 Bug#349485 Bug#350595 Bug#360726 Bug#361180 Bug#358623 Bug#362286 Bug#362107 Bug#362428
* Mihai Sucan (Mozilla Foundation) - fix for Bug#334583 Bug#348471 Bug#349485 Bug#350595 Bug#360726 Bug#361180 Bug#358623 Bug#362286 Bug#362107 Bug#362428 Bug#362835
******************************************************************************/
/*global window document navigator setTimeout clearTimeout XMLHttpRequest define */
@ -5673,7 +5673,10 @@ orion.textview.TextView = (function() {
this._ignorePaste = true;
try {
result = document.execCommand("paste", false, null);
} catch (ex) {}
} catch (ex) {
// Firefox can throw even when execCommand() works, see bug 362835
result = clipboardDiv.childNodes.length > 1 || clipboardDiv.firstChild && clipboardDiv.firstChild.childNodes.length > 0;
}
this._ignorePaste = false;
if (!result) {
/*

View File

@ -73,7 +73,10 @@ function editorLoaded()
let text = editor.getText();
ok(text, "editor has content after paste");
isnot(text.indexOf("foobarBug684862"), -1, "editor content is correct");
let pos = text.indexOf("foobarBug684862");
isnot(pos, -1, "editor content is correct");
// Test for bug 699541 - Pasted HTML shows twice in Orion.
is(text.lastIndexOf("foobarBug684862"), pos, "editor content is correct (no duplicate)");
executeSoon(function() {
editor.setCaretOffset(4);
@ -82,7 +85,7 @@ function editorLoaded()
text = editor.getText();
isnot(text.indexOf("foobarBug684862"), -1,
is(text.indexOf("foobarBug684862"), pos + 1,
"editor content is correct after navigation");
is(editor.getCaretOffset(), 6, "caret location");

View File

@ -69,7 +69,7 @@ function CssHtmlTree(aStyleInspector)
this.getRTLAttr = this.win.getComputedStyle(this.win.gBrowser).direction;
this.propertyViews = [];
// The document in which we display the results (csshtmltree.xhtml).
// The document in which we display the results (csshtmltree.xul).
this.styleDocument = this.styleWin.contentWindow.document;
// Nodes used in templating
@ -81,6 +81,9 @@ function CssHtmlTree(aStyleInspector)
this.templateProperty = this.styleDocument.getElementById("templateProperty");
this.panel = aStyleInspector.panel;
// No results text.
this.noResults = this.styleDocument.getElementById("noResults");
// The element that we're inspecting, and the document that it comes from.
this.viewedElement = null;
this.createStyleViews();
@ -133,20 +136,30 @@ XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
CssHtmlTree.prototype = {
// Cache the list of properties that have matched and unmatched properties.
_matchedProperties: null,
_unmatchedProperties: null,
htmlComplete: false,
// Used for cancelling timeouts in the style filter.
filterChangedTimeout: null,
_filterChangedTimeout: null,
// The search filter
searchField: null,
// Reference to the "Only user Styles" checkbox.
onlyUserStylesCheckbox: null,
// Holds the ID of the panelRefresh timeout.
_panelRefreshTimeout: null,
// Toggle for zebra striping
_darkStripe: true,
// Number of visible properties
numVisibleProperties: 0,
get showOnlyUserStyles()
{
return this.onlyUserStylesCheckbox.checked;
@ -159,17 +172,19 @@ CssHtmlTree.prototype = {
*/
highlight: function CssHtmlTree_highlight(aElement)
{
if (this.viewedElement == aElement) {
return;
}
this.viewedElement = aElement;
this._unmatchedProperties = null;
this._matchedProperties = null;
CssHtmlTree.processTemplate(this.templatePath, this.path, this);
if (this.htmlComplete) {
this.refreshPanel();
} else {
if (this._panelRefreshTimeout) {
this.win.clearTimeout(this._panelRefreshTimeout);
}
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// We use a setTimeout loop to display the properties in batches of 15 at a
@ -185,21 +200,27 @@ CssHtmlTree.prototype = {
let propView = new PropertyView(this, name);
CssHtmlTree.processTemplate(this.templateProperty,
this.propertyContainer, propView, true);
propView.refreshMatchedSelectors();
propView.refreshUnmatchedSelectors();
if (propView.visible) {
this.numVisibleProperties++;
}
propView.refreshAllSelectors();
this.propertyViews.push(propView);
}
if (i < max) {
// There are still some properties to display. We loop here to display
// the next batch of 15.
this.win.setTimeout(displayProperties.bind(this), 50);
this._panelRefreshTimeout =
this.win.setTimeout(displayProperties.bind(this), 15);
} else {
this.htmlComplete = true;
this._panelRefreshTimeout = null;
this.noResults.hidden = this.numVisibleProperties > 0;
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
}
}
}
this.win.setTimeout(displayProperties.bind(this), 50);
this._panelRefreshTimeout =
this.win.setTimeout(displayProperties.bind(this), 15);
}
},
@ -208,7 +229,17 @@ CssHtmlTree.prototype = {
*/
refreshPanel: function CssHtmlTree_refreshPanel()
{
this.win.clearTimeout(this._panelRefreshTimeout);
if (this._panelRefreshTimeout) {
this.win.clearTimeout(this._panelRefreshTimeout);
}
this.noResults.hidden = true;
// Reset visible property count
this.numVisibleProperties = 0;
// Reset zebra striping.
this._darkStripe = true;
// We use a setTimeout loop to display the properties in batches of 15 at a
// time. This results in a perceptibly more responsive UI.
@ -223,12 +254,14 @@ CssHtmlTree.prototype = {
if (i < max) {
// There are still some property views to refresh. We loop here to
// display the next batch of 15.
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
} else {
this._panelRefreshTimeout = null;
this.noResults.hidden = this.numVisibleProperties > 0;
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
}
}
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 0);
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
},
/**
@ -254,13 +287,13 @@ CssHtmlTree.prototype = {
{
let win = this.styleWin.contentWindow;
if (this.filterChangedTimeout) {
win.clearTimeout(this.filterChangedTimeout);
this.filterChangeTimeout = null;
if (this._filterChangedTimeout) {
win.clearTimeout(this._filterChangedTimeout);
}
this.filterChangedTimeout = win.setTimeout(function() {
this._filterChangedTimeout = win.setTimeout(function() {
this.refreshPanel();
this._filterChangeTimeout = null;
}.bind(this), FILTER_CHANGED_TIMEOUT);
},
@ -275,6 +308,7 @@ CssHtmlTree.prototype = {
*/
onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
{
this._matchedProperties = null;
this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
CssLogic.FILTER.ALL :
CssLogic.FILTER.UA;
@ -305,8 +339,8 @@ CssHtmlTree.prototype = {
CssHtmlTree.propertyNames = [];
// Here we build and cache a list of css properties supported by the browser
// We could use any element but let's use the main document's body
let styles = this.styleWin.contentWindow.getComputedStyle(this.styleDocument.body);
// We could use any element but let's use the main document's root element
let styles = this.styleWin.contentWindow.getComputedStyle(this.styleDocument.documentElement);
let mozProps = [];
for (let i = 0, numStyles = styles.length; i < numStyles; i++) {
let prop = styles.item(i);
@ -322,6 +356,56 @@ CssHtmlTree.prototype = {
mozProps.sort());
},
/**
* Get a list of properties that have matched selectors.
*
* @return {object} the object maps property names (keys) to booleans (values)
* that tell if the given property has matched selectors or not.
*/
get matchedProperties()
{
if (!this._matchedProperties) {
this._matchedProperties =
this.cssLogic.hasMatchedSelectors(CssHtmlTree.propertyNames);
}
return this._matchedProperties;
},
/**
* Check if a property has unmatched selectors. Result is cached.
*
* @param {string} aProperty the name of the property you want to check.
* @return {boolean} true if the property has unmatched selectors, false
* otherwise.
*/
hasUnmatchedSelectors: function CssHtmlTree_hasUnmatchedSelectors(aProperty)
{
// Initially check all of the properties that return false for
// hasMatchedSelectors(). This speeds-up the UI.
if (!this._unmatchedProperties) {
let properties = [];
CssHtmlTree.propertyNames.forEach(function(aName) {
if (!this.matchedProperties[aName]) {
properties.push(aName);
}
}, this);
if (properties.indexOf(aProperty) == -1) {
properties.push(aProperty);
}
this._unmatchedProperties = this.cssLogic.hasUnmatchedSelectors(properties);
}
// Lazy-get the result for properties we do not have cached.
if (!(aProperty in this._unmatchedProperties)) {
let result = this.cssLogic.hasUnmatchedSelectors([aProperty]);
this._unmatchedProperties[aProperty] = result[aProperty];
}
return this._unmatchedProperties[aProperty];
},
/**
* Destructor for CssHtmlTree.
*/
@ -329,16 +413,20 @@ CssHtmlTree.prototype = {
{
delete this.viewedElement;
// Remove event listeners
this.onlyUserStylesCheckbox.removeEventListener("command",
this.onlyUserStylesChanged);
this.searchField.removeEventListener("command", this.filterChanged);
// Nodes used in templating
delete this.root;
delete this.path;
delete this.templateRoot;
delete this.templatePath;
delete this.propertyContainer;
delete this.templateProperty;
delete this.panel;
// The document in which we display the results (csshtmltree.xhtml).
// The document in which we display the results (csshtmltree.xul).
delete this.styleDocument;
// The element that we're inspecting, and the document that it comes from.
@ -368,13 +456,15 @@ function PropertyView(aTree, aName)
this.link = "https://developer.mozilla.org/en/CSS/" + aName;
this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
this.templateUnmatchedSelectors = aTree.styleDocument.getElementById("templateUnmatchedSelectors");
}
PropertyView.prototype = {
// The parent element which contains the open attribute
element: null,
// Property header node
propertyHeader: null,
// Destination for property values
valueNode: null,
@ -384,29 +474,23 @@ PropertyView.prototype = {
// Are unmatched rules expanded?
unmatchedExpanded: false,
// Unmatched selector table
unmatchedSelectorTable: null,
// Matched selector container
matchedSelectorsContainer: null,
// Unmatched selector container
unmatchedSelectorsContainer: null,
// Matched selector expando
matchedExpander: null,
// Unmatched selector expando
unmatchedExpander: null,
// Container for X matched selectors
matchedSelectorsTitleNode: null,
// Unmatched selector container
unmatchedSelectorsContainer: null,
// Container for X unmatched selectors
unmatchedSelectorsTitleNode: null,
// Matched selectors table
matchedSelectorTable: null,
// Unmatched selectors table
unmatchedSelectorTable: null,
// Unmatched title block
unmatchedTitleBlock: null,
// Cache for matched selector views
_matchedSelectorViews: null,
@ -441,7 +525,7 @@ PropertyView.prototype = {
*/
get hasMatchedSelectors()
{
return this.propertyInfo.hasMatchedSelectors();
return this.name in this.tree.matchedProperties;
},
/**
@ -449,7 +533,7 @@ PropertyView.prototype = {
*/
get hasUnmatchedSelectors()
{
return this.propertyInfo.hasUnmatchedSelectors();
return this.name in this.tree.hasUnmatchedSelectors;
},
/**
@ -472,10 +556,18 @@ PropertyView.prototype = {
/**
* Returns the className that should be assigned to the propertyView.
*
* @return string
*/
get className()
{
return this.visible ? "property-view" : "property-view-hidden";
if (this.visible) {
this.tree._darkStripe = !this.tree._darkStripe;
let darkValue = this.tree._darkStripe ?
"property-view darkrow" : "property-view";
return darkValue;
}
return "property-view-hidden";
},
/**
@ -494,18 +586,14 @@ PropertyView.prototype = {
if (!this.tree.viewedElement || !this.visible) {
this.valueNode.innerHTML = "";
this.matchedSelectorsContainer.hidden = true;
this.unmatchedSelectorsContainer.hidden = true;
this.matchedSelectorTable.innerHTML = "";
this.unmatchedSelectorTable.innerHTML = "";
this.matchedSelectorsContainer.innerHTML = "";
this.matchedExpander.removeAttribute("open");
this.unmatchedExpander.removeAttribute("open");
return;
}
this.tree.numVisibleProperties++;
this.valueNode.innerHTML = this.propertyInfo.value;
this.refreshMatchedSelectors();
this.refreshUnmatchedSelectors();
this.refreshAllSelectors();
},
/**
@ -516,12 +604,18 @@ PropertyView.prototype = {
let hasMatchedSelectors = this.hasMatchedSelectors;
this.matchedSelectorsContainer.hidden = !hasMatchedSelectors;
if (hasMatchedSelectors) {
this.propertyHeader.classList.add("expandable");
} else {
this.propertyHeader.classList.remove("expandable");
}
if (this.matchedExpanded && hasMatchedSelectors) {
CssHtmlTree.processTemplate(this.templateMatchedSelectors,
this.matchedSelectorTable, this);
this.matchedSelectorsContainer, this);
this.matchedExpander.setAttribute("open", "");
} else {
this.matchedSelectorTable.innerHTML = "";
this.matchedSelectorsContainer.innerHTML = "";
this.matchedExpander.removeAttribute("open");
}
},
@ -531,17 +625,44 @@ PropertyView.prototype = {
*/
refreshUnmatchedSelectors: function PropertyView_refreshUnmatchedSelectors()
{
let hasUnmatchedSelectors = this.hasUnmatchedSelectors;
this.unmatchedSelectorsContainer.hidden = !hasUnmatchedSelectors;
let hasMatchedSelectors = this.hasMatchedSelectors;
if (this.unmatchedExpanded && hasUnmatchedSelectors) {
CssHtmlTree.processTemplate(this.templateUnmatchedSelectors,
this.unmatchedSelectorTable, this);
this.unmatchedExpander.setAttribute("open", "");
this.unmatchedSelectorTable.hidden = !this.unmatchedExpanded;
if (hasMatchedSelectors) {
this.unmatchedSelectorsContainer.hidden = !this.matchedExpanded ||
!this.hasUnmatchedSelectors;
this.unmatchedTitleBlock.hidden = false;
} else {
this.unmatchedSelectorTable.innerHTML = "";
this.unmatchedExpander.removeAttribute("open");
this.unmatchedSelectorsContainer.hidden = !this.unmatchedExpanded;
this.unmatchedTitleBlock.hidden = true;
}
if (this.unmatchedExpanded && this.hasUnmatchedSelectors) {
CssHtmlTree.processTemplate(this.templateUnmatchedSelectors,
this.unmatchedSelectorTable, this);
if (!hasMatchedSelectors) {
this.matchedExpander.setAttribute("open", "");
this.unmatchedSelectorTable.classList.add("only-unmatched");
} else {
this.unmatchedExpander.setAttribute("open", "");
this.unmatchedSelectorTable.classList.remove("only-unmatched");
}
} else {
if (!hasMatchedSelectors) {
this.matchedExpander.removeAttribute("open");
}
this.unmatchedExpander.removeAttribute("open");
this.unmatchedSelectorTable.innerHTML = "";
}
},
/**
* Refresh the panel matched and unmatched rules
*/
refreshAllSelectors: function PropertyView_refreshAllSelectors()
{
this.refreshMatchedSelectors();
},
/**
@ -580,12 +701,18 @@ PropertyView.prototype = {
/**
* The action when a user expands matched selectors.
*
* @param {Event} aEvent Used to determine the class name of the targets click
* event. If the class name is "helplink" then the event is allowed to bubble
* to the mdn link icon.
*/
matchedSelectorsClick: function PropertyView_matchedSelectorsClick(aEvent)
propertyHeaderClick: function PropertyView_propertyHeaderClick(aEvent)
{
this.matchedExpanded = !this.matchedExpanded;
this.refreshMatchedSelectors();
aEvent.preventDefault();
if (aEvent.target.className != "helplink") {
this.matchedExpanded = !this.matchedExpanded;
this.refreshAllSelectors();
aEvent.preventDefault();
}
},
/**
@ -597,6 +724,15 @@ PropertyView.prototype = {
this.refreshUnmatchedSelectors();
aEvent.preventDefault();
},
/**
* The action when a user clicks on the MDN help link for a property.
*/
mdnLinkClick: function PropertyView_mdnLinkClick(aEvent)
{
this.tree.win.openUILinkIn(this.link, "tab");
aEvent.preventDefault();
},
};
/**

View File

@ -151,6 +151,7 @@ CssLogic.prototype = {
// in processUnmatchedSelectors().
_matchId: 0,
_matchedRules: null,
_matchedSelectors: null,
_unmatchedSelectors: null,
@ -166,6 +167,7 @@ CssLogic.prototype = {
this._sheetIndex = 0;
this._sheets = {};
this._sheetsCached = false;
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
},
@ -200,6 +202,7 @@ CssLogic.prototype = {
this._propertyInfos = {};
}
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
let win = this.viewedDocument.defaultView;
@ -242,6 +245,7 @@ CssLogic.prototype = {
aValue == CssLogic.FILTER.UA);
if (needFullUpdate) {
this._matchedRules = null;
this._matchedSelectors = null;
this._unmatchedSelectors = null;
this._propertyInfos = {};
@ -289,7 +293,7 @@ CssLogic.prototype = {
// styleSheets isn't an array, but forEach can work on it anyway
Array.prototype.forEach.call(this.viewedDocument.styleSheets,
this._cacheSheet, this);
this._sheetsCached = true;
},
@ -309,19 +313,19 @@ CssLogic.prototype = {
}
// Only work with stylesheets that have their media allowed.
if (!CssLogic.sheetMediaAllowed(aDomSheet)) {
if (!this.mediaMatches(aDomSheet)) {
return;
}
// Cache the sheet.
let cssSheet = this.getSheet(aDomSheet, false, this._sheetIndex++);
let cssSheet = this.getSheet(aDomSheet, this._sheetIndex++);
if (cssSheet._passId != this._passId) {
cssSheet._passId = this._passId;
// Find import rules.
Array.prototype.forEach.call(aDomSheet.cssRules, function(aDomRule) {
if (aDomRule.type == Ci.nsIDOMCSSRule.IMPORT_RULE && aDomRule.styleSheet &&
CssLogic.sheetMediaAllowed(aDomRule)) {
this.mediaMatches(aDomRule)) {
this._cacheSheet(aDomRule.styleSheet);
}
}, this);
@ -355,20 +359,18 @@ CssLogic.prototype = {
* otherwise the new CSSStyleSheet object is cached.
*
* @param {CSSStyleSheet} aDomSheet the CSSStyleSheet object you want.
* @param {boolean} aSystemSheet tells if the stylesheet is a browser-provided
* sheet or not.
* @param {number} aIndex the index, within the document, of the stylesheet.
*
* @return {CssSheet} the CssSheet object for the given CSSStyleSheet object.
*/
getSheet: function CL_getSheet(aDomSheet, aSystemSheet, aIndex)
getSheet: function CL_getSheet(aDomSheet, aIndex)
{
let cacheId = aSystemSheet ? "1" : "0";
let cacheId = "";
if (aDomSheet.href) {
cacheId += aDomSheet.href;
cacheId = aDomSheet.href;
} else if (aDomSheet.ownerNode && aDomSheet.ownerNode.ownerDocument) {
cacheId += aDomSheet.ownerNode.ownerDocument.location;
cacheId = aDomSheet.ownerNode.ownerDocument.location;
}
let sheet = null;
@ -377,8 +379,10 @@ CssLogic.prototype = {
if (cacheId in this._sheets) {
for (let i = 0, numSheets = this._sheets[cacheId].length; i < numSheets; i++) {
sheet = this._sheets[cacheId][i];
if (sheet.domSheet == aDomSheet) {
sheet.index = aIndex;
if (sheet.domSheet === aDomSheet) {
if (aIndex != -1) {
sheet.index = aIndex;
}
sheetFound = true;
break;
}
@ -390,8 +394,8 @@ CssLogic.prototype = {
this._sheets[cacheId] = [];
}
sheet = new CssSheet(this, aDomSheet, aSystemSheet, aIndex);
if (sheet.sheetAllowed && !aSystemSheet) {
sheet = new CssSheet(this, aDomSheet, aIndex);
if (sheet.sheetAllowed && !sheet.systemSheet) {
this._ruleCount += sheet.ruleCount;
}
@ -486,77 +490,54 @@ CssLogic.prototype = {
return;
}
if (!this._matchedRules) {
this._buildMatchedRules();
}
this._matchedSelectors = [];
this._unmatchedSelectors = null;
this._passId++;
this._matchId++;
let element = this.viewedElement;
let filter = this.sourceFilter;
let sheetIndex = 0;
let domRules = null;
do {
try {
domRules = this.domUtils.getCSSStyleRules(element);
} catch (ex) {
Services.console.
logStringMessage("CssLogic_processMatchedSelectors error: " + ex);
continue;
}
for (let i = 0; i < this._matchedRules.length; i++) {
let rule = this._matchedRules[i][0];
let status = this._matchedRules[i][1];
let status = (this.viewedElement == element) ?
CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
for (let i = 0, numRules = domRules.Count(); i < numRules; i++) {
let domRule = domRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
let domSheet = domRule.parentStyleSheet;
let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
if (filter !== CssLogic.FILTER.UA && systemSheet) {
continue;
}
let sheet = this.getSheet(domSheet, systemSheet, sheetIndex);
let rule = sheet.getRule(domRule);
rule.selectors.forEach(function (aSelector) {
if (aSelector._matchId !== this._matchId &&
element.mozMatchesSelector(aSelector)) {
aSelector._matchId = this._matchId;
this._matchedSelectors.push([ aSelector, status ]);
if (aCallback) {
aCallback.call(aScope, aSelector, status);
}
rule.selectors.forEach(function (aSelector) {
if (aSelector._matchId !== this._matchId &&
(aSelector.elementStyle ||
this._selectorMatchesElement(aSelector))) {
aSelector._matchId = this._matchId;
this._matchedSelectors.push([ aSelector, status ]);
if (aCallback) {
aCallback.call(aScope, aSelector, status);
}
}, this);
if (sheet._passId !== this._passId) {
sheetIndex++;
sheet._passId = this._passId;
}
}, this);
if (rule._passId !== this._passId) {
rule._passId = this._passId;
}
}
rule._passId = this._passId;
}
},
// Add element.style information.
if (element.style.length > 0) {
let rule = new CssRule(null, { style: element.style }, element);
let selector = rule.selectors[0];
selector._matchId = this._matchId;
this._matchedSelectors.push([ selector, status ]);
if (aCallback) {
aCallback.call(aScope, selector, status);
}
rule._passId = this._passId;
/**
* Check if the given selector matches the highlighted element or any of its
* parents.
*
* @private
* @param {string} aSelector the selector string you want to check.
* @return {boolean} true if the given selector matches the highlighted
* element or any of its parents, otherwise false is returned.
*/
_selectorMatchesElement: function CL__selectorMatchesElement(aSelector)
{
let element = this.viewedElement;
do {
if (element.mozMatchesSelector(aSelector)) {
return true;
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
return false;
},
/**
@ -573,9 +554,6 @@ CssLogic.prototype = {
*/
processUnmatchedSelectors: function CL_processUnmatchedSelectors(aCallback, aScope)
{
if (!this._matchedSelectors) {
this.processMatchedSelectors();
}
if (this._unmatchedSelectors) {
if (aCallback) {
this._unmatchedSelectors.forEach(aCallback, aScope);
@ -583,17 +561,21 @@ CssLogic.prototype = {
return;
}
if (!this._matchedSelectors) {
this.processMatchedSelectors();
}
this._unmatchedSelectors = [];
this.forEachSheet(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
return;
}
aSheet.forEachRule(function (aRule) {
aRule.selectors.forEach(function (aSelector) {
if (aSelector._matchId != this._matchId) {
if (aSelector._matchId !== this._matchId) {
this._unmatchedSelectors.push(aSelector);
if (aCallback) {
aCallback.call(aScope, aSelector);
@ -607,88 +589,205 @@ CssLogic.prototype = {
/**
* Check if the highlighted element or it's parents have matched selectors.
*
* @param {function} [aCallback] Simple callback method. If aCallback is
* provided then the domRules for each element in the loop are passed to
* the callback function. When the element has .style properties, the callback
* receives {style: element.style}. If the callback returns true then the
* element has matched rules, otherwise not.
* @return {Boolean} true if the current element or it's parents have
* matching CssSelector objects, false otherwise
* @param {array} aProperties The list of properties you want to check if they
* have matched selectors or not.
* @return {object} An object that tells for each property if it has matched
* selectors or not. Object keys are property names and values are booleans.
*/
hasMatchedSelectors: function CL_hasMatchedSelectors(aCallback)
hasMatchedSelectors: function CL_hasMatchedSelectors(aProperties)
{
if (!this._matchedRules) {
this._buildMatchedRules();
}
let result = {};
this._matchedRules.some(function(aValue) {
let rule = aValue[0];
aProperties = aProperties.filter(function(aProperty) {
if (rule.getPropertyValue(aProperty)) {
// We just need to find if a rule has this property while it matches
// the viewedElement (or its parents).
result[aProperty] = true;
return false;
}
return true; // Keep the property for the next rule.
});
return aProperties.length == 0;
}, this);
return result;
},
/**
* Build the array of matched rules for the currently highlighted element.
* The array will hold rules that match the viewedElement and its parents.
*
* @private
*/
_buildMatchedRules: function CL__buildMatchedRules()
{
let domRules;
let element = this.viewedElement;
let matched = false;
let filter = this.sourceFilter;
let sheetIndex = 0;
this._matchId++;
this._passId++;
this._matchedRules = [];
do {
let status = this.viewedElement === element ?
CssLogic.STATUS.MATCHED : CssLogic.STATUS.PARENT_MATCH;
try {
domRules = this.domUtils.getCSSStyleRules(element);
} catch (ex) {
Services.console.
logStringMessage("CssLogic_hasMatchedSelectors error: " + ex);
logStringMessage("CL__buildMatchedRules error: " + ex);
continue;
}
// Check if the are DOM rules that we can consider as matched rules
// (depending on the callback).
if (domRules.Count() && (!aCallback || aCallback(domRules))) {
matched = true;
for (let i = 0, n = domRules.Count(); i < n; i++) {
let domRule = domRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
let sheet = this.getSheet(domRule.parentStyleSheet, -1);
if (sheet._passId !== this._passId) {
sheet.index = sheetIndex++;
sheet._passId = this._passId;
}
if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
continue;
}
let rule = sheet.getRule(domRule);
if (rule._passId === this._passId) {
continue;
}
rule._matchId = this._matchId;
rule._passId = this._passId;
this._matchedRules.push([rule, status]);
}
// Check if the element has any element.style properties that we can
// consider as "matched" (depending on the callback).
if (element.style.length > 0 &&
(!aCallback || aCallback({style: element.style}))) {
matched = true;
}
if (matched) {
break;
// Add element.style information.
if (element.style.length > 0) {
let rule = new CssRule(null, { style: element.style }, element);
rule._matchId = this._matchId;
rule._passId = this._passId;
this._matchedRules.push([rule, status]);
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
return matched;
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
},
/**
* Check if the highlighted element or it's parents have unmatched selectors.
*
* @param {String} aProperty The CSS property to check against
* @return {Boolean} true if the current element or it's parents have
* unmatched CssSelector objects, false otherwise
* Please note that this method is far slower than hasMatchedSelectors()
* because it needs to do a lot more checks in the DOM.
*
* @param {array} aProperties The list of properties you want to check if they
* have unmatched selectors or not.
* @return {object} An object that tells for each property if it has unmatched
* selectors or not. Object keys are property names and values are booleans.
*/
hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperty)
hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperties)
{
return this.forSomeSheets(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet) {
if (!this._matchedRules) {
this._buildMatchedRules();
}
let result = {};
this.forSomeSheets(function (aSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
return false;
}
return aSheet.forSomeRules(function (aRule) {
if (aRule.getPropertyValue(aProperty)) {
let element = this.viewedElement;
let selectorText = aRule._domRule.selectorText;
let matches = false;
let unmatched = aRule._matchId !== this._matchId ||
this._ruleHasUnmatchedSelector(aRule);
if (!unmatched) {
return false;
}
do {
if (element.mozMatchesSelector(selectorText)) {
matches = true;
break;
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
if (!matches) {
// Now we know that there are rules but none match.
aProperties = aProperties.filter(function(aProperty) {
if (!aRule.getPropertyValue(aProperty)) {
// Keep this property for the next rule. We need to find a rule
// which has the property.
return true;
}
}
result[aProperty] = true;
// We found a rule that has the current property while it does not
// match the current element. We can remove this property from the
// array.
return false;
});
return aProperties.length == 0;
}, this);
}, this);
aProperties.forEach(function(aProperty) { result[aProperty] = false; });
return result;
},
/**
* Check if a CssRule has an unmatched selector for the highlighted element or
* its parents.
*
* @private
* @param {CssRule} aRule The rule you want to check if it has an unmatched
* selector.
* @return {boolean} True if the rule has an unmatched selector, false
* otherwise.
*/
_ruleHasUnmatchedSelector: function CL__ruleHasUnmatchedSelector(aRule)
{
if (!aRule._cssSheet && aRule.sourceElement) {
// CssRule wraps element.style, which never has unmatched selectors.
return false;
}
let element = this.viewedElement;
let selectors = aRule.selectors;
do {
selectors = selectors.filter(function(aSelector) {
return !element.mozMatchesSelector(aSelector);
});
if (selectors.length == 0) {
break;
}
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
return selectors.length > 0;
},
/**
* Tells if the given DOM CSS object matches the current view media.
*
* @param {object} aDomObject The DOM CSS object to check.
* @return {boolean} True if the DOM CSS object matches the current view
* media, or false otherwise.
*/
mediaMatches: function CL_mediaMatches(aDomObject)
{
let mediaText = aDomObject.media.mediaText;
return !mediaText || this.viewedDocument.defaultView.
matchMedia(mediaText).matches;
},
};
/**
@ -789,37 +888,6 @@ CssLogic.isSystemStyleSheet = function CssLogic_isSystemStyleSheet(aSheet)
return false;
};
/**
* Check if the given DOM CSS object holds an allowed media. Currently we only
* allow media screen or all.
*
* @param {CSSStyleSheet|CSSImportRule|CSSMediaRule} aDomObject the
* DOM object you want checked.
* @return {boolean} true if the media description is allowed, or false
* otherwise.
*/
CssLogic.sheetMediaAllowed = function CssLogic_sheetMediaAllowed(aDomObject)
{
let result = false;
let media = aDomObject.media;
if (media.length > 0) {
let mediaItem = null;
for (let m = 0, mediaLen = media.length; m < mediaLen; m++) {
mediaItem = media.item(m).toLowerCase();
if (mediaItem === CssLogic.MEDIA.SCREEN ||
mediaItem === CssLogic.MEDIA.ALL) {
result = true;
break;
}
}
} else {
result = true;
}
return result;
};
/**
* Return a shortened version of a style sheet's source.
*
@ -827,27 +895,33 @@ CssLogic.sheetMediaAllowed = function CssLogic_sheetMediaAllowed(aDomObject)
*/
CssLogic.shortSource = function CssLogic_shortSource(aSheet)
{
// Use a string like "inline" if there is no source href
if (!aSheet || !aSheet.href) {
return CssLogic.l10n("rule.sourceInline");
}
// Use a string like "inline" if there is no source href
if (!aSheet || !aSheet.href) {
return CssLogic.l10n("rule.sourceInline");
}
// We try, in turn, the filename, filePath, query string, whole thing
let url = Services.io.newURI(aSheet.href, null, null);
// We try, in turn, the filename, filePath, query string, whole thing
let url = {};
try {
url = Services.io.newURI(aSheet.href, null, null);
url = url.QueryInterface(Ci.nsIURL);
if (url.fileName) {
return url.fileName;
}
} catch (ex) {
// Some UA-provided stylesheets are not valid URLs.
}
if (url.filePath) {
return url.filePath;
}
if (url.fileName) {
return url.fileName;
}
if (url.query) {
return url.query;
}
if (url.filePath) {
return url.filePath;
}
return this.domSheet.href;
if (url.query) {
return url.query;
}
return aSheet.href;
}
/**
@ -857,15 +931,13 @@ CssLogic.shortSource = function CssLogic_shortSource(aSheet)
* @param {CssLogic} aCssLogic pointer to the CssLogic instance working with
* this CssSheet object.
* @param {CSSStyleSheet} aDomSheet reference to a DOM CSSStyleSheet object.
* @param {boolean} aSystemSheet tells if the stylesheet is system-provided.
* @param {number} aIndex tells the index/position of the stylesheet within the
* main document.
*/
function CssSheet(aCssLogic, aDomSheet, aSystemSheet, aIndex)
function CssSheet(aCssLogic, aDomSheet, aIndex)
{
this._cssLogic = aCssLogic;
this.domSheet = aDomSheet;
this.systemSheet = aSystemSheet;
this.index = this.systemSheet ? -100 * aIndex : aIndex;
// Cache of the sheets href. Cached by the getter.
@ -884,6 +956,44 @@ function CssSheet(aCssLogic, aDomSheet, aSystemSheet, aIndex)
CssSheet.prototype = {
_passId: null,
_systemSheet: null,
_mediaMatches: null,
/**
* Tells if the stylesheet is provided by the browser or not.
*
* @return {boolean} true if this is a browser-provided stylesheet, or false
* otherwise.
*/
get systemSheet()
{
if (this._systemSheet === null) {
this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
}
return this._systemSheet;
},
/**
* Tells if the stylesheet is disabled or not.
* @return {boolean} true if this stylesheet is disabled, or false otherwise.
*/
get disabled()
{
return this.domSheet.disabled;
},
/**
* Tells if the stylesheet matches the current browser view media.
* @return {boolean} true if this stylesheet matches the current browser view
* media, or false otherwise.
*/
get mediaMatches()
{
if (this._mediaMatches === null) {
this._mediaMatches = this._cssLogic.mediaMatches(this.domSheet);
}
return this._mediaMatches;
},
/**
* Get a source for a stylesheet, taking into account embedded stylesheets
@ -976,7 +1086,7 @@ CssSheet.prototype = {
if (cacheId in this._rules) {
for (let i = 0, rulesLen = this._rules[cacheId].length; i < rulesLen; i++) {
rule = this._rules[cacheId][i];
if (rule._domRule == aDomRule) {
if (rule._domRule === aDomRule) {
ruleFound = true;
break;
}
@ -1018,7 +1128,7 @@ CssSheet.prototype = {
aCallback.call(aScope, this.getRule(aDomRule));
ruleCount++;
} else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
Array.prototype.forEach.call(aDomRule.cssRules, _iterator, this);
}
}
@ -1051,7 +1161,7 @@ CssSheet.prototype = {
if (aDomRule.type == Ci.nsIDOMCSSRule.STYLE_RULE) {
return aCallback.call(aScope, this.getRule(aDomRule));
} else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
aDomRule.cssRules && this._cssLogic.mediaMatches(aDomRule)) {
return Array.prototype.some.call(aDomRule.cssRules, _iterator, this);
}
}
@ -1409,8 +1519,6 @@ function CssPropertyInfo(aCssLogic, aProperty)
// that have sheetAllowed = false).
this._matchedSelectors = null;
this._unmatchedSelectors = null;
this._hasMatchedSelectors = null;
this._hasUnmatchedSelectors = null;
}
CssPropertyInfo.prototype = {
@ -1508,60 +1616,6 @@ CssPropertyInfo.prototype = {
return this._unmatchedSelectors;
},
/**
* Check if the property has any matched selectors.
*
* @return {Boolean} true if the current element or it's parents have
* matching CssSelector objects, false otherwise
*/
hasMatchedSelectors: function CssPropertyInfo_hasMatchedSelectors()
{
if (this._hasMatchedSelectors === null) {
this._hasMatchedSelectors = this._cssLogic.hasMatchedSelectors(function(aDomRules) {
if (!aDomRules.Count) {
// For element.style.
return !!aDomRules.style.getPropertyValue(this.property);
}
for (let i = 0; i < aDomRules.Count(); i++) {
let domRule = aDomRules.GetElementAt(i);
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
let domSheet = domRule.parentStyleSheet;
let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
let filter = this._cssLogic.sourceFilter;
if (filter !== CssLogic.FILTER.UA && systemSheet) {
continue;
}
if (domRule.style.getPropertyValue(this.property)) {
return true;
}
}
return false;
}.bind(this));
}
return this._hasMatchedSelectors;
},
/**
* Check if the property has any matched selectors.
*
* @return {Boolean} true if the current element or it's parents have
* unmatched CssSelector objects, false otherwise
*/
hasUnmatchedSelectors: function CssPropertyInfo_hasUnmatchedSelectors()
{
if (this._hasUnmatchedSelectors === null) {
this._hasUnmatchedSelectors = this._cssLogic.hasUnmatchedSelectors(this.property);
}
return this._hasUnmatchedSelectors;
},
/**
* Find the selectors that match the highlighted element and its parents.
* Uses CssLogic.processMatchedSelectors() to find the matched selectors,

View File

@ -117,6 +117,17 @@ ElementStyle.prototype = {
domUtils: Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils),
/**
* Called by the Rule object when it has been changed through the
* setProperty* methods.
*/
_changed: function ElementStyle_changed()
{
if (this.onChanged) {
this.onChanged();
}
},
/**
* Refresh the list of rules to be displayed for the active element.
* Upon completion, this.rules[] will hold a list of Rule objects.
@ -125,19 +136,29 @@ ElementStyle.prototype = {
{
this.rules = [];
let element = this.element;
do {
this._addElementRules(element);
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
// Mark overridden computed styles.
this.markOverridden();
},
_addElementRules: function ElementStyle_addElementRules(aElement)
{
let inherited = aElement !== this.element ? aElement : null;
// Include the element's style first.
this.rules.push(new Rule(this, {
style: this.element.style,
selectorText: CssLogic.l10n("rule.sourceElement")
}));
this._maybeAddRule({
style: aElement.style,
selectorText: CssLogic.l10n("rule.sourceElement"),
inherited: inherited
});
// Get the styles that apply to the element.
try {
var domRules = this.domUtils.getCSSStyleRules(this.element);
} catch (ex) {
Services.console.logStringMessage("ElementStyle_populate error: " + ex);
return;
}
var domRules = this.domUtils.getCSSStyleRules(aElement);
// getCSStyleRules returns ordered from least-specific to
// most-specific.
@ -150,14 +171,43 @@ ElementStyle.prototype = {
continue;
}
// XXX: non-style rules.
if (domRule.type === Ci.nsIDOMCSSRule.STYLE_RULE) {
this.rules.push(new Rule(this, { domRule: domRule }));
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
this._maybeAddRule({
domRule: domRule,
inherited: inherited
});
}
},
/**
* Add a rule if it's one we care about. Filters out duplicates and
* inherited styles with no inherited properties.
*
* @param {object} aOptions
* Options for creating the Rule, see the Rule constructor.
*
* @return true if we added the rule.
*/
_maybeAddRule: function ElementStyle_maybeAddRule(aOptions)
{
// If we've already included this domRule (for example, when a
// common selector is inherited), ignore it.
if (aOptions.domRule &&
this.rules.some(function(rule) rule.domRule === aOptions.domRule)) {
return false;
}
// Mark overridden computed styles.
this.markOverridden();
let rule = new Rule(this, aOptions);
// Ignore inherited rules with no properties.
if (aOptions.inherited && rule.textProps.length == 0) {
return false;
}
this.rules.push(rule);
},
/**
@ -178,7 +228,7 @@ ElementStyle.prototype = {
let computedProps = [];
for each (let textProp in textProps) {
computedProps = computedProps.concat(textProp.computed);
};
}
// Walk over the computed properties. As we see a property name
// for the first time, mark that property's name as taken by this
@ -214,7 +264,7 @@ ElementStyle.prototype = {
computedProp._overriddenDirty = (!!computedProp.overridden != overridden);
computedProp.overridden = overridden;
if (!computedProp.overridden) {
if (!computedProp.overridden && computedProp.textProp.enabled) {
taken[computedProp.name] = computedProp;
}
}
@ -273,6 +323,8 @@ ElementStyle.prototype = {
* the domRule's style will be used.
* selectorText: selector text to display. If omitted, the domRule's
* selectorText will be used.
* inherited: An element this rule was inherited from. If omitted,
* the rule applies directly to the current element.
* @constructor
*/
function Rule(aElementStyle, aOptions)
@ -281,7 +333,7 @@ function Rule(aElementStyle, aOptions)
this.domRule = aOptions.domRule || null;
this.style = aOptions.style || this.domRule.style;
this.selectorText = aOptions.selectorText || this.domRule.selectorText;
this.inherited = aOptions.inherited || null;
this._getTextProperties();
}
@ -297,6 +349,17 @@ Rule.prototype = {
let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
this._title += ":" + line;
}
if (this.inherited) {
let eltText = this.inherited.tagName.toLowerCase();
if (this.inherited.id) {
eltText += "#" + this.inherited.id;
}
let args = [eltText, this._title];
this._title = CssLogic._strings.formatStringFromName("rule.inheritedSource",
args, args.length);
}
return this._title;
},
@ -336,6 +399,7 @@ Rule.prototype = {
prop.priority = this.style.getPropertyPriority(prop.name);
prop.updateComputed();
}
this.elementStyle._changed();
this.elementStyle.markOverridden();
},
@ -416,7 +480,13 @@ Rule.prototype = {
if(!matches || !matches[2])
continue;
let prop = new TextProperty(this, matches[1], matches[2], matches[3] || "");
let name = matches[1];
if (this.inherited &&
!this.elementStyle.domUtils.isInheritedProperty(name)) {
continue;
}
let prop = new TextProperty(this, name, matches[2], matches[3] || "");
this.textProps.push(prop);
}
},
@ -478,6 +548,7 @@ TextProperty.prototype = {
for (let i = 0, n = dummyStyle.length; i < n; i++) {
let prop = dummyStyle.item(i);
this.computed.push({
textProp: this,
name: prop,
value: dummyStyle.getPropertyValue(prop),
priority: dummyStyle.getPropertyPriority(prop),
@ -568,7 +639,15 @@ CssRuleView.prototype = {
return;
}
if (this._elementStyle) {
delete this._elementStyle.onChanged;
}
this._elementStyle = new ElementStyle(aElement);
this._elementStyle.onChanged = function() {
this._changed();
}.bind(this);
this._createEditors();
},
@ -584,6 +663,17 @@ CssRuleView.prototype = {
this._elementStyle = null;
},
/**
* Called when the user has made changes to the ElementStyle.
* Emits an event that clients can listen to.
*/
_changed: function CssRuleView_changed()
{
var evt = this.doc.createEvent("Events");
evt.initEvent("CssRuleViewChanged", true, false);
this.element.dispatchEvent(evt);
},
/**
* Creates editor UI for each of the rules in _elementStyle.
*/
@ -944,10 +1034,12 @@ TextPropertyEditor.prototype = {
*/
_parseValue: function TextPropertyEditor_parseValue(aValue)
{
let [value, priority] = aValue.split("!", 2);
let pieces = aValue.split("!", 2);
let value = pieces[0];
let priority = pieces.length > 1 ? pieces[1] : "";
return {
value: value.trim(),
priority: (priority ? priority.trim() : "")
value: pieces[0].trim(),
priority: (pieces.length > 1 ? pieces[1].trim() : "")
};
},

View File

@ -87,6 +87,7 @@ StyleInspector.prototype = {
context: this,
get isOpen() isOpen(),
onSelect: this.selectNode,
onChanged: this.updateNode,
show: this.open,
hide: this.close,
dim: this.dimTool,
@ -112,7 +113,7 @@ StyleInspector.prototype = {
let boundIframeOnLoad = function loadedInitializeIframe() {
if (this.iframe &&
this.iframe.getAttribute("src") ==
"chrome://browser/content/csshtmltree.xhtml") {
"chrome://browser/content/devtools/csshtmltree.xul") {
let selectedNode = this.selectedNode || null;
this.cssHtmlTree = new CssHtmlTree(this);
this.cssLogic.highlight(selectedNode);
@ -152,10 +153,6 @@ StyleInspector.prototype = {
panel.setAttribute("width", 350);
panel.setAttribute("height", this.window.screen.height / 2);
let vbox = this.document.createElement("vbox");
vbox.setAttribute("flex", "1");
panel.appendChild(vbox);
let iframe = this.document.createElement("iframe");
let boundIframeOnLoad = function loadedInitializeIframe()
{
@ -165,24 +162,12 @@ StyleInspector.prototype = {
aCallback(this);
}.bind(this);
iframe.setAttribute("flex", "1");
iframe.flex = 1;
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.addEventListener("load", boundIframeOnLoad, true);
iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
iframe.setAttribute("src", "chrome://browser/content/devtools/csshtmltree.xul");
vbox.appendChild(iframe);
let hbox = this.document.createElement("hbox");
hbox.setAttribute("class", "resizerbox");
vbox.appendChild(hbox);
let spacer = this.document.createElement("spacer");
spacer.setAttribute("flex", "1");
hbox.appendChild(spacer);
let resizer = this.document.createElement("resizer");
resizer.setAttribute("dir", "bottomend");
hbox.appendChild(resizer);
panel.appendChild(iframe);
popupSet.appendChild(panel);
this._boundPopupShown = this.popupShown.bind(this);
@ -263,6 +248,17 @@ StyleInspector.prototype = {
}
},
/**
* Update the display for the currently-selected node.
*/
updateNode: function SI_updateNode()
{
if (this.isOpen() && !this.dimmed) {
this.cssLogic.highlight(this.selectedNode);
this.cssHtmlTree.refreshPanel();
}
},
/**
* Dim or undim a panel by setting or removing a dimmed attribute.
* @param aState
@ -282,7 +278,7 @@ StyleInspector.prototype = {
this.selectNode(aSelection);
if (this.openDocked) {
if (!this.iframeReady) {
this.iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
this.iframe.setAttribute("src", "chrome://browser/content/devtools/csshtmltree.xul");
}
} else {
this.panel.openPopup(this.window.gBrowser.selectedBrowser, "end_before", 0, 0,

View File

@ -1,20 +1,4 @@
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
%inspectorDTD;
<!ELEMENT loop ANY>
<!ATTLIST li foreach CDATA #IMPLIED>
<!ATTLIST div foreach CDATA #IMPLIED>
<!ATTLIST loop foreach CDATA #IMPLIED>
<!ATTLIST a target CDATA #IMPLIED>
<!ATTLIST a __pathElement CDATA #IMPLIED>
<!ATTLIST div _id CDATA #IMPLIED>
<!ATTLIST div save CDATA #IMPLIED>
<!ATTLIST table save CDATA #IMPLIED>
<!ATTLIST loop if CDATA #IMPLIED>
<!ATTLIST tr if CDATA #IMPLIED>
]>
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
@ -35,9 +19,10 @@
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Joe Walker (jwalker@mozilla.com) (original author)
- Joe Walker <jwalker@mozilla.com> (original author)
- Mihai Șucan <mihai.sucan@gmail.com>
- Michael Ratcliffe <mratcliffe@mozilla.com>
- Dão Gottwald <dao@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
@ -52,28 +37,52 @@
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=UTF-8" />
<link rel="stylesheet" type="text/css"
href="chrome://browser/skin/devtools/csshtmltree.css" />
</head>
<body role="application">
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
%inspectorDTD;
<!ELEMENT loop ANY>
<!ATTLIST li foreach CDATA #IMPLIED>
<!ATTLIST div foreach CDATA #IMPLIED>
<!ATTLIST loop foreach CDATA #IMPLIED>
<!ATTLIST a target CDATA #IMPLIED>
<!ATTLIST a __pathElement CDATA #IMPLIED>
<!ATTLIST div _id CDATA #IMPLIED>
<!ATTLIST div save CDATA #IMPLIED>
<!ATTLIST table save CDATA #IMPLIED>
<!ATTLIST loop if CDATA #IMPLIED>
<!ATTLIST tr if CDATA #IMPLIED>
]>
<xul:window xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<!-- The output from #templateRoot (below) is inserted here. -->
<div id="root">
</div>
<div id="root"></div>
<!-- The output from #templatePath (below) is inserted here. -->
<div id="path">
</div>
<!-- When no properties are found the following block is displayed. -->
<div id="noResults" hidden="">
&noPropertiesFound;
</div>
<!-- The output from #templateProperty (below) is appended here. -->
<div id="propertyContainer">
</div>
<xul:hbox id="footer">
<xul:label class="legendKey bestmatch">&bestMatch;</xul:label>
<xul:label class="legendKey matched">&matched;</xul:label>
<xul:label class="legendKey parentmatch">&parentMatch;</xul:label>
<xul:spacer flex="1"/>
<xul:resizer dir="bottomright"/>
</xul:hbox>
<!--
To visually debug the templates without running firefox, alter the display:none
-->
@ -83,15 +92,16 @@ To visually debug the templates without running firefox, alter the display:none
styles" checkbox. For data it needs an instance of CssHtmlTree.
-->
<div id="templateRoot">
<div class="filters">
<label class="userStylesLabel" dir="${getRTLAttr}">
<xul:hbox class="headerControls" flex="1">
<label class="userStylesLabel">
<input class="onlyuserstyles" save="${onlyUserStylesCheckbox}"
type="checkbox" onchange="${onlyUserStylesChanged}" checked=""/>
&userStylesLabel;
<input class="userStyles" save="${onlyUserStylesCheckbox}" type="checkbox"
onchange="${onlyUserStylesChanged}" checked=""/>
</label>
<input save="${searchField}" class="searchfield" type="text"
oninput="${filterChanged}"/>
</div>
<xul:textbox class="searchfield" type="search" save="${searchField}"
placeholder="&userStylesSearch;"
oncommand="${filterChanged}"/>
</xul:hbox>
</div>
<!--
@ -99,16 +109,17 @@ To visually debug the templates without running firefox, alter the display:none
at. For data it needs an instance of CssHtmlTree.
-->
<div id="templatePath">
<p class="path">
<label dir="${getRTLAttr}">&lookingAtLabel;</label>
<ol>
<li foreach="item in ${pathElements}" dir="${getRTLAttr}">
<a href="#" onclick="${pathClick}" __pathElement="${item.element}">
${__element.pathElement = item.element; item.display}
</a>
</li>
</ol>
</p>
<span class="selectedElementLabel">
&selectedElementLabel;
</span>
<!-- following broken in RTL mode, see bug 699900 -->
<ol>
<li foreach="item in ${pathElements}">
<a href="#" onclick="${pathClick}" __pathElement="${item.element}">
${__element.pathElement = item.element; item.display}
</a>
</li>
</ol>
</div>
<!--
@ -118,29 +129,20 @@ To visually debug the templates without running firefox, alter the display:none
}
-->
<div id="templateProperty">
<div class="${className}" save="${element}" dir="${getRTLAttr}">
<div class="property-header">
<div class="property-name" dir="${getRTLAttr}">
<a class="link" target="_blank" title="&helpLinkTitle;"
href="${link}">${name}</a>
<div class="${className}" save="${element}">
<xul:hbox class="property-header" save="${propertyHeader}"
onclick="${propertyHeaderClick}">
<div save="${matchedExpander}" class="match expander"/>
<div class="property-name">${name}</div>
<div class="helplink-container">
<a href="${link}" class="helplink" title="&helpLinkTitle;" onclick="${mdnLinkClick}">
&helpLinkTitle;
</a>
</div>
<div save="${valueNode}" class="property-value" dir="ltr">${value}</div>
</div>
</xul:hbox>
<div save="${matchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
<div onclick="${matchedSelectorsClick}" class="rule-matched">
<div save="${matchedExpander}" class="expander"></div>
<div save="${matchedSelectorsTitleNode}">&matchedSelectors;</div>
</div>
<table save="${matchedSelectorTable}" dir="${getRTLAttr}"></table>
</div>
<div save="${unmatchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
<div onclick="${unmatchedSelectorsClick}" class="rule-unmatched">
<div save="${unmatchedExpander}" class="expander"></div>
<div save="${unmatchedSelectorsTitleNode}">&unmatchedSelectors;</div>
</div>
<table save="${unmatchedSelectorTable}" dir="${getRTLAttr}"></table>
<div save="${matchedSelectorsContainer}" class="rulelink">
</div>
</div>
</div>
@ -163,32 +165,7 @@ To visually debug the templates without running firefox, alter the display:none
</td>
<td class="rule-link">
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
</td>
</tr>
</loop>
</table>
</div>
<!--
A templateUnmatchedSelectors sits inside each templateProperties showing the
list of selectors that fail to affect that property. Each needs data like this:
{
unmatchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].unmatchedSelectorViews
}
This is a template so the parent does not need to be a table, except that
using a div as the parent causes the DOM to muck with the tr elements
-->
<div id="templateUnmatchedSelectors">
<table>
<loop foreach="selector in ${unmatchedSelectorViews}">
<tr>
<td dir="ltr" class="rule-text unmatched">
${selector.humanReadableText(__element)}
</td>
<td class="rule-link">
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
</td>
</tr>
</loop>
@ -196,5 +173,4 @@ To visually debug the templates without running firefox, alter the display:none
</div>
</div>
</body>
</html>
</xul:window>

View File

@ -1,9 +1,4 @@
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/styleinspector.dtd">
%inspectorDTD;
]>
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
@ -39,15 +34,11 @@
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<meta http-equiv="Content-Type"
content="application/xhtml+xml; charset=UTF-8" />
<link rel="stylesheet" type="text/css"
href="chrome://browser/content/devtools/styleinspector.css" />
<link rel="stylesheet" type="text/css"
href="chrome://browser/skin/devtools/csshtmltree.css" />
</head>
<body role="application" id="ruleview-body"></body>
</html>
<?xml-stylesheet href="chrome://global/skin/global.css"?>
<?xml-stylesheet href="chrome://browser/content/devtools/styleinspector.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
%inspectorDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>

View File

@ -51,8 +51,10 @@ _BROWSER_TEST_FILES = \
browser_bug683672.js \
browser_styleinspector_bug_672746_default_styles.js \
browser_styleinspector_bug_672744_search_filter.js \
browser_styleinspector_bug_689759_no_results_placeholder.js \
browser_bug_692400_element_style.js \
browser_ruleview_editor.js \
browser_ruleview_inherit.js \
browser_ruleview_manipulation.js \
browser_ruleview_override.js \
browser_ruleview_ui.js \

View File

@ -38,7 +38,7 @@ function runTests()
ok(stylePanel.isOpen(), "style inspector is open");
testMatchedSelectors();
testUnmatchedSelectors();
//testUnmatchedSelectors();
info("finishing up");
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
@ -65,7 +65,7 @@ function testMatchedSelectors()
is(numMatchedSelectors, 6,
"CssLogic returns the correct number of matched selectors for div");
is(propertyView.propertyInfo.hasMatchedSelectors(), true,
is(propertyView.hasMatchedSelectors, true,
"hasMatchedSelectors returns true");
}
@ -89,7 +89,7 @@ function testUnmatchedSelectors()
is(numUnmatchedSelectors, 13,
"CssLogic returns the correct number of unmatched selectors for body");
is(propertyView.propertyInfo.hasUnmatchedSelectors(), true,
is(propertyView.hasUnmatchedSelectors, true,
"hasUnmatchedSelectors returns true");
}

View File

@ -44,7 +44,7 @@ function SI_checkText()
propertyView.matchedExpanded = true;
propertyView.refreshMatchedSelectors();
let td = propertyView.matchedSelectorTable.querySelector("td.rule-text");
let td = propertyView.matchedSelectorsContainer.querySelector("td.rule-text");
ok(td, "found the first table row");
let selector = propertyView.matchedSelectorViews[0];

View File

@ -0,0 +1,101 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/CssRuleView.jsm");
let doc;
function simpleInherit()
{
let style = '' +
'#test2 {' +
' background-color: green;' +
' color: purple;' +
'}';
let styleNode = addStyle(doc, style);
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 2, "Should have 2 rules.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
let inheritRule = elementStyle.rules[1];
is(inheritRule.selectorText, "#test2", "Inherited rule should be the one that includes inheritable properties.");
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
let inheritProp = inheritRule.textProps[0];
is(inheritProp.name, "color", "color should have been inherited.");
styleNode.parentNode.removeChild(styleNode);
emptyInherit();
}
function emptyInherit()
{
// No inheritable styles, this rule shouldn't show up.
let style = '' +
'#test2 {' +
' background-color: green;' +
'}';
let styleNode = addStyle(doc, style);
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 1, "Should have 1 rule.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
styleNode.parentNode.removeChild(styleNode);
elementStyleInherit();
}
function elementStyleInherit()
{
doc.body.innerHTML = '<div id="test2" style="color: red"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 2, "Should have 2 rules.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
let inheritRule = elementStyle.rules[1];
ok(!inheritRule.domRule, "Inherited rule should be an element style, not a rule.");
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
let inheritProp = inheritRule.textProps[0];
is(inheritProp.name, "color", "color should have been inherited.");
finishTest();
}
function finishTest()
{
doc = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
doc = content.document;
waitForFocus(simpleInherit, content);
}, true);
content.location = "data:text/html,basic style inspector tests";
}

View File

@ -110,6 +110,33 @@ function importantOverride()
ok(classProp.overridden, "New important prop should override class property.");
ok(!elementProp.overridden, "New important prop should not be overriden.");
disableOverride();
}
function disableOverride()
{
let style = '' +
'#testid {' +
' background-color: blue;' +
'}' +
'.testclass {' +
' background-color: green;' +
'}';
let styleNode = addStyle(doc, style);
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
let elementStyle = new _ElementStyle(doc.getElementById("testid"));
let idRule = elementStyle.rules[1];
let idProp = idRule.textProps[0];
idProp.setEnabled(false);
let classRule = elementStyle.rules[2];
let classProp = classRule.textProps[0];
ok(!classProp.overridden, "Class prop should not be overridden after id prop was disabled.");
styleNode.parentNode.removeChild(styleNode);
finishTest();
}

View File

@ -32,6 +32,18 @@ function waitForEditorBlur(aEditor, aCallback)
}, false);
}
var gRuleViewChanged = false;
function ruleViewChanged()
{
gRuleViewChanged = true;
}
function expectChange()
{
ok(gRuleViewChanged, "Rule view should have fired a change event.");
gRuleViewChanged = false;
}
function startTest()
{
let style = '' +
@ -46,15 +58,15 @@ function startTest()
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
let testElement = doc.getElementById("testid");
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xul",
"cssruleviewtest",
"width=200,height=350");
ruleDialog.addEventListener("load", function onLoad(evt) {
ruleDialog.removeEventListener("load", onLoad);
let doc = ruleDialog.document;
let body = doc.getElementById("ruleview-body");
ruleView = new CssRuleView(doc);
body.appendChild(ruleView.element);
doc.documentElement.appendChild(ruleView.element);
ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
ruleView.highlight(testElement);
waitForFocus(testCancelNew, ruleDialog);
}, true);
@ -70,6 +82,7 @@ function testCancelNew()
is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
let input = aEditor.input;
waitForEditorBlur(aEditor, function () {
ok(!gRuleViewChanged, "Shouldn't get a change event after a cancel.");
is(elementRuleEditor.rule.textProps.length, 0, "Should have canceled creating a new text property.");
ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
testCreateNew();
@ -92,6 +105,7 @@ function testCreateNew()
input.value = "background-color";
waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
expectChange();
is(elementRuleEditor.rule.textProps.length, 1, "Should have created a new text property.");
is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
let textProp = elementRuleEditor.rule.textProps[0];
@ -99,6 +113,7 @@ function testCreateNew()
aEditor.input.value = "purple";
waitForEditorBlur(aEditor, function() {
expectChange();
is(textProp.value, "purple", "Text prop should have been changed.");
testEditProperty();
});
@ -121,10 +136,12 @@ function testEditProperty()
is(propEditor.nameSpan.inplaceEditor, aEditor, "Next focused editor should be the name editor.");
let input = aEditor.input;
waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
expectChange();
input = aEditor.input;
is(propEditor.valueSpan.inplaceEditor, aEditor, "Focus should have moved to the value.");
waitForEditorBlur(aEditor, function() {
expectChange();
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
"border-color should have been set.");
testDisableProperty();
@ -151,14 +168,20 @@ function testDisableProperty()
propEditor.enable.click();
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "", "Border-color should have been unset.");
expectChange();
propEditor.enable.click();
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
"Border-color should have been reset.");
expectChange();
finishTest();
}
function finishTest()
{
ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
ruleView.clear();
ruleDialog.close();
ruleDialog = ruleView = null;
doc = null;

View File

@ -64,7 +64,7 @@ function SI_CheckProperty()
let cssLogic = stylePanel.cssLogic;
let propertyInfo = cssLogic.getPropertyInfo("color");
ok(propertyInfo.matchedRuleCount > 0, "color property has matching rules");
ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
//ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
}
function finishUp()

View File

@ -52,8 +52,9 @@ function SI_toggleDefaultStyles()
Services.obs.removeObserver(SI_toggleDefaultStyles, "StyleInspector-populated", false);
info("clearing \"only user styles\" checkbox");
let iframe = stylePanel.iframe;
let checkbox = iframe.contentDocument.querySelector(".userStyles");
let checkbox = iframe.contentDocument.querySelector(".onlyuserstyles");
Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
}
@ -64,7 +65,6 @@ function SI_AddFilterText()
let iframe = stylePanel.iframe;
let searchbar = iframe.contentDocument.querySelector(".searchfield");
Services.obs.addObserver(SI_checkFilter, "StyleInspector-populated", false);
info("setting filter text to \"color\"");
searchbar.focus();

View File

@ -62,7 +62,7 @@ function SI_toggleDefaultStyles()
{
// Click on the checkbox.
let iframe = stylePanel.iframe;
let checkbox = iframe.contentDocument.querySelector(".userStyles");
let checkbox = iframe.contentDocument.querySelector(".onlyuserstyles");
Services.obs.addObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
}
@ -86,7 +86,7 @@ function propertyVisible(aName)
let propertyViews = stylePanel.cssHtmlTree.propertyViews;
for each (let propView in propertyViews) {
if (propView.name == aName) {
return propView.className == "property-view";
return propView.visible;
}
}
}

View File

@ -0,0 +1,118 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the no results placeholder works properly.
let doc;
let stylePanel;
function createDocument()
{
doc.body.innerHTML = '<style type="text/css"> ' +
'.matches {color: #F00;}</style>' +
'<span id="matches" class="matches">Some styled text</span>';
doc.title = "Tests that the no results placeholder works properly";
ok(window.StyleInspector, "StyleInspector exists");
stylePanel = new StyleInspector(window);
Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
stylePanel.createPanel(false, function() {
stylePanel.open(doc.body);
});
}
function runStyleInspectorTests()
{
Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
ok(stylePanel.isOpen(), "style inspector is open");
Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
let span = doc.querySelector("#matches");
ok(span, "captain, we have the matches span");
let htmlTree = stylePanel.cssHtmlTree;
stylePanel.selectNode(span);
is(span, htmlTree.viewedElement,
"style inspector node matches the selected node");
is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
}
function SI_AddFilterText()
{
Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated", false);
let iframe = stylePanel.iframe;
let searchbar = stylePanel.cssHtmlTree.searchField;
let searchTerm = "xxxxx";
Services.obs.addObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
info("setting filter text to \"" + searchTerm + "\"");
searchbar.focus();
for each (let c in searchTerm) {
EventUtils.synthesizeKey(c, {}, iframe.contentWindow);
}
}
function SI_checkPlaceholderVisible()
{
Services.obs.removeObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
info("SI_checkPlaceholderVisible called");
let placeholder = stylePanel.cssHtmlTree.noResults;
let iframe = stylePanel.iframe;
let display = iframe.contentWindow.getComputedStyle(placeholder).display;
is(display, "block", "placeholder is visible");
SI_ClearFilterText();
}
function SI_ClearFilterText()
{
let iframe = stylePanel.iframe;
let searchbar = stylePanel.cssHtmlTree.searchField;
Services.obs.addObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
info("clearing filter text");
searchbar.focus();
searchbar.value = "";
EventUtils.synthesizeKey("c", {}, iframe.contentWindow);
}
function SI_checkPlaceholderHidden()
{
Services.obs.removeObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
let placeholder = stylePanel.cssHtmlTree.noResults;
let iframe = stylePanel.iframe;
let display = iframe.contentWindow.getComputedStyle(placeholder).display;
is(display, "none", "placeholder is hidden");
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
stylePanel.close();
}
function finishUp()
{
Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
ok(!stylePanel.isOpen(), "style inspector is closed");
doc = stylePanel = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,no results placeholder test";
}

View File

@ -198,7 +198,9 @@ const LEVELS = {
dir: SEVERITY_LOG,
group: SEVERITY_LOG,
groupCollapsed: SEVERITY_LOG,
groupEnd: SEVERITY_LOG
groupEnd: SEVERITY_LOG,
time: SEVERITY_LOG,
timeEnd: SEVERITY_LOG
};
// The lowest HTTP response code (inclusive) that is considered an error.
@ -2094,6 +2096,30 @@ HUD_SERVICE.prototype =
}
return;
case "time":
if (!args) {
return;
}
if (args.error) {
Cu.reportError(this.getStr(args.error));
return;
}
body = this.getFormatStr("timerStarted", [args.name]);
clipboardText = body;
sourceURL = aMessage.filename;
sourceLine = aMessage.lineNumber;
break;
case "timeEnd":
if (!args) {
return;
}
body = this.getFormatStr("timeEnd", [args.name, args.duration]);
clipboardText = body;
sourceURL = aMessage.filename;
sourceLine = aMessage.lineNumber;
break;
default:
Cu.reportError("Unknown Console API log level: " + level);
return;
@ -4622,7 +4648,7 @@ function JSTermHelper(aJSTerm)
});
let iframe = createAndAppendElement(panel, "iframe", {
src: "chrome://browser/content/devtools/cssruleview.xhtml",
src: "chrome://browser/content/devtools/cssruleview.xul",
flex: "1",
});
@ -4630,8 +4656,7 @@ function JSTermHelper(aJSTerm)
panel.removeEventListener("load", onLoad, true);
let doc = iframe.contentDocument;
let view = new CssRuleView(doc);
let body = doc.getElementById("ruleview-body");
body.appendChild(view.element);
doc.documentElement.appendChild(view.element);
view.highlight(aNode);
}, true);

View File

@ -149,6 +149,7 @@ _BROWSER_TEST_FILES = \
browser_gcli_integrate.js \
browser_gcli_require.js \
browser_gcli_web.js \
browser_webconsole_bug_658368_time_methods.js \
head.js \
$(NULL)
@ -220,6 +221,7 @@ _BROWSER_TEST_PAGES = \
test-bug-678816-content.js \
test-file-location.js \
browser_gcli_inspect.html \
test-bug-658368-time-methods.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

View File

@ -0,0 +1,87 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that the Console API implements the time() and timeEnd() methods.
function test() {
addTab("http://example.com/browser/browser/devtools/webconsole/" +
"test/browser/test-bug-658368-time-methods.html");
openConsole();
browser.addEventListener("load", onLoad, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
executeSoon(function() {
findLogEntry("aTimer: timer started");
findLogEntry("ms");
// The next test makes sure that timers with the same name but in separate
// tabs, do not contain the same value.
addTab("data:text/html,<script type='text/javascript'>" +
"console.timeEnd('bTimer');</script>");
openConsole();
browser.addEventListener("load", testTimerIndependenceInTabs, true);
});
}
function testTimerIndependenceInTabs(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInTabs, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
executeSoon(function() {
testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
false, true);
// 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);
content.location = "data:text/html,<script type='text/javascript'>" +
"console.time('bTimer');</script>";
});
}
function testTimerIndependenceInSameTab(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTab, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
executeSoon(function() {
findLogEntry("bTimer: timer started");
hud.jsterm.clearOutput();
// Now the following console.timeEnd() call shouldn't display anything,
// if the timers in different pages are not related.
browser.addEventListener("load", testTimerIndependenceInSameTabAgain, true);
content.location = "data:text/html,<script type='text/javascript'>" +
"console.timeEnd('bTimer');</script>";
});
}
function testTimerIndependenceInSameTabAgain(aEvent) {
browser.removeEventListener(aEvent.type, testTimerIndependenceInSameTabAgain, true);
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
executeSoon(function() {
testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
false, true);
finishTest();
});
}

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<title>Test for bug 658368: Expand console object with time and timeEnd
methods</title>
</head>
<body>
<h1>Test for bug 658368: Expand console object with time and timeEnd
methods</h1>
<script type="text/javascript">
function foo() {
console.timeEnd("aTimer");
}
console.time("aTimer");
foo();
console.time("bTimer");
</script>
</body>
</html>

View File

@ -4,8 +4,6 @@
<script type="text/javascript">
function test() {
console.log("start");
console.time();
console.timeEnd()
console.exception()
console.assert()
console.clear()

View File

@ -278,8 +278,6 @@
@BINPATH@/components/toolkitsearch.manifest
@BINPATH@/components/nsSearchService.js
@BINPATH@/components/nsSearchSuggestions.js
@BINPATH@/components/nsTryToClose.manifest
@BINPATH@/components/nsTryToClose.js
@BINPATH@/components/passwordmgr.manifest
@BINPATH@/components/nsLoginInfo.js
@BINPATH@/components/nsLoginManager.js
@ -481,9 +479,7 @@
; svg
@BINPATH@/res/svg.css
@BINPATH@/components/dom_svg.xpt
#ifdef MOZ_SMIL
@BINPATH@/components/dom_smil.xpt
#endif
; [Personal Security Manager]
;

View File

@ -23,3 +23,8 @@ htmlPanel.tooltiptext=HTML panel
# toolbar button.
htmlPanel.accesskey=H
# LOCALIZATION NOTE (ruleView.*): Button label, accesskey and tooltip text
# associated with the Highlighter's CSS Rule View in the Style Sidebar.
ruleView.label=Rules
ruleView.accesskey=R
ruleView.tooltiptext=View and Edit CSS

View File

@ -3,10 +3,14 @@
- should be displayed or not. -->
<!ENTITY userStylesLabel "Only user styles">
<!-- LOCALIZATION NOTE (lookingAtLabel): This is the label for the path of
<!-- LOCALIZATION NOTE (userStylesSearch): This is the placeholder that goes in
- the search box when no search term has been entered. -->
<!ENTITY userStylesSearch "Search">
<!-- LOCALIZATION NOTE (selectedElementLabel): This is the label for the path of
- the highlighted element in the web page. This path is based on the document
- tree. -->
<!ENTITY lookingAtLabel "Looking at:">
<!ENTITY selectedElementLabel "Selected element:">
<!-- LOCALIZATION NOTE (helpLinkTitle): For each style property
- the user can hover it and get a help link button which allows one to
@ -14,12 +18,22 @@
- This is the link title shown in the hover tooltip. -->
<!ENTITY helpLinkTitle "Read the documentation for this property">
<!-- LOCALIZATION NOTE (matchedSelectors): For each style property the
- panel shows whether there are any selectors that match the currently
- selected element. -->
<!ENTITY matchedSelectors "Matched selectors">
<!-- LOCALIZATION NOTE (noPropertiesFound): In the case where there are no CSS
- properties to display e.g. due to search criteria this message is
- displayed. -->
<!ENTITY noPropertiesFound "No CSS properties found.">
<!-- LOCALIZATION NOTE (unmatchedSelectors): For each style property
- the panel shows whether there are any selectors that do not match the
- currently selected element. -->
<!ENTITY unmatchedSelectors "Unmatched selectors">
<!-- LOCALIZATION NOTE (bestMatch, matched, parentMatch & unmatched): For each
- style property the panel shows the rules which hold that specific property.
- For every rule, the rule status is also displayed: a rule can be the best
- match, a match, a parent match, or a rule did not match the element the
- user has highlighted. -->
<!ENTITY bestMatch "Best Match">
<!ENTITY matched "Matched">
<!ENTITY parentMatch "Parent Match">
<!ENTITY unmatched "Unmatched">

View File

@ -19,6 +19,12 @@ rule.status.UNMATCHED=Unmatched
rule.sourceInline=inline
rule.sourceElement=element
# LOCALIZATION NOTE (rule.inheritedSource): Shown for CSS rules
# that were inherited from a parent node. Will be passed a node
# identifier and a source location.
# e.g "Inherited from body#bodyID (styles.css:20)"
rule.inheritedSource=Inherited from %S (%S)
# LOCALIZATION NOTE (group): Style properties are displayed in categories and
# these are the category names.
group.Text_Fonts_and_Color=Text, Fonts & Color
@ -34,3 +40,4 @@ group.Effects_and_Other=Effects and Other
style.highlighter.button.label1=Properties
style.highlighter.accesskey1=P
style.highlighter.button.tooltip=Inspect element styles

View File

@ -172,3 +172,15 @@ stacktrace.anonymousFunction=<anonymous>
# to console.trace(). The stack trace of JavaScript function calls is displayed.
# In this minimal message we only show the last call.
stacktrace.outputMessage=Stack trace from %S, function %S, line %S.
# LOCALIZATION NOTE (timerStarted):
# This string is used to display the result of the console.time() call.
# %S=name of timer
timerStarted=%S: timer started
# LOCALIZATION NOTE (timeEnd):
# This string is used to display the result of the console.timeEnd() call.
# %1$S=name of timer, %2$S=number of milliseconds
timeEnd=%1$S: %2$Sms
maxTimersExceeded=The maximum allowed number of timers in this page was exceeded.

View File

@ -1904,6 +1904,16 @@ panel[dimmed="true"] {
#status-bar {
min-height: 0;
-moz-appearance: none;
background-color: transparent;
border: none;
}
#addon-bar[customizing] > #status-bar {
opacity: .5;
background-image: -moz-repeating-linear-gradient(-45deg,
rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
}
#status-bar > statusbarpanel {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 882 B

View File

@ -22,6 +22,7 @@
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@mozilla.com>
* Dão Gottwald <dao@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
@ -37,114 +38,135 @@
*
* ***** END LICENSE BLOCK ***** */
body {
font-family: sans-serif;
font-size: 11px;
background: #EEE;
:root {
-moz-appearance: none;
background: -moz-Field;
color: -moz-FieldText;
}
.path,
.filters {
#root {
display: -moz-box;
}
#path {
font-size: 11px;
word-spacing: -1px;
margin-bottom: 0;
color: -moz-dialogtext;
background-color: -moz-dialog;
padding: 4px 5px 0;
}
.path ol {
#path ol {
list-style: none outside none;
margin: 0;
padding: 0;
}
.path li {
#path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
#path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
#path li:last-child {
font-weight: bold;
color: #0091ff;
}
.path li:last-child:after {
color: red;
#path li:last-child:after {
content: "";
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
padding: 4px;
-moz-padding-start: 0;
-moz-padding-end: 5px;
}
.property-name,
.rule-matched,
.rule-unmatched {
cursor: pointer;
padding: 2px;
-moz-padding-start: 4px;
-moz-padding-end: 0;
white-space: nowrap;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link {
color: #55A;
}
.link,
.link:visited {
color: #55A;
color: #0091ff;
}
a.link {
text-decoration: none;
cursor: pointer;
}
a.link:visited {
.link,
.helplink,
.link:visited,
.helplink:visited {
text-decoration: none;
}
.rule-matched,
.rule-unmatched {
padding: 2px 0;
white-space: nowrap;
.helplink-container {
position: relative;
top: 2px;
}
.helplink {
display: block;
height: 14px;
width: 0;
overflow: hidden;
-moz-padding-start: 14px;
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
-moz-margin-end: 2px;
}
.property-header:not(:hover) > .helplink-container {
visibility: hidden;
}
.unmatchedSelectorTable {
-moz-margin-start: 15px;
}
.rulelink {
color: #55A;
color: -moz-dialogtext;
-moz-margin-start: 12px;
}
.expander {
width: 8px;
height: 8px;
float: left;
-moz-margin-start: 15px;
-moz-appearance: treetwisty;
-moz-margin-start: 10px;
-moz-margin-end: 5px;
margin-top: 3px;
background: url("chrome://browser/skin/devtools/arrows.png");
background-position: 24px 0;
}
.searchfield {
background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
border-radius: 5px;
-moz-padding-start: 20px;
width: 135px;
float: right;
}
.expander[dir="rtl"] {
background-position: 16px 0;
}
.expander[open] {
background-position: 8px 0;
-moz-appearance: treetwistyopen;
}
.expandable {
cursor: pointer;
}
.match {
visibility: hidden;
}
.expandable > .match {
visibility: visible;
}
.only-unmatched {
-moz-margin-start: 0;
}
.property-name {
display: inline-block;
font-size: 12px;
font-weight: bold;
color: #000;
color: -moz-FieldText;
width: 220px;
}
.property-value {
display: inline-block;
font-size: 10px;
color: grey;
}
.property-view-hidden {
@ -159,11 +181,7 @@ a.link:visited {
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
-moz-padding-start: 10px;
}
.resizerbox {
background-color: window;
-moz-padding-start: 15px;
}
.bestmatch {
@ -179,16 +197,68 @@ a.link:visited {
color: brown;
}
.userStyles {
position: relative;
top: 3px;
#propertyContainer {
display: -moz-box;
-moz-box-orient: vertical;
-moz-box-flex: 1;
overflow-y: auto;
}
.userStyles,
.selectedElementLabel {
font-weight: bold;
}
.darkrow {
background-color: rgba(0,0,0,.022);
}
#noResults {
font-size: 18px;
margin-top: 5px;
text-align: center;
}
.headerControls {
color: -moz-dialogtext;
background-color: -moz-dialog;
padding-top: 5px;
}
.onlyuserstyles,
.userStylesLabel {
cursor: pointer;
}
.userStylesLabel {
display: -moz-box;
white-space: nowrap;
}
.onlyuserstyles {
position: relative;
top: 3px;
font-family: sans-serif;
font-size: 11px;
}
.searchfield {
display: -moz-box;
-moz-box-flex: 1;
margin-left: 10px;
}
.styleinspector-legend {
-moz-margin-start: 12px;
}
#footer {
border-top: 1px solid -moz-dialog;
}
.legendKey {
margin: 0 5px;
}
/**
* CSS Rule View
*/
@ -229,7 +299,7 @@ a.link:visited {
-moz-margin-end: 5px;
}
.ruleview-expander[dir="rtl"] {
.ruleview-expander:-moz-locale-dir(rtl) {
background-position: 16px 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -79,12 +79,12 @@ browser.jar:
skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
skin/classic/browser/tabview/edit-light.png (tabview/edit-light.png)
skin/classic/browser/tabview/search.png (tabview/search.png)
skin/classic/browser/tabview/search.png (tabview/search.png)
skin/classic/browser/tabview/stack-expander.png (tabview/stack-expander.png)
skin/classic/browser/tabview/tabview.png (tabview/tabview.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/search.png (devtools/search.png)
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png)

View File

@ -2469,6 +2469,13 @@ panel[dimmed="true"] {
padding-right: 0;
}
#addon-bar[customizing] > #status-bar {
opacity: .5;
background-image: -moz-repeating-linear-gradient(-45deg,
rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
}
#status-bar > statusbarpanel {
border-width: 0;
-moz-appearance: none;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 882 B

View File

@ -22,6 +22,7 @@
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@mozilla.com>
* Dão Gottwald <dao@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
@ -37,114 +38,137 @@
*
* ***** END LICENSE BLOCK ***** */
body {
font-family: sans-serif;
font-size: 11px;
background: #EEE;
:root {
-moz-appearance: none;
background: -moz-Field;
color: -moz-FieldText;
}
.path,
.filters {
#root {
display: -moz-box;
}
#path {
font-size: 11px;
word-spacing: -1px;
margin-bottom: 0;
color: -moz-dialogtext;
background-color: -moz-dialog;
padding: 4px 5px 0;
}
.path ol {
#path ol {
list-style: none outside none;
margin: 0;
padding: 0;
}
.path li {
#path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
#path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
#path li:last-child {
font-weight: bold;
color: #0091ff;
}
.path li:last-child:after {
color: red;
#path li:last-child:after {
content: "";
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
padding: 4px;
-moz-padding-start: 0;
-moz-padding-end: 5px;
}
.property-name,
.rule-matched,
.rule-unmatched {
cursor: pointer;
padding: 2px;
-moz-padding-start: 4px;
-moz-padding-end: 0;
white-space: nowrap;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link {
color: #55A;
}
.link,
.link:visited {
color: #55A;
color: #0091ff;
}
a.link {
text-decoration: none;
cursor: pointer;
}
a.link:visited {
.link,
.helplink,
.link:visited,
.helplink:visited {
text-decoration: none;
}
.rule-matched,
.rule-unmatched {
padding: 2px 0;
white-space: nowrap;
.helplink-container {
position: relative;
top: 2px;
}
.helplink {
display: block;
height: 14px;
width: 0;
overflow: hidden;
-moz-padding-start: 14px;
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
-moz-margin-end: 2px;
}
.property-header:not(:hover) > .helplink-container {
visibility: hidden;
}
.unmatchedSelectorTable {
-moz-margin-start: 15px;
}
.rulelink {
color: #55A;
color: -moz-dialogtext;
-moz-margin-start: 12px;
}
.expander {
width: 8px;
height: 8px;
float: left;
-moz-margin-start: 15px;
-moz-appearance: treetwisty;
width: 12px;
height: 12px;
-moz-margin-start: 5px;
-moz-margin-end: 5px;
margin-top: 3px;
background: url("chrome://browser/skin/devtools/arrows.png");
background-position: 24px 0;
}
.searchfield {
background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
border-radius: 5px;
-moz-padding-start: 20px;
width: 135px;
float: right;
}
.expander[dir="rtl"] {
background-position: 16px 0;
}
.expander[open] {
background-position: 8px 0;
-moz-appearance: treetwistyopen;
}
.expandable {
cursor: pointer;
}
.match {
visibility: hidden;
}
.expandable > .match {
visibility: visible;
}
.only-unmatched {
-moz-margin-start: 0;
}
.property-name {
display: inline-block;
font-size: 12px;
font-weight: bold;
color: #000;
color: -moz-FieldText;
width: 220px;
}
.property-value {
display: inline-block;
font-size: 10px;
color: grey;
}
.property-view-hidden {
@ -159,11 +183,7 @@ a.link:visited {
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
-moz-padding-start: 10px;
}
.resizerbox {
background-color: window;
-moz-padding-start: 15px;
}
.bestmatch {
@ -179,16 +199,68 @@ a.link:visited {
color: brown;
}
.userStyles {
position: relative;
top: 3px;
#propertyContainer {
display: -moz-box;
-moz-box-orient: vertical;
-moz-box-flex: 1;
overflow-y: auto;
}
.userStyles,
.selectedElementLabel {
font-weight: bold;
}
.darkrow {
background-color: rgba(0,0,0,.022);
}
#noResults {
font-size: 18px;
margin-top: 5px;
text-align: center;
}
.headerControls {
color: -moz-dialogtext;
background-color: -moz-dialog;
padding-top: 5px;
}
.onlyuserstyles,
.userStylesLabel {
cursor: pointer;
}
.userStylesLabel {
display: -moz-box;
white-space: nowrap;
}
.onlyuserstyles {
position: relative;
top: 3px;
font-family: sans-serif;
font-size: 11px;
}
.searchfield {
display: -moz-box;
-moz-box-flex: 1;
margin-left: 10px;
}
.styleinspector-legend {
-moz-margin-start: 12px;
}
#footer {
border-top: 1px solid -moz-dialog;
}
.legendKey {
margin: 0 5px;
}
/**
* CSS Rule View
*/
@ -229,7 +301,7 @@ a.link:visited {
-moz-margin-end: 5px;
}
.ruleview-expander[dir="rtl"] {
.ruleview-expander:-moz-locale-dir(rtl) {
background-position: 16px 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -123,7 +123,7 @@ browser.jar:
skin/classic/browser/tabview/tabview.png (tabview/tabview.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/search.png (devtools/search.png)
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)

View File

@ -2568,6 +2568,13 @@ panel[dimmed="true"] {
min-height: 0;
}
#addon-bar[customizing] > #status-bar {
opacity: .5;
background-image: -moz-repeating-linear-gradient(-45deg,
rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
}
#status-bar > statusbarpanel {
border-width: 0;
-moz-appearance: none;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 882 B

View File

@ -22,6 +22,7 @@
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@mozilla.com>
* Dão Gottwald <dao@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
@ -37,114 +38,137 @@
*
* ***** END LICENSE BLOCK ***** */
body {
font-family: sans-serif;
font-size: 11px;
background: #EEE;
:root {
-moz-appearance: none;
background: -moz-Field;
color: -moz-FieldText;
}
.path,
.filters {
#root {
display: -moz-box;
}
#path {
font-size: 11px;
word-spacing: -1px;
margin-bottom: 0;
color: -moz-dialogtext;
background-color: -moz-dialog;
padding: 4px 5px 0;
}
.path ol {
#path ol {
list-style: none outside none;
margin: 0;
padding: 0;
}
.path li {
#path li {
border-radius: 3px;
padding: 2px 3px;
text-shadow: #FFF 0 1px 0;
font-weight: bold;
font-size: 11px;
background: -moz-linear-gradient(top, #F6F6FF, #E3E3FF);
display: inline-block;
}
.path li:after {
#path li:after {
content: " > ";
}
.path li:last-child {
background: -moz-linear-gradient(top, #FFC, #DD8);
#path li:last-child {
font-weight: bold;
color: #0091ff;
}
.path li:last-child:after {
color: red;
#path li:last-child:after {
content: "";
}
.property-header {
padding: 2px 5px;
background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
color: #666;
padding: 4px;
-moz-padding-start: 0;
-moz-padding-end: 5px;
}
.property-name,
.rule-matched,
.rule-unmatched {
cursor: pointer;
padding: 2px;
-moz-padding-start: 4px;
-moz-padding-end: 0;
white-space: nowrap;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link {
color: #55A;
}
.link,
.link:visited {
color: #55A;
color: #0091ff;
}
a.link {
text-decoration: none;
cursor: pointer;
}
a.link:visited {
.link,
.helplink,
.link:visited,
.helplink:visited {
text-decoration: none;
}
.rule-matched,
.rule-unmatched {
padding: 2px 0;
white-space: nowrap;
.helplink-container {
position: relative;
top: 2px;
}
.helplink {
display: block;
height: 14px;
width: 0;
overflow: hidden;
-moz-padding-start: 14px;
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
-moz-margin-end: 2px;
}
.property-header:not(:hover) > .helplink-container {
visibility: hidden;
}
.unmatchedSelectorTable {
-moz-margin-start: 15px;
}
.rulelink {
color: #55A;
color: -moz-dialogtext;
-moz-margin-start: 12px;
}
.expander {
width: 8px;
height: 8px;
float: left;
-moz-margin-start: 15px;
width: 9px;
height: 9px;
-moz-margin-start: 5px;
-moz-margin-end: 5px;
margin-top: 3px;
background: url("chrome://browser/skin/devtools/arrows.png");
background-position: 24px 0;
background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
}
.searchfield {
background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
border-radius: 5px;
-moz-padding-start: 20px;
width: 135px;
float: right;
}
.expander[dir="rtl"] {
background-position: 16px 0;
}
.expander[open] {
background-position: 8px 0;
background-image: url("chrome://global/skin/tree/twisty-open.png");
}
.expandable {
cursor: pointer;
}
.match {
visibility: hidden;
}
.expandable > .match {
visibility: visible;
}
.only-unmatched {
-moz-margin-start: 0;
}
.property-name {
display: inline-block;
font-size: 12px;
font-weight: bold;
color: #000;
color: -moz-FieldText;
width: 220px;
}
.property-value {
display: inline-block;
font-size: 10px;
color: grey;
}
.property-view-hidden {
@ -159,11 +183,7 @@ a.link:visited {
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
.rule-text {
direction: ltr;
-moz-padding-start: 10px;
}
.resizerbox {
background-color: window;
-moz-padding-start: 15px;
}
.bestmatch {
@ -179,16 +199,68 @@ a.link:visited {
color: brown;
}
.userStyles {
position: relative;
top: 3px;
#propertyContainer {
display: -moz-box;
-moz-box-orient: vertical;
-moz-box-flex: 1;
overflow-y: auto;
}
.userStyles,
.selectedElementLabel {
font-weight: bold;
}
.darkrow {
background-color: rgba(0,0,0,.022);
}
#noResults {
font-size: 18px;
margin-top: 5px;
text-align: center;
}
.headerControls {
color: -moz-dialogtext;
background-color: -moz-dialog;
padding-top: 5px;
}
.onlyuserstyles,
.userStylesLabel {
cursor: pointer;
}
.userStylesLabel {
display: -moz-box;
white-space: nowrap;
}
.onlyuserstyles {
position: relative;
top: 3px;
font-family: sans-serif;
font-size: 11px;
}
.searchfield {
display: -moz-box;
-moz-box-flex: 1;
margin-left: 10px;
}
.styleinspector-legend {
-moz-margin-start: 12px;
}
#footer {
border-top: 1px solid -moz-dialog;
}
.legendKey {
margin: 0 5px;
}
/**
* CSS Rule View
*/
@ -229,7 +301,7 @@ a.link:visited {
-moz-margin-end: 5px;
}
.ruleview-expander[dir="rtl"] {
.ruleview-expander:-moz-locale-dir(rtl) {
background-position: 16px 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -107,7 +107,7 @@ browser.jar:
skin/classic/browser/tabview/tabview-inverted.png (tabview/tabview-inverted.png)
skin/classic/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/browser/devtools/search.png (devtools/search.png)
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
@ -259,7 +259,7 @@ browser.jar:
skin/classic/aero/browser/tabview/tabview-inverted.png (tabview/tabview-inverted.png)
skin/classic/aero/browser/tabview/tabview.css (tabview/tabview.css)
skin/classic/aero/browser/devtools/arrows.png (devtools/arrows.png)
skin/classic/aero/browser/devtools/search.png (devtools/search.png)
skin/classic/aero/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/aero/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)

View File

@ -215,9 +215,13 @@ class PythonJob(Job):
print >>sys.stderr, e
return e.exitcode
except:
print >>sys.stderr, sys.exc_info()[1]
print >>sys.stderr, traceback.print_exc()
return -127
e = sys.exc_info()[1]
if isinstance(e, SystemExit) and (e.code == 0 or e.code == '0'):
pass # sys.exit(0) is not a failure
else:
print >>sys.stderr, e
print >>sys.stderr, traceback.print_exc()
return -127
finally:
os.environ = oldenv
return 0

View File

@ -0,0 +1,8 @@
#T gmake skip
CMD = %pycmd asplode
PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir
all:
$(CMD) 0
@echo TEST-PASS

View File

@ -1,4 +1,4 @@
import os
import os, sys
def writetofile(args):
with open(args[0], 'w') as f:
@ -7,3 +7,7 @@ def writetofile(args):
def writeenvtofile(args):
with open(args[0], 'w') as f:
f.write(os.environ[args[1]])
def asplode(args):
sys.exit(args[0])
return 0

View File

@ -253,7 +253,6 @@ MOZ_PERMISSIONS = @MOZ_PERMISSIONS@
MOZ_XTF = @MOZ_XTF@
MOZ_SVG_DLISTS = @MOZ_SVG_DLISTS@
MOZ_CAIRO_CFLAGS = @MOZ_CAIRO_CFLAGS@
MOZ_SMIL = @MOZ_SMIL@
MOZ_PREF_EXTENSIONS = @MOZ_PREF_EXTENSIONS@

View File

@ -805,11 +805,11 @@ ifneq (,$(SHARED_LIBRARY)$(PROGRAM))
export::
ifdef PROGRAM
$(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \
$(PROGRAM:$(BIN_SUFFIX)=) $(DIST)/$(MOZ_APP_NAME)
$(PROGRAM:$(BIN_SUFFIX)=) $(DIST)/bin
endif
ifdef SHARED_LIBRARY
$(PYTHON) $(topsrcdir)/build/win32/pgomerge.py \
$(SHARED_LIBRARY_NAME) $(DIST)/$(MOZ_APP_NAME)
$(SHARED_LIBRARY_NAME) $(DIST)/bin
endif
endif # SHARED_LIBRARY || PROGRAM
endif # WINNT_
@ -1469,7 +1469,7 @@ $(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
$(PYTHON_PATH) \
-I$(topsrcdir)/other-licenses/ply \
-I$(topsrcdir)/xpcom/idl-parser \
$(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(topsrcdir)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
$(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(DEPTH)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
@if test -n "$(findstring $*.h, $(EXPORTS))"; \
then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
@ -1482,7 +1482,7 @@ $(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
-I$(topsrcdir)/other-licenses/ply \
-I$(topsrcdir)/xpcom/idl-parser \
-I$(topsrcdir)/xpcom/typelib/xpt/tools \
$(topsrcdir)/xpcom/idl-parser/typelib.py --cachedir=$(topsrcdir)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
$(topsrcdir)/xpcom/idl-parser/typelib.py --cachedir=$(DEPTH)/xpcom/idl-parser $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
# no need to link together if XPIDLSRCS contains only XPIDL_MODULE
ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))

View File

@ -6190,18 +6190,6 @@ if test -n "$MOZ_SVG_DLISTS"; then
AC_DEFINE(MOZ_SVG_DLISTS)
fi
dnl ========================================================
dnl SMIL
dnl ========================================================
MOZ_SMIL=1
MOZ_ARG_DISABLE_BOOL(smil,
[ --disable-smil Disable SMIL animation support],
MOZ_SMIL=,
MOZ_SMIL=1 )
if test -n "$MOZ_SMIL"; then
AC_DEFINE(MOZ_SMIL)
fi
dnl ========================================================
dnl Build Freetype in the tree
dnl ========================================================
@ -8294,7 +8282,6 @@ AC_SUBST(MOZ_AUTH_EXTENSION)
AC_SUBST(MOZ_PERMISSIONS)
AC_SUBST(MOZ_XTF)
AC_SUBST(MOZ_PREF_EXTENSIONS)
AC_SUBST(MOZ_SMIL)
AC_SUBST(MOZ_JS_LIBS)
AC_SUBST(MOZ_PSM)
AC_SUBST(MOZ_DEBUG)

View File

@ -0,0 +1,16 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function boom() {
select = document.createElementNS("http://www.w3.org/1999/xhtml", "select");
text = document.body.childNodes[0];
select.setAttribute("onDOMSubtreeModified", "text.parentNode.removeChild(text);");
select.appendChild(text);
}
</script>
</head>
<body onload="boom()">
</body>
</html>

View File

@ -96,4 +96,5 @@ load 667336-1.html
load 679459.html
load 679689-1.html
load 682463.html
load 693212.xhtml
load 698974-1.html

View File

@ -57,10 +57,8 @@ class nsAttrName;
class nsTextFragment;
class nsIDocShell;
class nsIFrame;
#ifdef MOZ_SMIL
class nsISMILAttr;
class nsIDOMCSSStyleDeclaration;
#endif // MOZ_SMIL
namespace mozilla {
namespace css {
@ -891,7 +889,6 @@ public:
mPrimaryFrame = aFrame;
}
#ifdef MOZ_SMIL
/*
* Returns a new nsISMILAttr that allows the caller to animate the given
* attribute on this element.
@ -924,7 +921,6 @@ public:
*/
virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
bool aNotify) = 0;
#endif // MOZ_SMIL
nsresult LookupNamespaceURI(const nsAString& aNamespacePrefix,
nsAString& aNamespaceURI) const;

View File

@ -61,9 +61,7 @@
#include "nsGkAtoms.h"
#include "nsAutoPtr.h"
#include "nsPIDOMWindow.h"
#ifdef MOZ_SMIL
#include "nsSMILAnimationController.h"
#endif // MOZ_SMIL
#include "nsIScriptGlobalObject.h"
#include "nsIDocumentEncoder.h"
#include "nsIAnimationFrameListener.h"
@ -745,10 +743,10 @@ public:
virtual Element* GetFullScreenElement() = 0;
/**
* Requests that the document make aElement the full-screen element,
* and move into full-screen mode.
* Asynchronously requests that the document make aElement the full-screen
* element, and move into full-screen mode.
*/
virtual void RequestFullScreen(Element* aElement) = 0;
virtual void AsyncRequestFullScreen(Element* aElement) = 0;
/**
* Requests that the document, and all documents in its hierarchy exit
@ -1326,7 +1324,6 @@ public:
void EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
void* aData);
#ifdef MOZ_SMIL
// Indicates whether mAnimationController has been (lazily) initialized.
// If this returns true, we're promising that GetAnimationController()
// will have a non-null return value.
@ -1336,7 +1333,6 @@ public:
// initialization, if this document supports animation and if
// mAnimationController isn't yet initialized.
virtual nsSMILAnimationController* GetAnimationController() = 0;
#endif // MOZ_SMIL
// Makes the images on this document capable of having their animation
// active or suspended. An Image will animate as long as at least one of its
@ -1649,10 +1645,8 @@ protected:
// themselves when they go away.
nsAutoPtr<nsTHashtable<nsPtrHashKey<nsIContent> > > mFreezableElements;
#ifdef MOZ_SMIL
// SMIL Animation Controller, lazily-initialized in GetAnimationController
nsRefPtr<nsSMILAnimationController> mAnimationController;
#endif // MOZ_SMIL
// Table of element properties for this document.
nsPropertyTable mPropertyTable;

View File

@ -284,9 +284,7 @@ private:
// 0 is global.
#define DOM_USER_DATA 1
#define DOM_USER_DATA_HANDLER 2
#ifdef MOZ_SMIL
#define SMIL_MAPPED_ATTR_ANIMVAL 3
#endif // MOZ_SMIL
// IID for the nsINode interface
#define NS_INODE_IID \

View File

@ -185,11 +185,9 @@
#include "nsDOMNavigationTiming.h"
#include "nsEventStateManager.h"
#ifdef MOZ_SMIL
#include "nsSMILAnimationController.h"
#include "imgIContainer.h"
#include "nsSVGUtils.h"
#endif // MOZ_SMIL
#include "nsRefreshDriver.h"
@ -214,8 +212,13 @@ using namespace mozilla::dom;
typedef nsTArray<Link*> LinkArray;
// Reference to the document which requested DOM full-screen mode.
nsWeakPtr nsDocument::sFullScreenDoc = nsnull;
// Reference to the root document of the branch containing the document
// which requested DOM full-screen mode.
nsWeakPtr nsDocument::sFullScreenRootDoc = nsnull;
#ifdef PR_LOGGING
static PRLogModuleInfo* gDocumentLeakPRLog;
static PRLogModuleInfo* gCspPRLog;
@ -1586,11 +1589,9 @@ nsDocument::~nsDocument()
mStyleSheetSetList->Disconnect();
}
#ifdef MOZ_SMIL
if (mAnimationController) {
mAnimationController->Disconnect();
}
#endif // MOZ_SMIL
mParentDocument = nsnull;
@ -1873,12 +1874,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
cb.NoteXPCOMChild(tmp->mAnimationFrameListeners[i]);
}
#ifdef MOZ_SMIL
// Traverse animation components
if (tmp->mAnimationController) {
tmp->mAnimationController->Traverse(&cb);
}
#endif // MOZ_SMIL
if (tmp->mSubDocuments && tmp->mSubDocuments->ops) {
PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb);
@ -1950,11 +1949,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mIdentifierMap.Clear();
#ifdef MOZ_SMIL
if (tmp->mAnimationController) {
tmp->mAnimationController->Unlink();
}
#endif // MOZ_SMIL
tmp->mInUnlinkOrDeletion = false;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -3763,13 +3760,11 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
"Script global object must be an inner window!");
}
#endif
#ifdef MOZ_SMIL
NS_ABORT_IF_FALSE(aScriptGlobalObject || !mAnimationController ||
mAnimationController->IsPausedByType(
nsSMILTimeContainer::PAUSE_PAGEHIDE |
nsSMILTimeContainer::PAUSE_BEGIN),
"Clearing window pointer while animations are unpaused");
#endif // MOZ_SMIL
if (mScriptGlobalObject && !aScriptGlobalObject) {
// We're detaching from the window. We need to grab a pointer to
@ -5530,7 +5525,6 @@ nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
mExternalResourceMap.EnumerateResources(aCallback, aData);
}
#ifdef MOZ_SMIL
nsSMILAnimationController*
nsDocument::GetAnimationController()
{
@ -5565,7 +5559,6 @@ nsDocument::GetAnimationController()
return mAnimationController;
}
#endif // MOZ_SMIL
struct DirTable {
const char* mName;
@ -7274,11 +7267,9 @@ nsDocument::OnPageShow(bool aPersisted,
mIsShowing = true;
}
#ifdef MOZ_SMIL
if (mAnimationController) {
mAnimationController->OnPageShow();
}
#endif
if (aPersisted) {
SetImagesNeedAnimating(true);
@ -7301,6 +7292,21 @@ NotifyPageHide(nsIDocument* aDocument, void* aData)
return true;
}
static bool
SetFullScreenState(nsIDocument* aDoc, Element* aElement, bool aIsFullScreen);
static void
SetWindowFullScreen(nsIDocument* aDoc, bool aValue);
static bool
ResetFullScreen(nsIDocument* aDocument, void* aData) {
if (aDocument->IsFullScreenDoc()) {
::SetFullScreenState(aDocument, nsnull, false);
aDocument->EnumerateSubDocuments(ResetFullScreen, nsnull);
}
return true;
}
void
nsDocument::OnPageHide(bool aPersisted,
nsIDOMEventTarget* aDispatchStartTarget)
@ -7329,11 +7335,9 @@ nsDocument::OnPageHide(bool aPersisted,
mIsShowing = false;
}
#ifdef MOZ_SMIL
if (mAnimationController) {
mAnimationController->OnPageHide();
}
#endif
if (aPersisted) {
SetImagesNeedAnimating(false);
@ -7352,6 +7356,29 @@ nsDocument::OnPageHide(bool aPersisted,
EnumerateExternalResources(NotifyPageHide, &aPersisted);
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
if (IsFullScreenDoc()) {
// A full-screen doc has been hidden. We need to ensure we exit
// full-screen, i.e. remove full-screen state from all full-screen
// documents, and exit the top-level window from full-screen mode.
// Unfortunately by the time a doc is hidden, it has been removed
// from the doc tree, so we can't just call CancelFullScreen()...
// So firstly reset full-screen state in *this* document. OnPageHide()
// is called in every hidden document, so doing this ensures all hidden
// documents have their state reset.
::SetFullScreenState(this, nsnull, false);
// Next walk the document tree of still visible documents, and reset
// their full-screen state. We then move the top-level window out
// of full-screen mode.
nsCOMPtr<nsIDocument> fullScreenRoot(do_QueryReferent(sFullScreenRootDoc));
if (fullScreenRoot) {
fullScreenRoot->EnumerateSubDocuments(ResetFullScreen, nsnull);
SetWindowFullScreen(fullScreenRoot, false);
sFullScreenRootDoc = nsnull;
}
}
}
void
@ -8456,6 +8483,7 @@ nsDocument::CancelFullScreen()
doc = doc->GetParentDocument();
}
sFullScreenDoc = nsnull;
sFullScreenRootDoc = nsnull;
// Move the window out of full-screen mode.
SetWindowFullScreen(this, false);
@ -8500,18 +8528,66 @@ GetCommonAncestor(nsIDocument* aDoc1, nsIDocument* aDoc2)
return parent;
}
void
nsDocument::RequestFullScreen(Element* aElement)
// Returns the root document in a document hierarchy.
static nsIDocument*
GetRootDocument(nsIDocument* aDoc)
{
if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
if (aElement) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(aElement,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
}
if (!aDoc)
return nsnull;
nsIDocument* doc = aDoc;
while (doc->GetParentDocument()) {
doc = doc->GetParentDocument();
}
return doc;
}
class nsCallRequestFullScreen : public nsRunnable
{
public:
nsCallRequestFullScreen(Element* aElement)
: mElement(aElement),
mDoc(aElement->OwnerDoc()),
mWasCallerChrome(nsContentUtils::IsCallerChrome())
{
}
NS_IMETHOD Run()
{
nsDocument* doc = static_cast<nsDocument*>(mDoc.get());
doc->RequestFullScreen(mElement, mWasCallerChrome);
return NS_OK;
}
nsRefPtr<Element> mElement;
nsCOMPtr<nsIDocument> mDoc;
bool mWasCallerChrome;
};
void
nsDocument::AsyncRequestFullScreen(Element* aElement)
{
if (!aElement) {
return;
}
// Request full-screen asynchronously.
nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(aElement));
NS_DispatchToCurrentThread(event);
}
void
nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
{
if (!aElement ||
!aElement->IsInDoc() ||
aElement->OwnerDoc() != this ||
!IsFullScreenEnabled(aWasCallerChrome) ||
!GetWindow()) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
return;
}
@ -8538,6 +8614,10 @@ nsDocument::RequestFullScreen(Element* aElement)
SetWindowFullScreen(fullScreenDoc, false);
}
// Remember the root document, so that if a full-screen document is hidden
// we can reset full-screen state the remaining visible full-screen documents.
sFullScreenRootDoc = do_GetWeakReference(GetRootDocument(this));
// Set the full-screen element. This sets the full-screen style on the
// element, and the full-screen-ancestor styles on ancestors of the element
// in this document.
@ -8602,20 +8682,25 @@ NS_IMETHODIMP
nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
{
NS_ENSURE_ARG_POINTER(aFullScreen);
*aFullScreen = false;
*aFullScreen = IsFullScreenEnabled(nsContentUtils::IsCallerChrome());
return NS_OK;
}
if (nsContentUtils::IsCallerChrome() &&
nsContentUtils::IsFullScreenApiEnabled()) {
bool
nsDocument::IsFullScreenEnabled(bool aCallerIsChrome)
{
if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) {
// Chrome code can always use the full-screen API, provided it's not
// explicitly disabled.
*aFullScreen = true;
return NS_OK;
// explicitly disabled. Note IsCallerChrome() returns true when running
// in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
// nsRunnable!
return true;
}
if (!nsContentUtils::IsFullScreenApiEnabled() ||
nsContentUtils::HasPluginWithUncontrolledEventDispatch(this) ||
!IsVisible()) {
return NS_OK;
return false;
}
// Ensure that all ancestor <iframe> elements have the mozallowfullscreen
@ -8628,13 +8713,12 @@ nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
// The node requesting fullscreen, or one of its crossdoc ancestors,
// is an iframe which doesn't have the "mozalllowfullscreen" attribute.
// This request is not authorized by the parent document.
return NS_OK;
return false;
}
node = nsContentUtils::GetCrossDocParentNode(node);
} while (node);
*aFullScreen = true;
return NS_OK;
return true;
}
PRInt64

View File

@ -865,11 +865,9 @@ public:
nsTArray<nsCString> mFileDataUris;
#ifdef MOZ_SMIL
// Returns our (lazily-initialized) animation controller.
// If HasAnimationController is true, this is guaranteed to return non-null.
nsSMILAnimationController* GetAnimationController();
#endif // MOZ_SMIL
void SetImagesNeedAnimating(bool aAnimating);
@ -952,10 +950,16 @@ public:
virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
virtual Element* GetFullScreenElement();
virtual void RequestFullScreen(Element* aElement);
virtual void AsyncRequestFullScreen(Element* aElement);
virtual void CancelFullScreen();
virtual bool IsFullScreenDoc();
// This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
// to move document into full-screen mode if allowed. aWasCallerChrome
// should be true when nsIDocument::AsyncRequestFullScreen() was called
// by chrome code.
void RequestFullScreen(Element* aElement, bool aWasCallerChrome);
// Returns true if making this change results in a change in the full-screen
// state of this document.
bool SetFullScreenState(Element* aElement, bool aIsFullScreen);
@ -969,6 +973,13 @@ public:
protected:
friend class nsNodeUtils;
// Returns true if a request for DOM full-screen is currently enabled in
// this document. This returns true if there are no windowed plugins in this
// doc tree, and if the document is visible, and if the api is not
// disabled by pref. aIsCallerChrome must contain the return value of
// nsContentUtils::IsCallerChrome() from the context we're checking.
bool IsFullScreenEnabled(bool aIsCallerChrome);
/**
* Check that aId is not empty and log a message to the console
* service if it is.
@ -1083,6 +1094,13 @@ protected:
// of this document will also be full-screen.
static nsWeakPtr sFullScreenDoc;
// The root document of the doctree containing the document which requested
// full-screen. This root document will also be in full-screen state, as will
// all the descendents down to the document which requested full-screen. This
// reference allows us to reset full-screen state on all documents when a
// document is hidden/navigation occurs.
static nsWeakPtr sFullScreenRootDoc;
nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;

View File

@ -928,7 +928,6 @@ nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
return NS_OK;
}
#ifdef MOZ_SMIL
nsIDOMCSSStyleDeclaration*
nsGenericDOMDataNode::GetSMILOverrideStyle()
{
@ -948,7 +947,6 @@ nsGenericDOMDataNode::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
NS_NOTREACHED("How come we're setting SMILOverrideStyle on a non-element?");
return NS_ERROR_UNEXPECTED;
}
#endif // MOZ_SMIL
css::StyleRule*
nsGenericDOMDataNode::GetInlineStyleRule()

View File

@ -52,9 +52,7 @@
#include "nsCycleCollectionParticipant.h"
#include "nsDOMMemoryReporter.h"
#ifdef MOZ_SMIL
#include "nsISMILAttr.h"
#endif // MOZ_SMIL
// This bit is set to indicate that if the text node changes to
// non-whitespace, we may need to create a frame for it. This bit must
@ -228,7 +226,6 @@ public:
virtual void DestroyContent();
virtual void SaveSubtreeState();
#ifdef MOZ_SMIL
virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
{
return nsnull;
@ -237,7 +234,6 @@ public:
virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
bool aNotify);
#endif // MOZ_SMIL
#ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const;

View File

@ -2293,10 +2293,8 @@ nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, b
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
cb.NoteXPCOMChild(mStyle.get());
#ifdef MOZ_SMIL
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
cb.NoteXPCOMChild(mSMILOverrideStyle.get());
#endif // MOZ_SMIL
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
cb.NoteXPCOMChild(mAttributeMap.get());
@ -2314,9 +2312,7 @@ void
nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
{
mStyle = nsnull;
#ifdef MOZ_SMIL
mSMILOverrideStyle = nsnull;
#endif // MOZ_SMIL
if (mAttributeMap) {
mAttributeMap->DropReference();
mAttributeMap = nsnull;
@ -2456,13 +2452,11 @@ nsGenericElement::InternalIsSupported(nsISupports* aObject,
*aReturn = true;
}
}
#ifdef MOZ_SMIL
else if (NS_SMILEnabled() && PL_strcasecmp(f, "TimeControl") == 0) {
if (aVersion.IsEmpty() || PL_strcmp(v, "1.0") == 0) {
*aReturn = true;
}
}
#endif /* MOZ_SMIL */
return NS_OK;
}
@ -3355,7 +3349,6 @@ nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
return NS_OK;
}
#ifdef MOZ_SMIL
nsIDOMCSSStyleDeclaration*
nsGenericElement::GetSMILOverrideStyle()
{
@ -3398,7 +3391,6 @@ nsGenericElement::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
return NS_OK;
}
#endif // MOZ_SMIL
css::StyleRule*
nsGenericElement::GetInlineStyleRule()

View File

@ -67,9 +67,7 @@
#include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
#ifdef MOZ_SMIL
#include "nsISMILAttr.h"
#endif // MOZ_SMIL
class nsIDOMAttr;
class nsIDOMEventListener;
@ -349,7 +347,6 @@ public:
virtual void DestroyContent();
virtual void SaveSubtreeState();
#ifdef MOZ_SMIL
virtual nsISMILAttr* GetAnimatedAttr(PRInt32 /*aNamespaceID*/, nsIAtom* /*aName*/)
{
return nsnull;
@ -358,7 +355,6 @@ public:
virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
bool aNotify);
#endif // MOZ_SMIL
#ifdef DEBUG
virtual void List(FILE* out, PRInt32 aIndent) const

View File

@ -1368,7 +1368,6 @@ GK_ATOM(yChannelSelector, "yChannelSelector")
GK_ATOM(z, "z")
GK_ATOM(zoomAndPan, "zoomAndPan")
#ifdef MOZ_SMIL
GK_ATOM(accumulate, "accumulate")
GK_ATOM(additive, "additive")
GK_ATOM(attributeName, "attributeName")
@ -1395,7 +1394,6 @@ GK_ATOM(repeatEvent, "repeatEvent")
GK_ATOM(restart, "restart")
GK_ATOM(to, "to")
GK_ATOM(XML, "XML")
#endif
// internal MathML attributes: different from columnalign_, columnlines_,
// fontstyle_, rowalign_ and rowlines_

View File

@ -307,8 +307,6 @@ nsPlainTextSerializer::AppendText(nsIContent* aText,
NS_ENSURE_ARG(aText);
nsresult rv = NS_OK;
PRInt32 length = 0;
nsAutoString textstr;
nsIContent* content = aText;
const nsTextFragment* frag;
@ -319,16 +317,19 @@ nsPlainTextSerializer::AppendText(nsIContent* aText,
PRInt32 endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
length = endoffset - aStartOffset;
PRInt32 length = endoffset - aStartOffset;
if (length <= 0) {
return NS_OK;
}
nsAutoString textstr;
if (frag->Is2b()) {
textstr.Assign(frag->Get2b() + aStartOffset, length);
}
else {
textstr.AssignWithConversion(frag->Get1b()+aStartOffset, length);
// AssignASCII is for 7-bit character only, so don't use it
const char *data = frag->Get1b();
CopyASCIItoUTF16(Substring(data + aStartOffset, data + endoffset), textstr);
}
mOutputString = &aStr;

View File

@ -271,11 +271,7 @@ nsStyledElementNotElementCSSInlineStyle::GetStyle(nsresult* retval)
// Just in case...
ReparseStyleAttribute(true);
slots->mStyle = new nsDOMCSSAttributeDeclaration(this
#ifdef MOZ_SMIL
, false
#endif // MOZ_SMIL
);
slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
SetMayHaveStyle();
}

View File

@ -323,7 +323,6 @@ nsIAtom** const kURLAttributesHTML[] = {
};
nsIAtom** const kElementsSVG[] = {
#ifdef MOZ_SVG
&nsGkAtoms::a, // a
&nsGkAtoms::altGlyph, // altGlyph
&nsGkAtoms::altGlyphDef, // altGlyphDef
@ -407,39 +406,29 @@ nsIAtom** const kElementsSVG[] = {
&nsGkAtoms::use, // use
&nsGkAtoms::view, // view
&nsGkAtoms::vkern, // vkern
#endif
nsnull
};
nsIAtom** const kAttributesSVG[] = {
#ifdef MOZ_SVG
// accent-height
#ifdef MOZ_SMIL
&nsGkAtoms::accumulate, // accumulate
&nsGkAtoms::additive, // additive
#endif
&nsGkAtoms::alignment_baseline, // alignment-baseline
// alphabetic
&nsGkAtoms::amplitude, // amplitude
// arabic-form
// ascent
#ifdef MOZ_SMIL
&nsGkAtoms::attributeName, // attributeName
&nsGkAtoms::attributeType, // attributeType
#endif
&nsGkAtoms::azimuth, // azimuth
&nsGkAtoms::baseFrequency, // baseFrequency
&nsGkAtoms::baseline_shift, // baseline-shift
// baseProfile
// bbox
#ifdef MOZ_SMIL
&nsGkAtoms::begin, // begin
#endif
&nsGkAtoms::bias, // bias
#ifdef MOZ_SMIL
&nsGkAtoms::by, // by
&nsGkAtoms::calcMode, // calcMode
#endif
// cap-height
&nsGkAtoms::_class, // class
&nsGkAtoms::clip_path, // clip-path
@ -460,17 +449,13 @@ nsIAtom** const kAttributesSVG[] = {
&nsGkAtoms::display, // display
&nsGkAtoms::divisor, // divisor
&nsGkAtoms::dominant_baseline, // dominant-baseline
#ifdef MOZ_SMIL
&nsGkAtoms::dur, // dur
#endif
&nsGkAtoms::dx, // dx
&nsGkAtoms::dy, // dy
&nsGkAtoms::edgeMode, // edgeMode
&nsGkAtoms::elevation, // elevation
// enable-background
#ifdef MOZ_SMIL
&nsGkAtoms::end, // end
#endif
&nsGkAtoms::fill, // fill
&nsGkAtoms::fill_opacity, // fill-opacity
&nsGkAtoms::fill_rule, // fill-rule
@ -518,11 +503,9 @@ nsIAtom** const kAttributesSVG[] = {
&nsGkAtoms::kerning, // kerning
&nsGkAtoms::kernelMatrix, // kernelMatrix
&nsGkAtoms::kernelUnitLength, // kernelUnitLength
#ifdef MOZ_SMIL
&nsGkAtoms::keyPoints, // keyPoints
&nsGkAtoms::keySplines, // keySplines
&nsGkAtoms::keyTimes, // keyTimes
#endif
&nsGkAtoms::lang, // lang
// lengthAdjust
&nsGkAtoms::letter_spacing, // letter-spacing
@ -575,15 +558,11 @@ nsIAtom** const kAttributesSVG[] = {
&nsGkAtoms::radius, // radius
&nsGkAtoms::refX, // refX
&nsGkAtoms::refY, // refY
#ifdef MOZ_SMIL
&nsGkAtoms::repeatCount, // repeatCount
&nsGkAtoms::repeatDur, // repeatDur
#endif
&nsGkAtoms::requiredExtensions, // requiredExtensions
&nsGkAtoms::requiredFeatures, // requiredFeatures
#ifdef MOZ_SMIL
&nsGkAtoms::restart, // restart
#endif
&nsGkAtoms::result, // result
&nsGkAtoms::rotate, // rotate
&nsGkAtoms::rx, // rx
@ -625,9 +604,7 @@ nsIAtom** const kAttributesSVG[] = {
// textLength
&nsGkAtoms::text_rendering, // text-rendering
&nsGkAtoms::title, // title
#ifdef MOZ_SMIL
&nsGkAtoms::to, // to
#endif
&nsGkAtoms::transform, // transform
&nsGkAtoms::type, // type
// u1
@ -664,7 +641,6 @@ nsIAtom** const kAttributesSVG[] = {
&nsGkAtoms::yChannelSelector, // yChannelSelector
&nsGkAtoms::z, // z
&nsGkAtoms::zoomAndPan, // zoomAndPan
#endif
nsnull
};

View File

@ -648,7 +648,6 @@ NON_IDL_EVENT(zoom,
NS_SVG_ZOOM,
EventNameType_SVGSVG,
NS_EVENT_NULL)
#ifdef MOZ_SMIL
NON_IDL_EVENT(begin,
NS_SMIL_BEGIN,
EventNameType_SMIL,
@ -673,7 +672,6 @@ NON_IDL_EVENT(repeatEvent,
NS_SMIL_REPEAT,
EventNameType_None,
NS_SMIL_TIME_EVENT)
#endif // MOZ_SMIL
NON_IDL_EVENT(MozAudioAvailable,
NS_MOZAUDIOAVAILABLE,

View File

@ -105,10 +105,8 @@ nsresult
NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
nsresult
NS_NewDOMSVGZoomEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsGUIEvent* aEvent);
#ifdef MOZ_SMIL
nsresult
NS_NewDOMTimeEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
#endif // MOZ_SMIL
nsresult
NS_NewDOMXULCommandEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsInputEvent* aEvent);
nsresult

View File

@ -85,9 +85,7 @@ static const char* const sEventNames[] = {
"offline", "online", "copy", "cut", "paste", "open", "message", "show",
"SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
"SVGZoom",
#ifdef MOZ_SMIL
"beginEvent", "endEvent", "repeatEvent",
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
"loadstart", "progress", "suspend", "emptied", "stalled", "play", "pause",
"loadedmetadata", "loadeddata", "waiting", "playing", "canplay",
@ -422,6 +420,14 @@ nsDOMEvent::StopPropagation()
return NS_OK;
}
NS_IMETHODIMP
nsDOMEvent::StopImmediatePropagation()
{
mEvent->flags |=
(NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY | NS_EVENT_FLAG_STOP_DISPATCH);
return NS_OK;
}
static nsIDocument* GetDocumentForReport(nsEvent* aEvent)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aEvent->currentTarget);
@ -796,7 +802,6 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
newEvent->eventStructType = NS_SVGZOOM_EVENT;
break;
}
#ifdef MOZ_SMIL
case NS_SMIL_TIME_EVENT:
{
newEvent = new nsUIEvent(false, msg, 0);
@ -804,7 +809,6 @@ NS_METHOD nsDOMEvent::DuplicatePrivateData()
newEvent->eventStructType = NS_SMIL_TIME_EVENT;
break;
}
#endif // MOZ_SMIL
case NS_SIMPLE_GESTURE_EVENT:
{
nsSimpleGestureEvent* oldSimpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
@ -1287,14 +1291,12 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_SVGScroll];
case NS_SVG_ZOOM:
return sEventNames[eDOMEvents_SVGZoom];
#ifdef MOZ_SMIL
case NS_SMIL_BEGIN:
return sEventNames[eDOMEvents_beginEvent];
case NS_SMIL_END:
return sEventNames[eDOMEvents_endEvent];
case NS_SMIL_REPEAT:
return sEventNames[eDOMEvents_repeatEvent];
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
case NS_LOADSTART:
return sEventNames[eDOMEvents_loadstart];

View File

@ -149,11 +149,9 @@ public:
eDOMEvents_SVGResize,
eDOMEvents_SVGScroll,
eDOMEvents_SVGZoom,
#ifdef MOZ_SMIL
eDOMEvents_beginEvent,
eDOMEvents_endEvent,
eDOMEvents_repeatEvent,
#endif // MOZ_SMIL
#ifdef MOZ_MEDIA
eDOMEvents_loadstart,
eDOMEvents_progress,

View File

@ -376,9 +376,9 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
if (!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
// Dispatch to the system event group. Make sure to clear the
// STOP_DISPATCH flag since this resets for each event group
// per DOM3 Events.
aVisitor.mEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH;
// STOP_DISPATCH flag since this resets for each event group.
aVisitor.mEvent->flags &=
~(NS_EVENT_FLAG_STOP_DISPATCH | NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY);
// Setting back the original target of the event.
aVisitor.mEvent->target = aVisitor.mEvent->originalTarget;
@ -396,6 +396,11 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
aCallback,
createdELMs != nsEventListenerManager::sCreatedCount,
aPusher);
// After dispatch, clear all the propagation flags so that
// system group listeners don't affect to the event.
aVisitor.mEvent->flags &=
~(NS_EVENT_FLAG_STOP_DISPATCH | NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY);
}
return NS_OK;
@ -787,10 +792,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
case NS_SVGZOOM_EVENT:
return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext,
static_cast<nsGUIEvent*>(aEvent));
#ifdef MOZ_SMIL
case NS_SMIL_TIME_EVENT:
return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, aEvent);
#endif // MOZ_SMIL
case NS_COMMAND_EVENT:
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext,
@ -854,11 +857,9 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
return NS_NewDOMSVGZoomEvent(aDOMEvent, aPresContext, nsnull);
#ifdef MOZ_SMIL
if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
aEventType.LowerCaseEqualsLiteral("timeevents"))
return NS_NewDOMTimeEvent(aDOMEvent, aPresContext, nsnull);
#endif // MOZ_SMIL
if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
return NS_NewDOMXULCommandEvent(aDOMEvent, aPresContext, nsnull);

View File

@ -624,14 +624,12 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
attrName = nsGkAtoms::onscroll;
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGZoom)
attrName = nsGkAtoms::onzoom;
#ifdef MOZ_SMIL
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onbeginEvent)
attrName = nsGkAtoms::onbegin;
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onrepeatEvent)
attrName = nsGkAtoms::onrepeat;
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onendEvent)
attrName = nsGkAtoms::onend;
#endif // MOZ_SMIL
content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
body = &handlerBody;
@ -764,6 +762,9 @@ nsEventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
bool hasListener = false;
while (iter.HasMore()) {
if (aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY) {
break;
}
nsListenerStruct* ls = &iter.GetNext();
// Check that the phase is same in event and event listener.
// Handle only trusted events, except when listener permits untrusted events.

View File

@ -111,6 +111,7 @@ _TEST_FILES = \
test_bug667612.html \
empty.js \
test_bug689564.html \
test_bug698929.html \
$(NULL)
#bug 585630

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=698929
-->
<head>
<title>Test for Bug 698929</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=698929">Mozilla Bug 698929</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 698929 **/
var e = document.createEvent("Event");
e.initEvent("foo", true, true);
var c = 0;
var b = 0;
document.addEventListener("foo",
function() {
++c;
});
document.body.addEventListener("foo", function(e) {
++b;
e.stopImmediatePropagation();
});
document.body.addEventListener("foo", function(e) {
++b;
});
document.body.dispatchEvent(e);
document.documentElement.dispatchEvent(e);
is(c, 1, "Listener in the document should have been called once.");
is(b, 1, "Listener in the body should have been called once.");
</script>
</pre>
</body>
</html>

View File

@ -3404,11 +3404,9 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
// This stops the full-screen from being abused similar to the popups of old,
// and it also makes it harder for bad guys' script to go full-screen and
// spoof the browser chrome/window and phish logins etc.
nsIDocument* doc = OwnerDoc();
if (!nsContentUtils::IsRequestFullScreenAllowed() ||
!IsInDoc()) {
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
new nsPLDOMEvent(OwnerDoc(),
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
@ -3416,27 +3414,8 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
return NS_OK;
}
nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
NS_ENSURE_STATE(domDocument);
bool fullScreenEnabled;
domDocument->GetMozFullScreenEnabled(&fullScreenEnabled);
if (!fullScreenEnabled) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
return NS_OK;
}
OwnerDoc()->AsyncRequestFullScreen(this);
doc->RequestFullScreen(this);
#ifdef DEBUG
bool fullscreen;
domDocument->GetMozFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Document should report fullscreen");
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");
#endif
return NS_OK;
}

Some files were not shown because too many files have changed in this diff Show More