Merge m-c to s-c.

This commit is contained in:
Richard Newman 2012-03-09 22:04:29 -08:00
commit fffa436786
490 changed files with 11405 additions and 5304 deletions

View File

@ -43,7 +43,7 @@
interface nsIEditor;
[scriptable, uuid(52837507-202d-4e72-a482-5f068a1fd720)]
[scriptable, uuid(e242d495-5cde-4b1c-8c84-2525b14939f5)]
interface nsIAccessibleEditableText : nsISupports
{
/**
@ -103,19 +103,4 @@ interface nsIAccessibleEditableText : nsISupports
* clipboard into the text represented by this object.
*/
void pasteText (in long position);
/**
* Returns an editor associated with the accessible.
*/
[noscript] readonly attribute nsIEditor associatedEditor;
};
/*
Assumptions:
selectAttributes method takes an nsISupports parameter.
'set' methods throw exception on failure.
'wstring' inputs are potentially multibyte (UTF-16 for
instance); 'string' and UTF-8 may be a better choice.
*/

View File

@ -680,8 +680,7 @@ NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
// Don't fire event for the first html:br in an editor.
if (aEvent->mAccessible->Role() == roles::WHITESPACE) {
nsCOMPtr<nsIEditor> editor;
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = textAccessible->GetEditor();
if (editor) {
bool isEmpty = false;
editor->GetDocumentIsEmpty(&isEmpty);

View File

@ -214,6 +214,11 @@ public:
*/
virtual PRUint64 NativeState();
/**
* Return bit set of invisible and offscreen states.
*/
PRUint64 VisibilityState();
/**
* Returns attributes for accessible without explicitly setted ARIA
* attributes.
@ -702,8 +707,6 @@ protected:
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
PRUint64 VisibilityState();
//////////////////////////////////////////////////////////////////////////////
// Name helpers

View File

@ -333,8 +333,7 @@ nsDocAccessible::NativeState()
state |= states::INVISIBLE | states::OFFSCREEN;
}
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = GetEditor();
state |= editor ? states::EDITABLE : states::READONLY;
return state;
@ -553,37 +552,32 @@ nsDocAccessible::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
return NS_OK;
}
// nsIAccessibleHyperText method
NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
// nsHyperTextAccessible method
already_AddRefed<nsIEditor>
nsDocAccessible::GetEditor() const
{
NS_ENSURE_ARG_POINTER(aEditor);
*aEditor = nsnull;
if (IsDefunct())
return NS_ERROR_FAILURE;
// Check if document is editable (designMode="on" case). Otherwise check if
// the html:body (for HTML document case) or document element is editable.
if (!mDocument->HasFlag(NODE_IS_EDITABLE) &&
!mContent->HasFlag(NODE_IS_EDITABLE))
return NS_OK;
return nsnull;
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
if (!editingSession)
return NS_OK; // No editing session interface
return nsnull; // No editing session interface
nsCOMPtr<nsIEditor> editor;
editingSession->GetEditorForWindow(mDocument->GetWindow(), getter_AddRefs(editor));
if (!editor) {
return NS_OK;
}
bool isEditable;
if (!editor)
return nsnull;
bool isEditable = false;
editor->GetIsDocumentEditable(&isEditable);
if (isEditable) {
NS_ADDREF(*aEditor = editor);
}
return NS_OK;
if (isEditable)
return editor.forget();
return nsnull;
}
// nsDocAccessible public method

View File

@ -133,8 +133,8 @@ public:
virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
#endif
// nsIAccessibleText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
// nsHyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// nsDocAccessible

View File

@ -544,11 +544,12 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible::DoAction(PRUint8 index)
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
already_AddRefed<nsIEditor>
nsHTMLTextFieldAccessible::GetEditor() const
{
*aEditor = nsnull;
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
if (!editableElt)
return nsnull;
// nsGenericHTMLElement::GetEditor has a security check.
// Make sure we're not restricted by the permissions of
@ -558,7 +559,7 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor
bool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
nsCOMPtr<nsIEditor> editor;
nsresult rv = editableElt->GetEditor(aEditor);
editableElt->GetEditor(getter_AddRefs(editor));
if (pushed) {
JSContext* cx;
@ -566,7 +567,7 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor
NS_ASSERTION(!cx, "context should be null");
}
return rv;
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -138,8 +138,8 @@ public:
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
// nsIAccessibleEditableText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
// nsHyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// nsAccessible
virtual void ApplyARIAState(PRUint64* aState);

View File

@ -166,8 +166,7 @@ nsHyperTextAccessible::NativeState()
{
PRUint64 states = nsAccessibleWrap::NativeState();
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = GetEditor();
if (editor) {
PRUint32 flags;
editor->GetFlags(&flags);
@ -711,8 +710,7 @@ nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
// If the given offsets are 0 and associated editor is empty then return
// collapsed range with editor root element as range container.
if (aStartHTOffset == 0 && aEndHTOffset == 0) {
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = GetEditor();
if (editor) {
bool isEmpty = false;
editor->GetDocumentIsEmpty(&isEmpty);
@ -1455,8 +1453,10 @@ NS_IMETHODIMP nsHyperTextAccessible::SetTextContents(const nsAString &aText)
NS_IMETHODIMP
nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
{
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditor> editor = GetEditor();
nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
NS_ENSURE_STATE(peditor);
@ -1470,8 +1470,10 @@ nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
NS_IMETHODIMP
nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
{
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditor> editor = GetEditor();
NS_ENSURE_STATE(editor);
nsresult rv = SetSelectionRange(aStartPos, aEndPos);
@ -1483,8 +1485,10 @@ nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
NS_IMETHODIMP
nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
{
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditor> editor = GetEditor();
NS_ENSURE_STATE(editor);
nsresult rv = SetSelectionRange(aStartPos, aEndPos);
@ -1496,8 +1500,10 @@ nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
NS_IMETHODIMP
nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
{
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditor> editor = GetEditor();
NS_ENSURE_STATE(editor);
nsresult rv = SetSelectionRange(aStartPos, aEndPos);
@ -1509,8 +1515,10 @@ nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
NS_IMETHODIMP
nsHyperTextAccessible::PasteText(PRInt32 aPosition)
{
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditor> editor = GetEditor();
NS_ENSURE_STATE(editor);
nsresult rv = SetSelectionRange(aPosition, aPosition);
@ -1519,44 +1527,37 @@ nsHyperTextAccessible::PasteText(PRInt32 aPosition)
return editor->Paste(nsIClipboard::kGlobalClipboard);
}
NS_IMETHODIMP
nsHyperTextAccessible::GetAssociatedEditor(nsIEditor **aEditor)
already_AddRefed<nsIEditor>
nsHyperTextAccessible::GetEditor() const
{
NS_ENSURE_ARG_POINTER(aEditor);
*aEditor = nsnull;
if (IsDefunct())
return NS_ERROR_FAILURE;
if (!mContent->HasFlag(NODE_IS_EDITABLE)) {
// If we're inside an editable container, then return that container's editor
nsCOMPtr<nsIAccessible> ancestor, current = this;
while (NS_SUCCEEDED(current->GetParent(getter_AddRefs(ancestor))) && ancestor) {
nsRefPtr<nsHyperTextAccessible> ancestorTextAccessible;
ancestor->QueryInterface(NS_GET_IID(nsHyperTextAccessible),
getter_AddRefs(ancestorTextAccessible));
if (ancestorTextAccessible) {
nsAccessible* ancestor = Parent();
while (ancestor) {
nsHyperTextAccessible* hyperText = ancestor->AsHyperText();
if (hyperText) {
// Recursion will stop at container doc because it has its own impl
// of GetAssociatedEditor()
return ancestorTextAccessible->GetAssociatedEditor(aEditor);
// of GetEditor()
return hyperText->GetEditor();
}
current = ancestor;
ancestor = ancestor->Parent();
}
return NS_OK;
return nsnull;
}
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
nsCoreUtils::GetDocShellTreeItemFor(mContent);
nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
if (!editingSession)
return NS_OK; // No editing session interface
NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
nsIDocument* docNode = mDoc->GetDocumentNode();
NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
return nsnull; // No editing session interface
nsCOMPtr<nsIEditor> editor;
return editingSession->GetEditorForWindow(docNode->GetWindow(), aEditor);
nsIDocument* docNode = mDoc->GetDocumentNode();
editingSession->GetEditorForWindow(docNode->GetWindow(),
getter_AddRefs(editor));
return editor.forget();
}
/**
@ -1770,8 +1771,7 @@ nsHyperTextAccessible::GetSelectionDOMRanges(PRInt16 aType,
nsCOMPtr<nsINode> startNode = GetNode();
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = GetEditor();
if (editor) {
nsCOMPtr<nsIDOMElement> editorRoot;
editor->GetRootElement(getter_AddRefs(editorRoot));

View File

@ -264,6 +264,14 @@ public:
return GetChildAt(GetChildIndexAtOffset(aOffset));
}
//////////////////////////////////////////////////////////////////////////////
// EditableTextAccessible
/**
* Return the editor associated with the accessible.
*/
virtual already_AddRefed<nsIEditor> GetEditor() const;
protected:
// nsHyperTextAccessible

View File

@ -273,8 +273,7 @@ nsXFormsEditableAccessible::NativeState()
}
}
nsCOMPtr<nsIEditor> editor;
GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIEditor> editor = GetEditor();
NS_ENSURE_TRUE(editor, state);
PRUint32 flags;
editor->GetFlags(&flags);
@ -286,11 +285,14 @@ nsXFormsEditableAccessible::NativeState()
return state;
}
NS_IMETHODIMP
nsXFormsEditableAccessible::GetAssociatedEditor(nsIEditor **aEditor)
already_AddRefed<nsIEditor>
nsXFormsEditableAccessible::GetEditor() const
{
nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
return sXFormsService->GetEditor(DOMNode, aEditor);
nsCOMPtr<nsIEditor> editor;
sXFormsService->GetEditor(DOMNode, getter_AddRefs(editor));
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -144,8 +144,8 @@ class nsXFormsEditableAccessible : public nsXFormsAccessible
public:
nsXFormsEditableAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
// nsIAccessibleEditableText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
// nsHyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// nsAccessible
virtual PRUint64 NativeState();

View File

@ -850,14 +850,17 @@ nsXULTextFieldAccessible::CanHaveAnonChildren()
return false;
}
NS_IMETHODIMP nsXULTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
already_AddRefed<nsIEditor>
nsXULTextFieldAccessible::GetEditor() const
{
*aEditor = nsnull;
nsCOMPtr<nsIContent> inputField = GetInputField();
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
return editableElt->GetEditor(aEditor);
if (!editableElt)
return nsnull;
nsCOMPtr<nsIEditor> editor;
editableElt->GetEditor(getter_AddRefs(editor));
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -260,8 +260,8 @@ public:
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
// nsIAccessibleEditableText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
// nsHyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// nsAccessible
virtual void ApplyARIAState(PRUint64* aState);

View File

@ -613,9 +613,9 @@ function getNodePrettyName(aNode)
function getObjAddress(aObj)
{
var exp = /native\s*@\s*(0x[a-f0-9]+)/g;
var match = exp.exec(aObj.valueOf());
var match = exp.exec(aObj.toString());
if (match)
return match[1];
return aObj.valueOf();
return aObj.toString();
}

View File

@ -304,12 +304,20 @@ function eventQueue(aEventType)
// Start processing of next invoker.
invoker = this.getNextInvoker();
this.setEventHandler(invoker);
if (gLogger.isEnabled()) {
gLogger.logToConsole("Event queue: \n invoke: " + invoker.getID());
gLogger.logToDOM("EQ: invoke: " + invoker.getID(), true);
}
this.setEventHandler(invoker);
var infoText = "Invoke the '" + invoker.getID() + "' test { ";
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
infoText += this.isEventUnexpected(idx) ? "un" : "";
infoText += "expected '" + this.getEventTypeAsString(idx) + "' event; ";
}
infoText += " }";
info(infoText);
if (invoker.invoke() == INVOKER_ACTION_FAILED) {
// Invoker failed to prepare action, fail and finish tests.

1
aclocal.m4 vendored
View File

@ -18,6 +18,7 @@ builtin(include, build/autoconf/lto.m4)dnl
builtin(include, build/autoconf/gcc-pr49911.m4)dnl
builtin(include, build/autoconf/frameptr.m4)dnl
builtin(include, build/autoconf/compiler-opts.m4)dnl
builtin(include, build/autoconf/expandlibs.m4)dnl
MOZ_PROG_CHECKMSYS()

View File

@ -46,7 +46,7 @@ pref("browser.homescreenURL", "file:///data/local/homescreen.html,file:///system
#endif
// URL for the dialer application.
pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html");
pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html http://localhost:7777/data/local/apps/homescreen/homescreen.html http://localhost:7777/apps/dialer/dialer.html http://localhost:7777/apps/homescreen/homescreen.html");
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
pref("browser.viewport.scaleRatio", -1);

View File

@ -66,7 +66,7 @@ pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%");
pref("extensions.getAddons.getWithPerformance.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%&platform=%OS%&appver=%VERSION%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=firefox");
pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");
@ -214,6 +214,7 @@ pref("app.update.service.enabled", true);
//
pref("extensions.update.enabled", true);
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
pref("extensions.update.interval", 86400); // Check for updates to Extensions and
// Themes every day
// Non-symmetric (not shared by extensions) extension-specific [update] preferences
@ -1041,6 +1042,9 @@ pref("devtools.debugger.enabled", false);
// The default Debugger UI height
pref("devtools.debugger.ui.height", 250);
// Disable remote debugging protocol logging
pref("devtools.debugger.log", false);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);

View File

@ -40,10 +40,12 @@ let gDropTargetShim = {
* @param aEvent The 'dragstart' event.
*/
_start: function DropTargetShim_start(aEvent) {
if (aEvent.target.classList.contains("site")) {
gGrid.lock();
// XXX bug 505521 - Listen for dragover on the document.
document.documentElement.addEventListener("dragover", this._dragover, false);
}
},
/**

View File

@ -850,7 +850,7 @@ nsContextMenu.prototype = {
let uri = makeURI(this.mediaURL);
let url = uri.QueryInterface(Ci.nsIURL);
if (url.fileBaseName)
name = url.fileBaseName + ".jpg";
name = decodeURI(url.fileBaseName) + ".jpg";
} catch (e) { }
if (!name)
name = "snapshot.jpg";

View File

@ -20,7 +20,9 @@ _BROWSER_FILES = \
browser_newtab_reset.js \
browser_newtab_tabsync.js \
browser_newtab_unpin.js \
browser_newtab_bug722273.js \
browser_newtab_bug723102.js \
browser_newtab_bug723121.js \
head.js \
$(NULL)

View File

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const NOW = Date.now() * 1000;
const URL = "http://fake-site.com/";
let tmp = {};
Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
let {NewTabUtils, Sanitizer} = tmp;
let bhist = Cc["@mozilla.org/browser/global-history;2"]
.getService(Ci.nsIBrowserHistory);
function runTests() {
clearHistory();
fillHistory();
yield addNewTabPageTab();
is(cells[0].site.url, URL, "first site is our fake site");
let page = {
update: function () {
executeSoon(TestRunner.next);
},
observe: function () {}
};
NewTabUtils.allPages.register(page);
yield clearHistory();
NewTabUtils.allPages.unregister(page);
ok(!cells[0].site, "the fake site is gone");
}
function fillHistory() {
let uri = makeURI(URL);
for (let i = 59; i > 0; i--)
bhist.addPageWithDetails(uri, "fake site", NOW - i * 60 * 1000000);
}
function clearHistory() {
let s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
let prefs = gPrefService.getBranch(s.prefDomain);
prefs.setBoolPref("history", true);
prefs.setBoolPref("downloads", false);
prefs.setBoolPref("cache", false);
prefs.setBoolPref("cookies", false);
prefs.setBoolPref("formdata", false);
prefs.setBoolPref("offlineApps", false);
prefs.setBoolPref("passwords", false);
prefs.setBoolPref("sessions", false);
prefs.setBoolPref("siteSettings", false);
s.sanitize();
}

View File

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
checkGridLocked(false, "grid is unlocked");
let cell = cells[0].node;
let site = cells[0].site.node;
sendDragEvent(site, "dragstart");
checkGridLocked(true, "grid is now locked");
sendDragEvent(site, "dragend");
checkGridLocked(false, "grid isn't locked anymore");
sendDragEvent(cell, "dragstart");
checkGridLocked(false, "grid isn't locked - dragstart was ignored");
}
function checkGridLocked(aLocked, aMessage) {
is(cw.gGrid.node.hasAttribute("locked"), aLocked, aMessage);
}
function sendDragEvent(aNode, aType) {
let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
let dataTransfer = {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () "about:blank"
};
let event = cw.document.createEvent("DragEvents");
event.initDragEvent(aType, true, true, cw, 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
}

View File

@ -129,10 +129,11 @@ function addNewTabPageTab() {
cw = browser.contentWindow;
if (NewTabUtils.allPages.enabled) {
cells = cw.gGrid.cells;
// Continue when the link cache has been populated.
NewTabUtils.links.populateCache(TestRunner.next);
NewTabUtils.links.populateCache(function () {
cells = cw.gGrid.cells;
executeSoon(TestRunner.next);
});
} else {
TestRunner.next();
}
@ -246,6 +247,8 @@ function unpinCell(aCell) {
*/
function simulateDrop(aDropTarget, aDragSource) {
let event = {
clientX: 0,
clientY: 0,
dataTransfer: {
mozUserCancelled: false,
setData: function () null,

View File

@ -47,20 +47,6 @@
white-space: pre-wrap;
}
#technicalContent > h2, #expertContent > h2 {
cursor: pointer;
-moz-padding-start: 20px;
position: relative;
left: -20px;
}
body[dir="rtl"] #technicalContent > h2,
body[dir="rtl"] #expertContent > h2 {
left: auto;
right: -20px;
}
div[collapsed] > p,
div[collapsed] > div {
.expander[collapsed] + * {
display: none;
}

View File

@ -260,13 +260,14 @@
<!-- The following sections can be unhidden by default by setting the
"browser.xul.error_pages.expert_bad_cert" pref to true -->
<div id="technicalContent" collapsed="true">
<h2 onclick="toggle('technicalContent');" id="technicalContentHeading">&certerror.technical.heading;</h2>
<h2 id="technicalContent" class="expander" collapsed="true">
<button onclick="toggle('technicalContent');">&certerror.technical.heading;</button>
</h2>
<p id="technicalContentText"/>
</div>
<div id="expertContent" collapsed="true">
<h2 onclick="toggle('expertContent');" id="expertContentHeading">&certerror.expert.heading;</h2>
<h2 id="expertContent" class="expander" collapsed="true">
<button onclick="toggle('expertContent');">&certerror.expert.heading;</button>
</h2>
<div>
<p>&certerror.expert.content;</p>
<p>&certerror.expert.contentPara2;</p>
@ -274,7 +275,6 @@
</div>
</div>
</div>
</div>
<!--
- Note: It is important to run the script this way, instead of using

View File

@ -56,6 +56,7 @@
#include "nsServiceManagerUtils.h"
#include "nsStringAPI.h"
#include "nsXULAppAPI.h"
#include "nsIPrefLocalizedString.h"
namespace mozilla {
namespace browser {
@ -200,7 +201,18 @@ AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
nsCString locale;
nsCOMPtr<nsIPrefLocalizedString> prefString;
rv = prefs->GetComplexValue("general.useragent.locale",
NS_GET_IID(nsIPrefLocalizedString),
getter_AddRefs(prefString));
if (NS_SUCCEEDED(rv)) {
nsAutoString wLocale;
prefString->GetData(getter_Copies(wLocale));
CopyUTF16toUTF8(wLocale, locale);
} else {
rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
}
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> curLocalePlugins;

View File

@ -43,6 +43,8 @@ include $(DEPTH)/config/autoconf.mk
DIRS = public src
TEST_DIRS += tests
include $(topsrcdir)/config/rules.mk
# Needed for preprocessor removal of IE Profile Migrator label - bug 236901

View File

@ -65,6 +65,7 @@ var MigrationWizard = {
this._source = window.arguments[0];
this._migrator = window.arguments[1].QueryInterface(kIMig);
this._autoMigrate = window.arguments[2].QueryInterface(kIPStartup);
this._skipImportSourcePage = window.arguments[3];
if (this._autoMigrate) {
// Show the "nothing" option in the automigrate case to provide an
@ -94,7 +95,7 @@ var MigrationWizard = {
// Reference to the "From File" radio button
var fromfile = null;
//XXXquark This function is called before init, so check for bookmarks here
// init is not called when openDialog opens the wizard, so check for bookmarks here.
if ("arguments" in window && window.arguments[0] == "bookmarks") {
this._bookmarks = true;
@ -151,6 +152,12 @@ var MigrationWizard = {
document.getElementById("importBookmarks").hidden = true;
document.getElementById("importAll").hidden = true;
}
// Advance to the next page if the caller told us to.
if (this._migrator && this._skipImportSourcePage) {
this._wiz.advance();
this._wiz.canRewind = false;
}
},
onImportSourcePageAdvanced: function ()

View File

@ -227,6 +227,12 @@ FirefoxProfileMigrator.prototype = {
this._replaceBookmarks = true;
}
// Ensure that aProfile is not the current profile.
if (this._paths.currentProfile.path === this._sourceProfile.path) {
throw new Exception("Source and destination profiles are the same");
return;
}
Services.obs.notifyObservers(null, "Migration:Started", null);
// Reset pending count. If this count becomes 0, "Migration:Ended"
@ -278,6 +284,11 @@ FirefoxProfileMigrator.prototype = {
this._sourceProfile.initWithPath(aProfile);
let result = 0;
// Ensure that aProfile is not the current profile.
if (this._paths.currentProfile.path === this._sourceProfile.path)
return result;
if (!this._sourceProfile.exists() || !this._sourceProfile.isReadable()) {
Cu.reportError("source profile directory doesn't exist or is not readable");
return result;

View File

@ -16,10 +16,25 @@ function ProfileMigrator() {
}
ProfileMigrator.prototype = {
migrate: function PM_migrate(aStartup) {
migrate: function PM_migrate(aStartup, aKey) {
// By opening the wizard with a supplied migrator, it will automatically
// migrate from it.
let [key, migrator] = this._getDefaultMigrator();
let key = null, migrator = null;
let skipImportSourcePage = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
if (aKey) {
key = aKey;
migrator = this._getMigratorIfSourceExists(key);
if (!migrator) {
Cu.reportError("Invalid migrator key specified or source does not exist.");
return;
}
// If the migrator was passed to us from the caller, use that migrator
// and skip the import source page.
skipImportSourcePage.data = true;
} else {
[key, migrator] = this._getDefaultMigrator();
}
if (!key)
return;
@ -27,6 +42,7 @@ ProfileMigrator.prototype = {
params.appendElement(this._toCString(key), false);
params.appendElement(migrator, false);
params.appendElement(aStartup, false);
params.appendElement(skipImportSourcePage, false);
Services.ww.openWindow(null,
"chrome://browser/content/migration/migration.xul",
@ -43,10 +59,14 @@ ProfileMigrator.prototype = {
},
_getMigratorIfSourceExists: function PM__getMigratorIfSourceExists(aKey) {
try {
let cid = "@mozilla.org/profile/migrator;1?app=browser&type=" + aKey;
let migrator = Cc[cid].createInstance(Ci.nsIBrowserProfileMigrator);
if (migrator.sourceExists)
return migrator;
} catch (ex) {
Cu.reportError("Could not get migrator: " + ex);
}
return null;
},

View File

@ -1412,6 +1412,9 @@ nsIEProfileMigrator::CopyFavoritesBatched(bool aReplace)
// Locate the Links toolbar folder, we want to replace the Personal Toolbar
// content with Favorites in this folder.
// On versions minor or equal to IE6 the folder name is stored in the
// LinksFolderName registry key, but in newer versions it may be just a
// Links subfolder inside the default Favorites folder.
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (regKey &&
@ -1421,9 +1424,14 @@ nsIEProfileMigrator::CopyFavoritesBatched(bool aReplace)
nsAutoString linksFolderName;
if (NS_SUCCEEDED(regKey->ReadStringValue(
NS_LITERAL_STRING("LinksFolderName"),
linksFolderName)))
linksFolderName))) {
personalToolbarFolderName = linksFolderName;
}
else {
personalToolbarFolderName.AssignLiteral("Links");
}
}
folder = bookmarksMenuFolderId;
}

View File

@ -0,0 +1,15 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/components/migration/tests
include $(DEPTH)/config/autoconf.mk
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,16 @@
<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
It will be read and overwritten.
DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks Menu</H1>
<DL><p>
<DT><A HREF="http://example.com/" ADD_DATE="1233157972" LAST_MODIFIED="1233157984">example</A>
<DT><H3 ADD_DATE="1233157910" LAST_MODIFIED="1233157972" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3>
<DD>Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
<DL><p>
<DT><A HREF="http://example.com/" ADD_DATE="1233157972" LAST_MODIFIED="1233157984">example</A>
</DL><p>
</DL><p>

View File

@ -0,0 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const IMIGRATOR = Ci.nsIBrowserProfileMigrator;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
// Initialize profile.
let gProfD = do_get_profile();
function newMigratorFor(aKey) {
let cid = "@mozilla.org/profile/migrator;1?app=browser&type=" + aKey;
return Cc[cid].createInstance(Ci.nsIBrowserProfileMigrator);
}
let (bookmarkshtml = do_get_file("bookmarks.html")) {
bookmarkshtml.copyTo(gProfD, "bookmarks.html");
}

View File

@ -0,0 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function run_test() {
let migrator = newMigratorFor("ie");
// Sanity check for the source.
do_check_true(migrator.sourceExists);
// Ensure bookmarks migration is available.
let availableSources = migrator.getMigrateData("FieldOfFlowers", false);
do_check_true((availableSources & IMIGRATOR.BOOKMARKS) > 0);
// Needed to enforce bookmarks replacing.
let startup = {
doStartup: function () {},
get directory() do_get_profile()
}
migrator.migrate(IMIGRATOR.BOOKMARKS, startup, "FieldOfFlowers");
// Check that at least two bookmark have been added to the menu and the
// toolbar. The first one comes from bookmarks.html, the others from IE.
do_check_true(PlacesUtils.bookmarks
.getIdForItemAt(PlacesUtils.bookmarksMenuFolderId, 1) > 0);
do_check_true(PlacesUtils.bookmarks
.getIdForItemAt(PlacesUtils.toolbarFolderId, 1) > 0);
}

View File

@ -0,0 +1,6 @@
[DEFAULT]
head = head_migration.js
tail =
[test_IE_bookmarks.js]
skip-if = os != "win"

View File

@ -411,18 +411,20 @@ BrowserGlue.prototype = {
// For any add-ons that were installed disabled and can be enabled offer
// them to the user
var changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED);
if (changedIDs.length > 0) {
AddonManager.getAddonsByIDs(changedIDs, function(aAddons) {
var win = this.getMostRecentBrowserWindow();
var browser = win.gBrowser;
var changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED);
AddonManager.getAddonsByIDs(changedIDs, function(aAddons) {
aAddons.forEach(function(aAddon) {
// If the add-on isn't user disabled or can't be enabled then skip it
// If the add-on isn't user disabled or can't be enabled then skip it.
if (!aAddon.userDisabled || !(aAddon.permissions & AddonManager.PERM_CAN_ENABLE))
return;
browser.selectedTab = browser.addTab("about:newaddon?id=" + aAddon.id);
})
});
}
let keywordURLUserSet = Services.prefs.prefHasUserValue("keyword.URL");
Services.telemetry.getHistogramById("FX_KEYWORD_URL_USERSET").add(keywordURLUserSet);

View File

@ -657,7 +657,9 @@ PlacesViewBase.prototype = {
aPlacesNode._siteURI = aLivemark.siteURI;
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aPlacesNode, this);
// Prioritize the current livemark.
aLivemark.reload();
PlacesUtils.livemarks.reloadLivemarks();
if (shouldInvalidate)
this.invalidateContainer(aPlacesNode);
}
@ -900,11 +902,6 @@ PlacesToolbar.prototype = {
__proto__: PlacesViewBase.prototype,
_cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
#ifdef XP_UNIX
#ifndef XP_MACOSX
"mousedown", "mouseup",
#endif
#endif
"mousemove", "mouseover", "mouseout"],
QueryInterface: function PT_QueryInterface(aIID) {
@ -1101,16 +1098,6 @@ PlacesToolbar.prototype = {
case "mouseout":
this._onMouseOut(aEvent);
break;
#ifdef XP_UNIX
#ifndef XP_MACOSX
case "mouseup":
this._onMouseUp(aEvent);
break;
case "mousedown":
this._onMouseDown(aEvent);
break;
#endif
#endif
case "popupshowing":
this._onPopupShowing(aEvent);
break;
@ -1538,14 +1525,6 @@ PlacesToolbar.prototype = {
draggedElt.getAttribute("type") == "menu") {
// If the drag gesture on a container is toward down we open instead
// of dragging.
#ifdef XP_UNIX
#ifndef XP_MACOSX
if (this._mouseDownTimer) {
this._mouseDownTimer.cancel();
this._mouseDownTimer = null;
}
#endif
#endif
let translateY = this._cachedMouseMoveEvent.clientY - aEvent.clientY;
let translateX = this._cachedMouseMoveEvent.clientX - aEvent.clientX;
if ((translateY) >= Math.abs(translateX/2)) {
@ -1718,47 +1697,6 @@ PlacesToolbar.prototype = {
}
},
#ifdef XP_UNIX
#ifndef XP_MACOSX
_onMouseDown: function PT__onMouseDown(aEvent) {
let target = aEvent.target;
if (aEvent.button == 0 &&
target.localName == "toolbarbutton" &&
target.getAttribute("type") == "menu") {
this._allowPopupShowing = false;
// On Linux we can open the popup only after a delay.
// Indeed as soon as the menupopup opens we are unable to start a
// drag aEvent. See bug 500081 for details.
this._mouseDownTimer = Cc["@mozilla.org/timer;1"].
createInstance(Ci.nsITimer);
let callback = {
_self: this,
_target: target,
notify: function(timer) {
this._target.open = true;
this._mouseDownTimer = null;
}
};
this._mouseDownTimer.initWithCallback(callback, 300,
Ci.nsITimer.TYPE_ONE_SHOT);
}
},
_onMouseUp: function PT__onMouseUp(aEvent) {
if (aEvent.button != 0)
return;
if (this._mouseDownTimer) {
// On a click (down/up), we should open the menu popup.
this._mouseDownTimer.cancel();
this._mouseDownTimer = null;
aEvent.target.open = true;
}
},
#endif
#endif
_onMouseMove: function PT__onMouseMove(aEvent) {
// Used in dragStart to prevent dragging folders when dragging down.
this._cachedMouseMoveEvent = aEvent;

View File

@ -90,7 +90,6 @@
observes="paneElementsBroadcaster"/>
<textbox id="editBMPanel_feedLocationField"
class="uri-element"
onblur="gEditItemOverlay.onFeedLocationFieldBlur();"
observes="paneElementsBroadcaster"/>
</row>
@ -102,7 +101,6 @@
observes="paneElementsBroadcaster"/>
<textbox id="editBMPanel_siteLocationField"
class="uri-element"
onblur="gEditItemOverlay.onSiteLocationFieldBlur();"
observes="paneElementsBroadcaster"/>
</row>

View File

@ -896,7 +896,9 @@ PlacesTreeView.prototype = {
aNode._feedURI = aLivemark.feedURI;
if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aNode, this);
// Prioritize the current livemark.
aLivemark.reload();
PlacesUtils.livemarks.reloadLivemarks();
if (shouldInvalidate)
this.invalidateContainer(aNode);
}

View File

@ -24,6 +24,7 @@
* Dave Camp <dcamp@mozilla.com> (original author)
* Panos Astithas <past@mozilla.com>
* Victor Porof <vporof@mozilla.com>
* Mihai Sucan <mihai.sucan@gmail.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
@ -60,9 +61,37 @@ function DebuggerPane(aTab) {
this._tab = aTab;
this._close = this.close.bind(this);
this._debugTab = this.debugTab.bind(this);
this.breakpoints = {};
}
DebuggerPane.prototype = {
/**
* Skip editor breakpoint change events.
*
* This property tells the source editor event handler to skip handling of
* the BREAKPOINT_CHANGE events. This is used when the debugger adds/removes
* breakpoints from the editor. Typically, the BREAKPOINT_CHANGE event handler
* adds/removes events from the debugger, but when breakpoints are added from
* the public debugger API, we need to do things in reverse.
*
* This implementation relies on the fact that the source editor fires the
* BREAKPOINT_CHANGE events synchronously.
*
* @private
* @type boolean
*/
_skipEditorBreakpointChange: false,
/**
* The list of breakpoints in the debugger as tracked by the current
* DebuggerPane instance. This an object where the values are BreakpointActor
* objects received from the client, while the keys are actor names, for
* example "conn0.breakpoint3".
*
* @type object
*/
breakpoints: null,
/**
* Creates and initializes the widgets contained in the debugger UI.
*/
@ -87,11 +116,15 @@ DebuggerPane.prototype = {
self.frame.removeEventListener("DOMContentLoaded", initPane, true);
// Initialize the source editor.
self.frame.contentWindow.editor = self.editor = new SourceEditor();
self.frame.contentWindow.updateEditorBreakpoints =
self._updateEditorBreakpoints.bind(self);
let config = {
mode: SourceEditor.MODES.JAVASCRIPT,
showLineNumbers: true,
readOnly: true
readOnly: true,
showAnnotationRuler: true,
showOverviewRuler: true,
};
let editorPlaceholder = self.frame.contentDocument.getElementById("editor");
@ -107,14 +140,217 @@ DebuggerPane.prototype = {
* editor initialization.
*/
_onEditorLoad: function DP__onEditorLoad() {
this.editor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
this._onEditorBreakpointChange.bind(this));
// Connect to the debugger server.
this.connect();
},
/**
* Event handler for breakpoint changes that happen in the editor. This
* function syncs the breakpoint changes in the editor to those in the
* debugger.
*
* @private
* @param object aEvent
* The SourceEditor.EVENTS.BREAKPOINT_CHANGE event object.
*/
_onEditorBreakpointChange: function DP__onEditorBreakpointChange(aEvent) {
if (this._skipEditorBreakpointChange) {
return;
}
aEvent.added.forEach(this._onEditorBreakpointAdd, this);
aEvent.removed.forEach(this._onEditorBreakpointRemove, this);
},
/**
* Retrieve the URL of the selected script in the debugger view.
*
* @private
* @return string
* The URL of the selected script.
*/
_selectedScript: function DP__selectedScript() {
return this.debuggerWindow ?
this.debuggerWindow.DebuggerView.Scripts.selected : null;
},
/**
* Event handler for new breakpoints that come from the editor.
*
* @private
* @param object aBreakpoint
* The breakpoint object coming from the editor.
*/
_onEditorBreakpointAdd: function DP__onEditorBreakpointAdd(aBreakpoint) {
let location = {
url: this._selectedScript(),
line: aBreakpoint.line + 1,
};
if (location.url) {
let callback = function (aClient, aError) {
if (aError) {
this._skipEditorBreakpointChange = true;
let result = this.editor.removeBreakpoint(aBreakpoint.line);
this._skipEditorBreakpointChange = false;
}
}.bind(this);
this.addBreakpoint(location, callback, true);
}
},
/**
* Event handler for breakpoints that are removed from the editor.
*
* @private
* @param object aBreakpoint
* The breakpoint object that was removed from the editor.
*/
_onEditorBreakpointRemove: function DP__onEditorBreakpointRemove(aBreakpoint) {
let url = this._selectedScript();
let line = aBreakpoint.line + 1;
if (!url) {
return;
}
let breakpoint = this.getBreakpoint(url, line);
if (breakpoint) {
this.removeBreakpoint(breakpoint, null, true);
}
},
/**
* Update the breakpoints in the editor view. This function takes the list of
* breakpoints in the debugger and adds them back into the editor view. This
* is invoked when the selected script is changed.
*
* @private
*/
_updateEditorBreakpoints: function DP__updateEditorBreakpoints()
{
let url = this._selectedScript();
if (!url) {
return;
}
this._skipEditorBreakpointChange = true;
for each (let breakpoint in this.breakpoints) {
if (breakpoint.location.url == url) {
this.editor.addBreakpoint(breakpoint.location.line - 1);
}
}
this._skipEditorBreakpointChange = false;
},
/**
* Add a breakpoint.
*
* @param object aLocation
* The location where you want the breakpoint. This object must have
* two properties:
* - url - the URL of the script.
* - line - the line number (starting from 1).
* @param function [aCallback]
* Optional function to invoke once the breakpoint is added. The
* callback is invoked with two arguments:
* - aBreakpointClient - the BreakpointActor client object, if the
* breakpoint has been added successfully.
* - aResponseError - if there was any error.
* @param boolean [aNoEditorUpdate=false]
* Tells if you want to skip editor updates. Typically the editor is
* updated to visually indicate that a breakpoint has been added.
*/
addBreakpoint:
function DP_addBreakpoint(aLocation, aCallback, aNoEditorUpdate) {
let breakpoint = this.getBreakpoint(aLocation.url, aLocation.line);
if (breakpoint) {
aCallback && aCallback(breakpoint);
return;
}
this.activeThread.setBreakpoint(aLocation, function(aResponse, aBpClient) {
if (!aResponse.error) {
this.breakpoints[aBpClient.actor] = aBpClient;
if (!aNoEditorUpdate) {
let url = this._selectedScript();
if (url == aLocation.url) {
this._skipEditorBreakpointChange = true;
this.editor.addBreakpoint(aLocation.line - 1);
this._skipEditorBreakpointChange = false;
}
}
}
aCallback && aCallback(aBpClient, aResponse.error);
}.bind(this));
},
/**
* Remove a breakpoint.
*
* @param object aBreakpoint
* The breakpoint you want to remove.
* @param function [aCallback]
* Optional function to invoke once the breakpoint is removed. The
* callback is invoked with one argument: the breakpoint location
* object which holds the url and line properties.
* @param boolean [aNoEditorUpdate=false]
* Tells if you want to skip editor updates. Typically the editor is
* updated to visually indicate that a breakpoint has been removed.
*/
removeBreakpoint:
function DP_removeBreakpoint(aBreakpoint, aCallback, aNoEditorUpdate) {
if (!(aBreakpoint.actor in this.breakpoints)) {
aCallback && aCallback(aBreakpoint.location);
return;
}
aBreakpoint.remove(function() {
delete this.breakpoints[aBreakpoint.actor];
if (!aNoEditorUpdate) {
let url = this._selectedScript();
if (url == aBreakpoint.location.url) {
this._skipEditorBreakpointChange = true;
this.editor.removeBreakpoint(aBreakpoint.location.line - 1);
this._skipEditorBreakpointChange = false;
}
}
aCallback && aCallback(aBreakpoint.location);
}.bind(this));
},
/**
* Get the breakpoint object at the given location.
*
* @param string aUrl
* The URL of where the breakpoint is.
* @param number aLine
* The line number where the breakpoint is.
* @return object
* The BreakpointActor object.
*/
getBreakpoint: function DP_getBreakpoint(aUrl, aLine) {
for each (let breakpoint in this.breakpoints) {
if (breakpoint.location.url == aUrl && breakpoint.location.line == aLine) {
return breakpoint;
}
}
return null;
},
/**
* Closes the debugger UI removing child nodes and event listeners.
*/
close: function DP_close() {
for each (let breakpoint in this.breakpoints) {
this.removeBreakpoint(breakpoint);
}
if (this._tab) {
this._tab._scriptDebugger = null;
this._tab = null;
@ -192,7 +428,7 @@ DebuggerPane.prototype = {
},
get debuggerWindow() {
return this.frame.contentWindow;
return this.frame ? this.frame.contentWindow : null;
},
get debuggerClient() {
@ -340,6 +576,7 @@ DebuggerUI.prototype = {
script.text = aSourceText;
script.contentType = aContentType;
elt.setUserData("sourceScript", script, null);
dbg._updateEditorBreakpoints();
}
};

View File

@ -22,6 +22,7 @@
*
* Contributor(s):
* Victor Porof <vporof@mozilla.com> (original author)
* Mihai Sucan <mihai.sucan@gmail.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
@ -199,7 +200,6 @@ DebuggerView.Stackframes = {
// the list item wasn't found in the stackframe container
if (!frame) {
dump("The frame list item wasn't found in the stackframes container.");
return;
}
@ -356,7 +356,6 @@ DebuggerView.Properties = {
// make sure the element was created successfully
if (!element) {
dump("The debugger scope container wasn't created properly: " + aId);
return null;
}
@ -398,7 +397,6 @@ DebuggerView.Properties = {
// make sure the element was created successfully
if (!element) {
dump("The debugger variable container wasn't created properly: " + aId);
return null;
}
@ -466,7 +464,6 @@ DebuggerView.Properties = {
// make sure the info node exists
if (!info) {
dump("Could not set the grip for the corresponding variable: " + aVar.id);
return null;
}
@ -569,7 +566,6 @@ DebuggerView.Properties = {
// make sure the element was created successfully
if (!element) {
dump("The debugger property container wasn't created properly.");
return null;
}
@ -710,11 +706,9 @@ DebuggerView.Properties = {
_createPropertyElement: function DVP__createPropertyElement(aName, aId, aClass, aParent) {
// make sure we don't duplicate anything and the parent exists
if (document.getElementById(aId)) {
dump("Duplicating a property element id is not allowed.");
return null;
}
if (!aParent) {
dump("A property element must have a valid parent node specified.");
return null;
}
@ -1127,6 +1121,15 @@ DebuggerView.Scripts = {
}
},
/**
* Retrieve the URL of the selected script.
* @return string|null
*/
get selected() {
return this._scripts.selectedItem ?
this._scripts.selectedItem.value : null;
},
/**
* Adds a script to the scripts container.
* If the script already exists (was previously added), null is returned.

View File

@ -78,7 +78,8 @@ function startDebuggingTab(aClient, aTabGrip)
gTabClient = aTabClient;
gClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
if (!aThreadClient) {
dump("Couldn't attach to thread: "+aResponse.error+"\n");
Components.utils.reportError("Couldn't attach to thread: " +
aResponse.error);
return;
}
ThreadState.connect(aThreadClient, function() {
@ -612,6 +613,7 @@ var SourceScripts = {
window.editor.setText(DebuggerView.getStr("loadingText"));
} else {
window.editor.setText(aScript.text);
window.updateEditorBreakpoints();
}
}
};

View File

@ -73,6 +73,7 @@ _BROWSER_TEST_FILES = \
browser_dbg_update-editor-mode.js \
browser_dbg_select-line.js \
browser_dbg_clean-exit.js \
browser_dbg_bug723069_editor-breakpoints.js \
head.js \
$(NULL)

View File

@ -0,0 +1,274 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Bug 723069: test the debugger breakpoint API and connection to the source
* editor.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
let gPane = null;
let gTab = null;
let gDebuggee = null;
let gDebugger = null;
let gScripts = null;
let gEditor = null;
let gBreakpoints = null;
function test()
{
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0);
});
gDebuggee.firstCall();
});
function onScriptsAdded()
{
gScripts = gDebugger.DebuggerView.Scripts;
is(gDebugger.StackFrames.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
is(gScripts._scripts.itemCount, 2, "Found the expected number of scripts.");
gEditor = gDebugger.editor;
isnot(gEditor.getText().indexOf("debugger"), -1,
"The correct script was loaded initially.");
isnot(gScripts.selected, gScripts.scriptLocations()[0],
"the correct sccript is selected");
gBreakpoints = gPane.breakpoints;
is(Object.keys(gBreakpoints), 0, "no breakpoints");
ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
is(gEditor.getBreakpoints().length, 0, "no breakpoints in the editor");
info("add the first breakpoint");
gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddFirst);
let location = {url: gScripts.selected, line: 6};
executeSoon(function() {
gPane.addBreakpoint(location, onBreakpointAddFirst);
});
}
let breakpointsAdded = 0;
let breakpointsRemoved = 0;
let editorBreakpointChanges = 0;
function onEditorBreakpointAddFirst(aEvent)
{
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddFirst);
editorBreakpointChanges++;
ok(aEvent, "breakpoint1 added to the editor");
is(aEvent.added.length, 1, "one breakpoint added to the editor");
is(aEvent.removed.length, 0, "no breakpoint was removed from the editor");
is(aEvent.added[0].line, 5, "editor breakpoint line is correct");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct");
}
function onBreakpointAddFirst(aBreakpointClient, aResponseError)
{
breakpointsAdded++;
ok(aBreakpointClient, "breakpoint1 added, client received");
ok(!aResponseError, "breakpoint1 added without errors");
is(aBreakpointClient.location.url, gScripts.selected,
"breakpoint1 client url is correct");
is(aBreakpointClient.location.line, 6,
"breakpoint1 client line is correct");
executeSoon(function() {
ok(aBreakpointClient.actor in gBreakpoints,
"breakpoint1 client found in the list of debugger breakpoints");
is(Object.keys(gBreakpoints).length, 1,
"the list of debugger breakpoints holds only one breakpoint");
is(gPane.getBreakpoint(gScripts.selected, 6), aBreakpointClient,
"getBreakpoint(selectedScript, 2) returns the correct breakpoint");
info("remove the first breakpoint");
gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointRemoveFirst);
gPane.removeBreakpoint(aBreakpointClient, onBreakpointRemoveFirst);
});
}
function onBreakpointRemoveFirst(aLocation)
{
breakpointsRemoved++;
ok(aLocation, "breakpoint1 removed");
is(aLocation.url, gScripts.selected, "breakpoint1 remove: url is correct");
is(aLocation.line, 6, "breakpoint1 remove: line is correct");
executeSoon(testBreakpointAddBackground);
}
function onEditorBreakpointRemoveFirst(aEvent)
{
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointRemoveFirst);
editorBreakpointChanges++;
ok(aEvent, "breakpoint1 removed from the editor");
is(aEvent.added.length, 0, "no breakpoint was added to the editor");
is(aEvent.removed.length, 1, "one breakpoint was removed from the editor");
is(aEvent.removed[0].line, 5, "editor breakpoint line is correct");
is(gEditor.getBreakpoints().length, 0, "editor.getBreakpoints().length is correct");
}
function testBreakpointAddBackground()
{
info("add a breakpoint to the second script which is not selected");
is(Object.keys(gBreakpoints).length, 0, "no breakpoints in the debugger");
ok(!gPane.getBreakpoint(gScripts.selected, 6),
"getBreakpoint(selectedScript, 6) returns no breakpoint");
let script0 = gScripts.scriptLocations()[0];
isnot(script0, gScripts.selected,
"first script location is not the currently selected script");
let location = {url: script0, line: 5};
gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddBackgroundTrap);
gPane.addBreakpoint(location, onBreakpointAddBackground);
}
function onEditorBreakpointAddBackgroundTrap(aEvent)
{
// trap listener: no breakpoint must be added to the editor when a breakpoint
// is added to a script that is not currently selected.
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddBackgroundTrap);
editorBreakpointChanges++;
ok(false, "breakpoint2 must not be added to the editor");
}
function onBreakpointAddBackground(aBreakpointClient, aResponseError)
{
breakpointsAdded++;
ok(aBreakpointClient, "breakpoint2 added, client received");
ok(!aResponseError, "breakpoint2 added without errors");
is(aBreakpointClient.location.url, gScripts.scriptLocations()[0],
"breakpoint2 client url is correct");
is(aBreakpointClient.location.line, 5,
"breakpoint2 client line is correct");
executeSoon(function() {
ok(aBreakpointClient.actor in gBreakpoints,
"breakpoint2 client found in the list of debugger breakpoints");
is(Object.keys(gBreakpoints).length, 1, "one breakpoint in the debugger");
is(gPane.getBreakpoint(gScripts.scriptLocations()[0], 5), aBreakpointClient,
"getBreakpoint(scriptLocations[0], 5) returns the correct breakpoint");
// remove the trap listener
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddBackgroundTrap);
gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddSwitch);
gEditor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onEditorTextChanged);
info("switch to the second script");
gScripts._scripts.selectedIndex = 0;
gDebugger.SourceScripts.onChange({ target: gScripts._scripts });
});
}
function onEditorBreakpointAddSwitch(aEvent)
{
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointAddSwitch);
editorBreakpointChanges++;
ok(aEvent, "breakpoint2 added to the editor");
is(aEvent.added.length, 1, "one breakpoint added to the editor");
is(aEvent.removed.length, 0, "no breakpoint was removed from the editor");
is(aEvent.added[0].line, 4, "editor breakpoint line is correct");
is(gEditor.getBreakpoints().length, 1,
"editor.getBreakpoints().length is correct");
}
function onEditorTextChanged()
{
gEditor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onEditorTextChanged);
is(gEditor.getText().indexOf("debugger"), -1,
"The second script is no longer displayed.");
isnot(gEditor.getText().indexOf("firstCall"), -1,
"The first script is displayed.");
executeSoon(function() {
info("remove the second breakpoint using the mouse");
gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointRemoveSecond);
let testWin = gEditor.editorElement.ownerDocument.defaultView;
EventUtils.synthesizeMouse(gEditor.editorElement, 10, 70, {}, testWin);
});
}
function onEditorBreakpointRemoveSecond(aEvent)
{
gEditor.removeEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
onEditorBreakpointRemoveSecond);
editorBreakpointChanges++;
ok(aEvent, "breakpoint2 removed from the editor");
is(aEvent.added.length, 0, "no breakpoint was added to the editor");
is(aEvent.removed.length, 1, "one breakpoint was removed from the editor");
is(aEvent.removed[0].line, 4, "editor breakpoint line is correct");
is(gEditor.getBreakpoints().length, 0, "editor.getBreakpoints().length is correct");
executeSoon(function() {
gDebugger.StackFrames.activeThread.resume(finish);
});
}
registerCleanupFunction(function() {
is(Object.keys(gBreakpoints).length, 0, "no breakpoint in the debugger");
ok(!gPane.getBreakpoint(gScripts.scriptLocations()[0], 5),
"getBreakpoint(scriptLocations[0], 5) returns no breakpoint");
removeTab(gTab);
is(breakpointsAdded, 2, "correct number of breakpoints have been added");
is(breakpointsRemoved, 1, "correct number of breakpoints have been removed");
is(editorBreakpointChanges, 4, "correct number of editor breakpoint changes");
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gScripts = null;
gEditor = null;
gBreakpoints = null;
});
}

View File

@ -7,7 +7,6 @@
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
@ -15,7 +14,6 @@ const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
function test() {
debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
@ -29,12 +27,16 @@ function testCleanExit() {
is(gDebugger.StackFrames.activeThread.paused, true,
"Should be paused after the debugger statement.");
gPane._client.addOneTimeListener("tabDetached", function () {
finish();
});
removeTab(gTab);
closeDebuggerAndFinish(gTab);
}}, 0);
});
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

View File

@ -55,10 +55,17 @@ function testLocationChange()
gPane._client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
ok(true, "Successfully reattached to the tab again.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
});
});
content.location = TAB1_URL;
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -6,13 +6,11 @@
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
@ -63,8 +61,7 @@ function testResume() {
is(button.label, gDebugger.DebuggerView.getStr("pauseLabel"),
"Button label should be pause when running.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
}}, 0);
});
@ -72,3 +69,9 @@ function testResume() {
gDebugger.document.getElementById("resume"),
gDebugger);
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
});

View File

@ -134,9 +134,15 @@ function resumeAndFinish() {
is(vs._scripts.itemCount, 6,
"Got too many script items in the list!");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
});
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -116,16 +116,19 @@ function testSimpleCall() {
ok(!testScope.expanded,
"Clicking again the testScope tilte should collapse it.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -118,16 +118,19 @@ function testSimpleCall() {
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
"The scope should have been removed from the parent container tree.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -73,16 +73,19 @@ function testSimpleCall() {
is(testScope.querySelector(".details").childNodes.length, 0,
"The var should have been removed from the parent container tree.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -81,16 +81,19 @@ function testSimpleCall() {
is(testScope.querySelector(".details").childNodes.length, 0,
"The var should have been removed from the parent container tree.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -117,17 +117,19 @@ function testSimpleCall() {
is(localVar5.querySelector(".info").textContent, "[object Object]",
"The grip information for the localVar5 wasn't set correctly.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -10,14 +10,12 @@ const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
@ -87,10 +85,16 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
}}, 0);
});
gDebugger.StackFrames.activeThread.resume();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

View File

@ -10,14 +10,12 @@ const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
@ -103,10 +101,16 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
}}, 0);
});
gDebugger.StackFrames.activeThread.resume();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

View File

@ -103,6 +103,13 @@ function testSwitchRunning()
ok(gDebugger.editor.getText().search(/firstCall/) == -1,
"The first script is no longer displayed.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -68,14 +68,22 @@ function testSelectLine() {
"The correct line is selected.");
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
});
});
});
// Scroll all the way down to ensure stackframe-3 is visible.
let stackframes = gDebugger.document.getElementById("stackframes");
stackframes.scrollTop = stackframes.scrollHeight;
// Click the oldest stack frame.
let frames = gDebugger.DebuggerView.Stackframes._frames;
is(frames.querySelectorAll(".dbg-stackframe").length, 4,
"Should have four frames.");
let element = gDebugger.document.getElementById("stackframe-3");
isnot(element, null, "Found the third stack frame.");
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
});
}}, 0);
@ -83,3 +91,11 @@ function testSelectLine() {
gDebuggee.firstCall();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -36,16 +36,19 @@ function testSimpleCall() {
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
"All children should be frames.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.simpleCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -67,17 +67,19 @@ function testEvalCall() {
ok(!frames.querySelector("#stackframe-1").classList.contains("selected"),
"Second frame should not be selected after click inside the first frame.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
}}, 0);
});
gDebuggee.evalCall();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -47,7 +47,9 @@ function testRecurse() {
is(frames.querySelectorAll(".dbg-stackframe").length, recurseLimit,
"Should have reached the recurse limit.");
resumeAndFinish();
gDebugger.StackFrames.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
});
});
frames.scrollTop = frames.scrollHeight;
@ -60,9 +62,10 @@ function testRecurse() {
gDebuggee.recurse();
}
function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() {
registerCleanupFunction(function() {
removeTab(gTab);
finish();
});
}
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -48,8 +48,7 @@ function testEvalCallResume() {
is(frames.querySelectorAll(".empty").length, 1,
"Should have the empty list explanation.");
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
});
gPane.activeThread.resume();
@ -58,3 +57,11 @@ function testEvalCallResume() {
gDebuggee.evalCall();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
});

View File

@ -72,7 +72,15 @@ function testSwitchPaused()
"Found the expected editor mode.");
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
closeDebuggerAndFinish(gTab);
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gScripts = null;
});

View File

@ -49,6 +49,14 @@ function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
function closeDebuggerAndFinish(aTab) {
DebuggerUI.aWindow.addEventListener("Debugger:Shutdown", function cleanup() {
DebuggerUI.aWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
finish();
}, false);
DebuggerUI.getDebugger(aTab).close();
}
function get_tab_actor_for_url(aClient, aURL, aCallback) {
aClient.listTabs(function(aResponse) {
for each (let tab in aResponse.tabs) {

View File

@ -23,6 +23,7 @@
* Mihai Sucan <mihai.sucan@gmail.com> (original author)
* Kenny Heaton <kennyheaton@gmail.com>
* Spyros Livathinos <livathinos.spyros@gmail.com>
* Allen Eubank <adeubank@gmail.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
@ -124,6 +125,18 @@ const DEFAULT_KEYBINDINGS = [
code: Ci.nsIDOMKeyEvent.DOM_VK_TAB,
shift: true,
},
{
action: "Move Lines Up",
code: Ci.nsIDOMKeyEvent.DOM_VK_UP,
ctrl: Services.appinfo.OS == "Darwin",
alt: true,
},
{
action: "Move Lines Down",
code: Ci.nsIDOMKeyEvent.DOM_VK_DOWN,
ctrl: Services.appinfo.OS == "Darwin",
alt: true,
},
];
var EXPORTED_SYMBOLS = ["SourceEditor"];
@ -367,6 +380,7 @@ SourceEditor.prototype = {
"Find Next Occurrence": [this.ui.findNext, this.ui],
"Find Previous Occurrence": [this.ui.findPrevious, this.ui],
"Goto Line...": [this.ui.gotoLine, this.ui],
"Move Lines Down": [this._moveLines, this],
};
for (let name in actions) {
@ -374,9 +388,17 @@ SourceEditor.prototype = {
this._view.setAction(name, action[0].bind(action[1]));
}
this._view.setAction("Move Lines Up", this._moveLines.bind(this, true));
let keys = (config.keys || []).concat(DEFAULT_KEYBINDINGS);
keys.forEach(function(aKey) {
let binding = new KeyBinding(aKey.code, aKey.accel, aKey.shift, aKey.alt);
// In Orion mod1 refers to Cmd on Macs and Ctrl on Windows and Linux.
// So, if ctrl is in aKey we use it on Windows and Linux, otherwise
// we use aKey.accel for mod1.
let mod1 = Services.appinfo.OS != "Darwin" &&
"ctrl" in aKey ? aKey.ctrl : aKey.accel;
let binding = new KeyBinding(aKey.code, mod1, aKey.shift, aKey.alt,
aKey.ctrl);
this._view.setKeyBinding(binding, aKey.action);
if (aKey.callback) {
@ -578,6 +600,78 @@ SourceEditor.prototype = {
return true;
},
/**
* Move lines upwards or downwards, relative to the current caret location.
*
* @private
* @param boolean aLineAbove
* True if moving lines up, false to move lines down.
*/
_moveLines: function SE__moveLines(aLineAbove)
{
if (this.readOnly) {
return false;
}
let model = this._model;
let selection = this.getSelection();
let firstLine = model.getLineAtOffset(selection.start);
if (firstLine == 0 && aLineAbove) {
return true;
}
let lastLine = model.getLineAtOffset(selection.end);
let firstLineStart = model.getLineStart(firstLine);
let lastLineStart = model.getLineStart(lastLine);
if (selection.start != selection.end && lastLineStart == selection.end) {
lastLine--;
}
if (!aLineAbove && (lastLine + 1) == this.getLineCount()) {
return true;
}
let lastLineEnd = model.getLineEnd(lastLine, true);
let text = this.getText(firstLineStart, lastLineEnd);
if (aLineAbove) {
let aboveLine = firstLine - 1;
let aboveLineStart = model.getLineStart(aboveLine);
this.startCompoundChange();
if (lastLine == (this.getLineCount() - 1)) {
let delimiterStart = model.getLineEnd(aboveLine);
let delimiterEnd = model.getLineEnd(aboveLine, true);
let lineDelimiter = this.getText(delimiterStart, delimiterEnd);
text += lineDelimiter;
this.setText("", firstLineStart - lineDelimiter.length, lastLineEnd);
} else {
this.setText("", firstLineStart, lastLineEnd);
}
this.setText(text, aboveLineStart, aboveLineStart);
this.endCompoundChange();
this.setSelection(aboveLineStart, aboveLineStart + text.length);
} else {
let belowLine = lastLine + 1;
let belowLineEnd = model.getLineEnd(belowLine, true);
let insertAt = belowLineEnd - lastLineEnd + firstLineStart;
let lineDelimiter = "";
if (belowLine == this.getLineCount() - 1) {
let delimiterStart = model.getLineEnd(lastLine);
lineDelimiter = this.getText(delimiterStart, lastLineEnd);
text = lineDelimiter + text.substr(0, text.length -
lineDelimiter.length);
}
this.startCompoundChange();
this.setText("", firstLineStart, lastLineEnd);
this.setText(text, insertAt, insertAt);
this.endCompoundChange();
this.setSelection(insertAt + lineDelimiter.length,
insertAt + text.length);
}
return true;
},
/**
* The Orion Selection event handler. The current caret line is
* highlighted and for Linux users the selected text is copied into the X11

View File

@ -192,6 +192,7 @@ SourceEditor.DEFAULTS = {
* - action - name of the editor action to invoke.
* - code - keyCode for the shortcut.
* - accel - boolean for the Accel key (Cmd on Macs, Ctrl on Linux/Windows).
* - ctrl - boolean for the Control key
* - shift - boolean for the Shift key.
* - alt - boolean for the Alt key.
* - callback - optional function to invoke, if the action is not predefined

View File

@ -58,6 +58,7 @@ _BROWSER_TEST_FILES = \
browser_bug725388_mouse_events.js \
browser_bug707987_debugger_breakpoints.js \
browser_bug712982_line_ruler_click.js \
browser_bug725618_moveLines_shortcut.js \
browser_bug700893_dirty_state.js \
head.js \

View File

@ -0,0 +1,117 @@
/* 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";
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
let editor;
let testWin;
function test()
{
waitForExplicitFinish();
const windowUrl = "data:application/vnd.mozilla.xul+xml,<?xml version='1.0'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='test for bug 725618 - moveLines shortcut' width='300' height='500'>" +
"<box flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
}
function initEditor()
{
let box = testWin.document.querySelector("box");
let text = "target\nfoo\nbar"
let config = {
initialText: text,
};
editor = new SourceEditor();
editor.init(box, config, editorLoaded);
}
function editorLoaded()
{
editor.focus();
editor.setCaretOffset(0);
let modifiers = {altKey: true, ctrlKey: Services.appinfo.OS == "Darwin"};
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "foo\ntarget\nbar", "Move lines down works");
is(editor.getSelectedText(), "target\n", "selection is correct");
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "foo\nbar\ntarget", "Move lines down works");
is(editor.getSelectedText(), "target", "selection is correct");
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "foo\nbar\ntarget", "Check for bottom of editor works");
is(editor.getSelectedText(), "target", "selection is correct");
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "foo\ntarget\nbar", "Move lines up works");
is(editor.getSelectedText(), "target\n", "selection is correct");
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar", "Move lines up works");
is(editor.getSelectedText(), "target\n", "selection is correct");
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar", "Check for top of editor works");
is(editor.getSelectedText(), "target\n", "selection is correct");
editor.setSelection(0, 10);
info("text within selection =" + editor.getSelectedText());
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "bar\ntarget\nfoo", "Multiple line move down works");
is(editor.getSelectedText(), "target\nfoo", "selection is correct");
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "bar\ntarget\nfoo",
"Check for bottom of editor works with multiple line selection");
is(editor.getSelectedText(), "target\nfoo", "selection is correct");
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar", "Multiple line move up works");
is(editor.getSelectedText(), "target\nfoo\n", "selection is correct");
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar",
"Check for top of editor works with multiple line selection");
is(editor.getSelectedText(), "target\nfoo\n", "selection is correct");
editor.readOnly = true;
editor.setCaretOffset(0);
EventUtils.synthesizeKey("VK_UP", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar",
"Check for readOnly mode works with move lines up");
EventUtils.synthesizeKey("VK_DOWN", modifiers, testWin);
is(editor.getText(), "target\nfoo\nbar",
"Check for readOnly mode works with move lines down");
finish();
}
registerCleanupFunction(function()
{
editor.destroy();
testWin.close();
testWin = editor = null;
});

View File

@ -1198,11 +1198,19 @@ function CssRule(aCssSheet, aDomRule, aElement)
this._cssSheet = aCssSheet;
this._domRule = aDomRule;
let parentRule = aDomRule.parentRule;
if (parentRule && parentRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE) {
this.mediaText = parentRule.media.mediaText;
}
if (this._cssSheet) {
// parse _domRule.selectorText on call to this.selectors
this._selectors = null;
this.line = this._cssSheet._cssLogic.domUtils.getRuleLine(this._domRule);
this.source = this._cssSheet.shortSource + ":" + this.line;
if (this.mediaText) {
this.source += " @media " + this.mediaText;
}
this.href = this._cssSheet.href;
this.contentRule = this._cssSheet.contentSheet;
} else if (aElement) {
@ -1218,6 +1226,13 @@ function CssRule(aCssSheet, aDomRule, aElement)
CssRule.prototype = {
_passId: null,
mediaText: "",
get isMediaRule()
{
return !!this.mediaText;
},
/**
* Check if the parent stylesheet is allowed by the CssLogic.sourceFilter.
*

View File

@ -356,10 +356,20 @@ function Rule(aElementStyle, aOptions)
this.style = aOptions.style || this.domRule.style;
this.selectorText = aOptions.selectorText || this.domRule.selectorText;
this.inherited = aOptions.inherited || null;
if (this.domRule) {
let parentRule = this.domRule.parentRule;
if (parentRule && parentRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE) {
this.mediaText = parentRule.media.mediaText;
}
}
this._getTextProperties();
}
Rule.prototype = {
mediaText: "",
get title()
{
if (this._title) {
@ -380,7 +390,7 @@ Rule.prototype = {
args, args.length);
}
return this._title;
return this._title + (this.mediaText ? " @media " + this.mediaText : "");
},
/**
@ -722,6 +732,24 @@ CssRuleView.prototype = {
}.bind(this);
this._createEditors();
// When creating a new property, we fake the normal property
// editor behavior (focusing a property's value after entering its
// name) by responding to the name's blur event, creating the
// value editor, and grabbing focus to the value editor. But if
// focus has already moved to another document, we won't be able
// to move focus to the new editor.
// Create a focusable item at the end of the editors to catch these
// cases.
this._focusBackstop = createChild(this.element, "div", {
tabindex: 0,
});
this._backstopHandler = function() {
// If this item is actually focused long enough to get the focus
// event, allow focus to move on out of this document.
moveFocus(this.doc.defaultView, FOCUS_FORWARD);
}.bind(this);
this._focusBackstop.addEventListener("focus", this._backstopHandler, false);
},
/**
@ -752,6 +780,12 @@ CssRuleView.prototype = {
this._clearRules();
this._viewedElement = null;
this._elementStyle = null;
if (this._focusBackstop) {
this._focusBackstop.removeEventListener("focus", this._backstopHandler, false);
this._backstopHandler = null;
this._focusBackstop = null;
}
},
/**
@ -835,7 +869,6 @@ RuleEditor.prototype = {
this.openBrace = createChild(header, "span", {
class: "ruleview-ruleopen",
tabindex: "0",
textContent: " {"
});

View File

@ -60,7 +60,10 @@ _BROWSER_TEST_FILES = \
browser_ruleview_manipulation.js \
browser_ruleview_override.js \
browser_ruleview_ui.js \
browser_ruleview_focus.js \
browser_bug705707_is_content_stylesheet.js \
browser_bug722196_property_view_media_queries.js \
browser_bug722196_rule_view_media_queries.js \
browser_bug_592743_specificity.js \
head.js \
$(NULL)
@ -74,6 +77,7 @@ _BROWSER_TEST_PAGES = \
browser_bug705707_is_content_stylesheet_script.css \
browser_bug705707_is_content_stylesheet.xul \
browser_bug705707_is_content_stylesheet_xul.css \
browser_bug722196_identify_media_queries.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

View File

@ -0,0 +1,24 @@
<html>
<head>
<title>test</title>
<script type="application/javascript;version=1.7">
</script>
<style>
div {
width: 1000px;
height: 100px;
background-color: #f00;
}
@media screen and (min-width: 1px) {
div {
width: 200px;
}
}
</style>
</head>
<body>
<div></div>
</body>
</html>

View File

@ -0,0 +1,68 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that we correctly display appropriate media query titles in the
// property view.
let doc;
let stylePanel;
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug722196_identify_media_queries.html";
function test()
{
waitForExplicitFinish();
addTab(TEST_URI);
browser.addEventListener("load", docLoaded, true);
}
function docLoaded()
{
browser.removeEventListener("load", docLoaded, true);
doc = content.document;
stylePanel = new StyleInspector(window);
Services.obs.addObserver(checkSheets, "StyleInspector-opened", false);
stylePanel.createPanel(false, function() {
stylePanel.open(doc.body);
});
}
function checkSheets()
{
Services.obs.removeObserver(checkSheets, "StyleInspector-opened", false);
ok(stylePanel.isOpen(), "style inspector is open");
var div = doc.querySelector("div");
ok(div, "captain, we have the div");
stylePanel.selectNode(div);
let cssLogic = stylePanel.cssLogic;
cssLogic.processMatchedSelectors();
let _strings = Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties");
let inline = _strings.GetStringFromName("rule.sourceInline");
let source1 = inline + ":8";
let source2 = inline + ":15 @media screen and (min-width: 1px)";
is(cssLogic._matchedRules[0][0].source, source1,
"rule.source gives correct output for rule 1");
is(cssLogic._matchedRules[1][0].source, source2,
"rule.source gives correct output for rule 2");
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
stylePanel.close();
}
function finishUp()
{
Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
doc = null;
gBrowser.removeCurrentTab();
finish();
}

View File

@ -0,0 +1,55 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that we correctly display appropriate media query titles in the
// rule view.
let tempScope = {};
Cu.import("resource:///modules/devtools/CssRuleView.jsm", tempScope);
let _ElementStyle = tempScope._ElementStyle;
let doc;
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug722196_identify_media_queries.html";
function test()
{
waitForExplicitFinish();
addTab(TEST_URI);
browser.addEventListener("load", docLoaded, true);
}
function docLoaded()
{
browser.removeEventListener("load", docLoaded, true);
doc = content.document;
checkSheets();
}
function checkSheets()
{
var div = doc.querySelector("div");
ok(div, "captain, we have the div");
let elementStyle = new _ElementStyle(div);
is(elementStyle.rules.length, 3, "Should have 3 rules.");
let _strings = Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties");
let inline = _strings.GetStringFromName("rule.sourceInline");
is(elementStyle.rules[0].title, inline, "check rule 0 title");
is(elementStyle.rules[1].title, inline +
":15 @media screen and (min-width: 1px)", "check rule 1 title");
is(elementStyle.rules[2].title, inline + ":8", "check rule 2 title");
finishUp();
}
function finishUp()
{
doc = null;
gBrowser.removeCurrentTab();
finish();
}

View File

@ -0,0 +1,106 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that focus doesn't leave the style editor when adding a property
// (bug 719916)
let doc;
let stylePanel;
function waitForRuleView(aCallback)
{
if (InspectorUI.ruleView) {
aCallback();
return;
}
let ruleViewFrame = InspectorUI.getToolIframe(InspectorUI.ruleViewObject);
ruleViewFrame.addEventListener("load", function(evt) {
ruleViewFrame.removeEventListener(evt.type, arguments.callee, true);
executeSoon(function() {
aCallback();
});
}, true);
}
function waitForEditorFocus(aParent, aCallback)
{
aParent.addEventListener("focus", function onFocus(evt) {
if (evt.target.inplaceEditor) {
aParent.removeEventListener("focus", onFocus, true);
let editor = evt.target.inplaceEditor;
executeSoon(function() {
aCallback(editor);
});
}
}, true);
}
function openRuleView()
{
Services.obs.addObserver(function onOpened() {
Services.obs.removeObserver(onOpened,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
// Highlight a node.
let node = content.document.getElementsByTagName("h1")[0];
InspectorUI.inspectNode(node);
InspectorUI.stopInspecting();
// Open the rule view sidebar.
waitForRuleView(testFocus);
InspectorUI.showSidebar();
InspectorUI.ruleButton.click();
testFocus();
}, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function testFocus()
{
let ruleViewFrame = InspectorUI.getToolIframe(InspectorUI.ruleViewObject);
let brace = ruleViewFrame.contentDocument.querySelectorAll(".ruleview-ruleclose")[0];
waitForEditorFocus(brace.parentNode, function onNewElement(aEditor) {
aEditor.input.value = "color";
waitForEditorFocus(brace.parentNode, function onEditingValue(aEditor) {
// If we actually get this focus we're ok.
ok(true, "We got focus.");
aEditor.input.value = "green";
// If we've retained focus, pressing return will start a new editor.
// If not, we'll wait here until we time out.
waitForEditorFocus(brace.parentNode, function onNewEditor(aEditor) {
aEditor.input.blur();
finishTest();
});
EventUtils.sendKey("return");
});
EventUtils.sendKey("return");
});
brace.focus();
}
function finishUp()
{
doc = stylePanel = 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;
doc.title = "Rule View Test";
waitForFocus(openRuleView, content);
}, true);
content.location = "data:text/html,<h1>Some header text</h1>";
}

View File

@ -20,6 +20,7 @@
*
* Contributor(s):
* Joe Walker <jwalker@mozilla.com> (original author)
* Mihai Sucan <mihai.sucan@gmail.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
@ -160,8 +161,6 @@ gcli.addCommand({
}
});
let breakpoints = [];
/**
* 'break' command
*/
@ -180,17 +179,25 @@ gcli.addCommand({
description: gcli.lookup("breaklistDesc"),
returnType: "html",
exec: function(args, context) {
if (breakpoints.length === 0) {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
let breakpoints = dbg.breakpoints;
if (Object.keys(breakpoints).length === 0) {
return gcli.lookup("breaklistNone");
}
let reply = gcli.lookup("breaklistIntro");
reply += "<ol>";
breakpoints.forEach(function(breakpoint) {
for each (let breakpoint in breakpoints) {
let text = gcli.lookupFormat("breaklistLineEntry",
[breakpoint.file, breakpoint.line]);
[breakpoint.location.url,
breakpoint.location.line]);
reply += "<li>" + text + "</li>";
});
};
reply += "</ol>";
return reply;
}
@ -248,14 +255,11 @@ gcli.addCommand({
}
var promise = context.createPromise();
let position = { url: args.file, line: args.line };
dbg.activeThread.setBreakpoint(position, function(aResponse, aBpClient) {
if (aResponse.error) {
promise.resolve(gcli.lookupFormat("breakaddFailed",
[ aResponse.error ]));
dbg.addBreakpoint(position, function(aBreakpoint, aError) {
if (aError) {
promise.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
return;
}
args.client = aBpClient;
breakpoints.push(args);
promise.resolve(gcli.lookup("breakaddAdded"));
});
return promise;
@ -275,17 +279,35 @@ gcli.addCommand({
type: {
name: "number",
min: 0,
max: function() { return breakpoints.length - 1; }
max: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
return Object.keys(dbg.breakpoints).length - 1;
},
},
description: gcli.lookup("breakdelBreakidDesc")
}
],
returnType: "html",
exec: function(args, context) {
let breakpoint = breakpoints.splice(args.breakid, 1)[0];
var promise = context.createPromise();
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
let breakpoints = dbg.breakpoints;
let id = Object.keys(dbg.breakpoints)[args.breakid];
if (!id || !(id in breakpoints)) {
return gcli.lookup("breakNotFound");
}
let promise = context.createPromise();
try {
breakpoint.client.remove(function(aResponse) {
dbg.removeBreakpoint(breakpoints[id], function() {
promise.resolve(gcli.lookup("breakdelRemoved"));
});
} catch (ex) {

View File

@ -255,6 +255,10 @@ breakdelBreakidDesc=Index of breakpoint
# command to explain that a breakpoint was removed.
breakdelRemoved=Breakpoint removed
# LOCALIZATION NOTE (breakNotFound) Used in the output of the 'break del'
# command to explain that the breakpoint was not found.
breakNotFound=Breakpoint was not found
# LOCALIZATION NOTE (consolecloseDesc) A very short description of the
# 'console close' command. This string is designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible.

View File

@ -139,6 +139,7 @@ if [ "$ENABLE_TESTS" ]; then
browser/components/shell/test/Makefile
browser/components/feeds/test/Makefile
browser/components/feeds/test/chrome/Makefile
browser/components/migration/tests/Makefile
browser/components/places/tests/Makefile
browser/components/places/tests/chrome/Makefile
browser/components/places/tests/browser/Makefile

View File

@ -121,8 +121,6 @@ let Storage = {
// want any data from private browsing to show up.
PinnedLinks.resetCache();
BlockedLinks.resetCache();
Pages.update();
}
},
@ -187,11 +185,6 @@ let AllPages = {
*/
_pages: [],
/**
* Tells whether we already added a preference observer.
*/
_observing: false,
/**
* Cached value that tells whether the New Tab Page feature is enabled.
*/
@ -203,12 +196,7 @@ let AllPages = {
*/
register: function AllPages_register(aPage) {
this._pages.push(aPage);
// Add the preference observer if we haven't already.
if (!this._observing) {
this._observing = true;
Services.prefs.addObserver(PREF_NEWTAB_ENABLED, this, true);
}
this._addObserver();
},
/**
@ -238,6 +226,14 @@ let AllPages = {
Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, !!aEnabled);
},
/**
* Returns the number of registered New Tab Pages (i.e. the number of open
* about:newtab instances).
*/
get length() {
return this._pages.length;
},
/**
* Updates all currently active pages but the given one.
* @param aExceptPage The page to exclude from updating.
@ -264,6 +260,15 @@ let AllPages = {
}, this);
},
/**
* Adds a preference observer and turns itself into a no-op after the first
* invokation.
*/
_addObserver: function AllPages_addObserver() {
Services.prefs.addObserver(PREF_NEWTAB_ENABLED, this, true);
this._addObserver = function () {};
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
@ -512,6 +517,8 @@ let Links = {
this._links = aLinks;
executeCallbacks();
}.bind(this));
this._addObserver();
}
},
@ -544,7 +551,32 @@ let Links = {
*/
resetCache: function Links_resetCache() {
this._links = [];
}
},
/**
* Implements the nsIObserver interface to get notified about browser history
* sanitization.
*/
observe: function Links_observe(aSubject, aTopic, aData) {
// Make sure to update open about:newtab instances. If there are no opened
// pages we can just wait for the next new tab to populate the cache again.
if (AllPages.length && AllPages.enabled)
this.populateCache(function () { AllPages.update() }, true);
else
this._links = null;
},
/**
* Adds a sanitization observer and turns itself into a no-op after the first
* invokation.
*/
_addObserver: function Links_addObserver() {
Services.obs.addObserver(this, "browser:purge-session-history", true);
this._addObserver = function () {};
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
/**

View File

@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
-moz-margin-start: 80px;
}
#technicalContent > h2, #expertContent > h2 {
background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
.expander > button {
-moz-padding-start: 20px;
-moz-margin-start: -20px;
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
border: none;
font: inherit;
color: inherit;
cursor: pointer;
}
body[dir="rtl"] #technicalContent > h2,
body[dir="rtl"] #expertContent > h2 {
background-position: right 0;
body[dir="rtl"] .expander > button {
background-position: right center;
}
#technicalContent[collapsed] > h2,
#expertContent[collapsed] > h2{
background-image: url("chrome://browser/skin/section_collapsed.png");
.expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
}
body[dir="rtl"] #technicalContent[collapsed] > h2,
body[dir="rtl"] #expertContent[collapsed] > h2 {
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
body[dir="rtl"] .expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
}

View File

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 791 B

View File

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 776 B

View File

Before

Width:  |  Height:  |  Size: 767 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -146,6 +146,7 @@
direction: ltr;
padding: 0;
-moz-padding-start: 20px;
vertical-align: text-bottom;
}
.bestmatch {

View File

@ -1,8 +0,0 @@
#close {
position: absolute;
top: 0;
right: 0;
width: 32px;
height: 32px;
background: url(KUI-close.png) center center no-repeat;
}

View File

@ -5,14 +5,16 @@ browser.jar:
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutCertError.css (aboutCertError.css)
skin/classic/browser/aboutCertError.css
skin/classic/browser/aboutCertError_sectionCollapsed.png
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
skin/classic/browser/aboutCertError_sectionExpanded.png
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/aboutSyncTabs.css
#endif
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-video.css
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Go-arrow.png
@ -27,9 +29,6 @@ browser.jar:
skin/classic/browser/Privacy-16.png
skin/classic/browser/Privacy-48.png
skin/classic/browser/searchbar.css (searchbar.css)
skin/classic/browser/section_collapsed.png
skin/classic/browser/section_collapsed-rtl.png
skin/classic/browser/section_expanded.png
skin/classic/browser/Secure.png
skin/classic/browser/Security-broken.png
skin/classic/browser/setDesktopBackground.css

View File

@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
-moz-margin-start: 80px;
}
#technicalContent > h2, #expertContent > h2 {
background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
.expander > button {
-moz-padding-start: 20px;
-moz-margin-start: -20px;
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
border: none;
font: inherit;
color: inherit;
cursor: pointer;
}
body[dir="rtl"] #technicalContent > h2,
body[dir="rtl"] #expertContent > h2 {
background-position: right 0;
body[dir="rtl"] .expander > button {
background-position: right center;
}
#technicalContent[collapsed] > h2,
#expertContent[collapsed] > h2{
background-image: url("chrome://browser/skin/section_collapsed.png");
.expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
}
body[dir="rtl"] #technicalContent[collapsed] > h2,
body[dir="rtl"] #expertContent[collapsed] > h2 {
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
body[dir="rtl"] .expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
}

View File

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 791 B

View File

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 776 B

View File

Before

Width:  |  Height:  |  Size: 767 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -148,6 +148,7 @@
direction: ltr;
padding: 0;
-moz-padding-start: 20px;
vertical-align: text-bottom;
}
.bestmatch {

View File

@ -1,8 +0,0 @@
#close {
position: absolute;
top: 0;
left: 0;
width: 32px;
height: 32px;
background: url(KUI-close.png) center center no-repeat;
}

View File

@ -4,14 +4,16 @@ browser.jar:
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutCertError.css (aboutCertError.css)
skin/classic/browser/aboutCertError.css
skin/classic/browser/aboutCertError_sectionCollapsed.png
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
skin/classic/browser/aboutCertError_sectionExpanded.png
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/aboutSyncTabs.css
#endif
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css (browser.css)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-video.css
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/home.png
@ -36,9 +38,6 @@ browser.jar:
skin/classic/browser/searchbar-dropmarker.png
skin/classic/browser/searchbar.css
skin/classic/browser/Search.png
skin/classic/browser/section_collapsed.png
skin/classic/browser/section_collapsed-rtl.png
skin/classic/browser/section_expanded.png
skin/classic/browser/Secure-Glyph-White.png
skin/classic/browser/keyhole-circle.png
skin/classic/browser/Toolbar.png

View File

@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
-moz-margin-start: 80px;
}
#technicalContent > h2, #expertContent > h2 {
background : url("chrome://browser/skin/section_expanded.png") left center no-repeat;
.expander > button {
-moz-padding-start: 20px;
-moz-margin-start: -20px;
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
border: none;
font: inherit;
color: inherit;
cursor: pointer;
}
body[dir="rtl"] #technicalContent > h2,
body[dir="rtl"] #expertContent > h2 {
body[dir="rtl"] .expander > button {
background-position: right center;
}
#technicalContent[collapsed] > h2,
#expertContent[collapsed] > h2{
background-image: url("chrome://browser/skin/section_collapsed.png");
.expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
}
body[dir="rtl"] #technicalContent[collapsed] > h2,
body[dir="rtl"] #expertContent[collapsed] > h2 {
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
body[dir="rtl"] .expander[collapsed] > button {
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
}

View File

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 791 B

View File

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 776 B

View File

Before

Width:  |  Height:  |  Size: 767 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -146,6 +146,7 @@
direction: ltr;
padding: 0;
-moz-padding-start: 20px;
vertical-align: text-bottom;
}
.bestmatch {

View File

@ -1,8 +0,0 @@
#close {
position: absolute;
top: 0;
right: 0;
width: 32px;
height: 32px;
background: url(KUI-close.png) center center no-repeat;
}

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