Merge mozilla-central and tracemonkey.

This commit is contained in:
Chris Leary 2011-07-05 17:30:35 -07:00
commit 289351b012
977 changed files with 29113 additions and 14792 deletions

View File

@ -66,3 +66,4 @@ a95d426422816513477e5863add1b00ac7041dcb AURORA_BASE_20110412
9eae975b3d6fb7748fe5a3c0113d449b1c7cc0b2 AURORA_BASE_20110524
138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14
462c726144bc1fb45b61e774f64ac5d61b4e047c UPDATE_PACKAGING_R14
5eb553dd2ceae5f88d80f27afc5ef3935c5d43b0 AURORA_BASE_20110705

View File

@ -197,6 +197,9 @@ ifdef MOZ_CRASHREPORTER
$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) "$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip"
endif
codesighs:
$(MAKE) -C $(MOZ_BUILD_APP)/installer codesighs
# defined in package-name.mk
export MOZ_SOURCE_STAMP

View File

@ -41,8 +41,6 @@
#include "nsApplicationAccessibleWrap.h"
#include "nsMaiInterfaceText.h"
PRBool nsAccessNodeWrap::gHaveNewTextSignals = PR_FALSE;
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
*/
@ -72,7 +70,6 @@ nsAccessNodeWrap::~nsAccessNodeWrap()
void nsAccessNodeWrap::InitAccessibility()
{
nsAccessNode::InitXPAccessibility();
gHaveNewTextSignals = g_signal_lookup("text-insert", ATK_TYPE_TEXT);
}
void nsAccessNodeWrap::ShutdownAccessibility()

View File

@ -55,12 +55,6 @@ public: // construction, destruction
static void InitAccessibility();
static void ShutdownAccessibility();
/*
* do we have text-remove and text-insert signals if not we need to use
* text-changed see nsAccessibleWrap::FireAtkTextChangedEvent() and
* bug 619002
*/
static PRBool gHaveNewTextSignals;
};
#endif

View File

@ -67,6 +67,9 @@
#include "nsMaiInterfaceDocument.h"
#include "nsMaiInterfaceImage.h"
nsAccessibleWrap::EAvailableAtkSignals nsAccessibleWrap::gAvailableAtkSignals =
eUnknown;
//defined in nsApplicationAccessibleWrap.cpp
extern "C" GType g_atk_hyperlink_impl_type;
@ -1081,7 +1084,7 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
nsString newName;
accessible->GetName(newName);
NS_ConvertUTF16toUTF8 utf8Name(newName);
if (!utf8Name.Equals(atkObj->name))
if (!atkObj->name || !utf8Name.Equals(atkObj->name))
atk_object_set_name(atkObj, utf8Name.get());
break;
@ -1368,25 +1371,29 @@ nsAccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
PRBool isFromUserInput = aEvent->IsFromUserInput();
char* signal_name = nsnull;
if (gHaveNewTextSignals) {
nsAutoString text;
event->GetModifiedText(text);
signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove",
isFromUserInput ? "" : "::system", NULL);
g_signal_emit_by_name(aObject, signal_name, start, length,
NS_ConvertUTF16toUTF8(text).get());
} else {
// XXX remove this code and the gHaveNewTextSignals check when we can
// stop supporting old atk since it doesn't really work anyway
// see bug 619002
signal_name = g_strconcat(isInserted ? "text_changed::insert" :
"text_changed::delete",
isFromUserInput ? "" : kNonUserInputEvent, NULL);
g_signal_emit_by_name(aObject, signal_name, start, length);
}
if (gAvailableAtkSignals == eUnknown)
gAvailableAtkSignals = g_signal_lookup("text-insert", ATK_TYPE_TEXT) ?
eHaveNewAtkTextSignals : eNoNewAtkSignals;
g_free(signal_name);
return NS_OK;
if (gAvailableAtkSignals == eNoNewAtkSignals) {
// XXX remove this code and the gHaveNewTextSignals check when we can
// stop supporting old atk since it doesn't really work anyway
// see bug 619002
signal_name = g_strconcat(isInserted ? "text_changed::insert" :
"text_changed::delete",
isFromUserInput ? "" : kNonUserInputEvent, NULL);
g_signal_emit_by_name(aObject, signal_name, start, length);
} else {
nsAutoString text;
event->GetModifiedText(text);
signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove",
isFromUserInput ? "" : "::system", NULL);
g_signal_emit_by_name(aObject, signal_name, start, length,
NS_ConvertUTF16toUTF8(text).get());
}
g_free(signal_name);
return NS_OK;
}
nsresult

View File

@ -127,6 +127,20 @@ protected:
AtkObject *mAtkObject;
private:
/*
* do we have text-remove and text-insert signals if not we need to use
* text-changed see nsAccessibleWrap::FireAtkTextChangedEvent() and
* bug 619002
*/
enum EAvailableAtkSignals {
eUnknown,
eHaveNewAtkTextSignals,
eNoNewAtkSignals
};
static EAvailableAtkSignals gAvailableAtkSignals;
PRUint16 CreateMaiInterfaces(void);
};

View File

@ -635,6 +635,9 @@ nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
if (!aNode)
return NS_OK;
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
NS_IF_ADDREF(*aAccessible = GetAccessible(node));
@ -1006,12 +1009,13 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
}
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(aNode);
if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation") &&
!content->IsFocusable()) { // For presentation only
// Only create accessible for role of "presentation" if it is focusable --
// in that case we need an accessible in case it gets focused, we
// don't want focus ever to be 'lost'
return nsnull;
if (roleMapEntry && !nsCRT::strcmp(roleMapEntry->roleString, "presentation")) {
// Ignore presentation role if element is focusable (focus event shouldn't
// be ever lost and should be sensible).
if (content->IsFocusable())
roleMapEntry = nsnull;
else
return nsnull;
}
if (weakFrame.IsAlive() && !newAcc && isHTML) { // HTML accessibles

View File

@ -2581,7 +2581,7 @@ nsAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
if (aIndex < 0 || aIndex >= static_cast<PRInt32>(AnchorCount()))
return NS_ERROR_INVALID_ARG;
*aURI = AnchorURIAt(aIndex).get();
nsRefPtr<nsIURI>(AnchorURIAt(aIndex)).forget(aURI);
return NS_OK;
}

View File

@ -1255,19 +1255,18 @@ nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttribute
}
// For the html landmark elements we expose them like we do aria landmarks to
// make AT navigation schemes "just work".
// make AT navigation schemes "just work". Note html:header is redundant as
// a landmark since it usually contains headings. We're not yet sure how the
// web will use html:footer but our best bet right now is as contentinfo.
if (mContent->Tag() == nsAccessibilityAtoms::nav)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("navigation"));
else if (mContent->Tag() == nsAccessibilityAtoms::header)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("banner"));
else if (mContent->Tag() == nsAccessibilityAtoms::footer)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("contentinfo"));
else if (mContent->Tag() == nsAccessibilityAtoms::aside)
nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::xmlroles,
NS_LITERAL_STRING("note"));
NS_LITERAL_STRING("complementary"));
return NS_OK;
}

View File

@ -484,18 +484,22 @@ STDMETHODIMP nsAccessibleWrap::get_accKeyboardShortcut(
/* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut)
{
__try {
if (!pszKeyboardShortcut)
return E_INVALIDARG;
*pszKeyboardShortcut = NULL;
nsAccessible *xpAccessible = GetXPAccessibleFor(varChild);
if (xpAccessible) {
nsAutoString shortcut;
nsresult rv = xpAccessible->GetKeyboardShortcut(shortcut);
if (NS_FAILED(rv))
return E_FAIL;
if (!xpAccessible || xpAccessible->IsDefunct())
return E_FAIL;
*pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(),
shortcut.Length());
return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
}
nsAutoString shortcut;
nsresult rv = xpAccessible->GetKeyboardShortcut(shortcut);
if (NS_FAILED(rv))
return GetHRESULT(rv);
*pszKeyboardShortcut = ::SysAllocStringLen(shortcut.get(),
shortcut.Length());
return *pszKeyboardShortcut ? S_OK : E_OUTOFMEMORY;
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return E_FAIL;
}

View File

@ -673,14 +673,19 @@ nsXULTreeGridRowAccessible::GetName(nsAString& aName)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsITreeColumns> columns;
mTree->GetColumns(getter_AddRefs(columns));
if (columns) {
nsCOMPtr<nsITreeColumn> primaryColumn;
columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
if (primaryColumn)
GetCellName(primaryColumn, aName);
// XXX: the row name sholdn't be a concatenation of cell names (bug 664384).
nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
while (column) {
if (!aName.IsEmpty())
aName.AppendLiteral(" ");
nsAutoString cellName;
GetCellName(column, cellName);
aName.Append(cellName);
column = nsCoreUtils::GetNextSensibleColumn(column);
}
return NS_OK;
}

View File

@ -103,7 +103,7 @@
<button id="btn_namefromcontent" title="title">1</button>
<!-- button, no name from content, ARIA role overrides this rule -->
<button id="btn_nonamefromcontent" role="presentation">1</button>
<button id="btn_nonamefromcontent" role="img">1</button>
<!-- button, no content, name from @title -->
<button id="btn_title" title="title"></button>

View File

@ -88,8 +88,7 @@
title="title"><img alt="img title" /></a>
<!-- no name from content, ARIA role overrides this rule -->
<a id="nonamefromcontent" href="mozilla.org"
role="presentation">1</a>
<a id="nonamefromcontent" href="mozilla.org" role="img">1</a>
<br/>
<!-- no content, name from @title -->

View File

@ -86,7 +86,7 @@
}
}
function tableTester(aID)
function tableTester(aID, aIsTable, aCol1ID, aCol2ID)
{
this.DOMNode = getNode(aID);
@ -98,7 +98,7 @@
this.check = function tableTester_check(aEvent)
{
var tree = {
role: ROLE_TREE_TABLE,
role: aIsTable ? ROLE_TABLE : ROLE_TREE_TABLE,
children: [
{
role: ROLE_LIST
@ -109,15 +109,15 @@
{
role: ROLE_GRID_CELL,
children: [],
name: "row0_col1"
name: "row0_" + aCol1ID
},
{
role: ROLE_GRID_CELL,
children: [],
name: "row0_col2"
name: "row0_" + aCol2ID
}
],
name: "row0_col1"
name: "row0_" + aCol1ID + " row0_" + aCol2ID
},
{
role: ROLE_ROW,
@ -125,15 +125,15 @@
{
role: ROLE_GRID_CELL,
children: [],
name: "row1_col1"
name: "row1_" + aCol1ID
},
{
role: ROLE_GRID_CELL,
children: [],
name: "row1_col2"
name: "row1_" + aCol2ID
}
],
name: "row1_col1"
name: "row1_" + aCol1ID + " row1_" + aCol2ID
}
]
};
@ -152,7 +152,8 @@
var gQueue = new eventQueue(EVENT_REORDER);
gQueue.push(new treeTester("tree"));
gQueue.push(new tableTester("table"));
gQueue.push(new tableTester("table", true, "t_col1", "t_col2"));
gQueue.push(new tableTester("treetable", false, "tt_col1", "tt_col2"));
gQueue.invoke(); // Will call SimpleTest.finish()
}
@ -170,7 +171,12 @@
title="Treegrid row accessible shouldn't inherit name from tree accessible">
Mozilla Bug 546812
</a>
<p id="display"></p>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=664376"
title="Table rows of XUL trees no longer containing cell content as accessible name">
Mozilla Bug 664376
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
@ -188,8 +194,16 @@
<tree id="table" flex="1">
<treecols>
<treecol id="col1" flex="1" label="column" primary="true"/>
<treecol id="col2" flex="1" label="column 2"/>
<treecol id="t_col1" flex="1" label="column"/>
<treecol id="t_col2" flex="1" label="column 2"/>
</treecols>
<treechildren/>
</tree>
<tree id="treetable" flex="1">
<treecols>
<treecol id="tt_col1" flex="1" label="column" primary="true"/>
<treecol id="tt_col2" flex="1" label="column 2"/>
</treecols>
<treechildren/>
</tree>

View File

@ -57,6 +57,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=529289
is(accessibleTable.getCellAt(0,0).firstChild.name, "hi", "no cell");
}
//////////////////////////////////////////////////////////////////////////
// test gEmptyRoleMap
testRole("cell", ROLE_NOTHING);
@ -67,10 +68,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=529289
for (a in abstract_roles)
testRole(abstract_roles[a], ROLE_SECTION);
//////////////////////////////////////////////////////////////////////////
// misc roles
testRole("scrollbar", ROLE_SCROLLBAR);
testRole("dir", ROLE_LIST);
//////////////////////////////////////////////////////////////////////////
// test document role map update
var testDoc = getAccessible(document, [nsIAccessibleDocument]);
testRole(testDoc, ROLE_DOCUMENT);

View File

@ -31,9 +31,8 @@
// Some AT may look for this
testAttrs("nav", {"xml-roles" : "navigation"}, true);
testAttrs("header", {"xml-roles" : "banner"}, true);
testAttrs("footer", {"xml-roles" : "contentinfo"}, true);
testAttrs("aside", {"xml-roles" : "note"}, true);
testAttrs("aside", {"xml-roles" : "complementary"}, true);
testAttrs("main", {"xml-roles" : "main"}, true); // ARIA override
// And some AT may look for this
@ -63,6 +62,11 @@
title="Map <article> like we do aria role article">
Mozilla Bug 613502
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=610650"
title="Change implementation of HTML5 landmark elements to conform">
Mozilla Bug 610650
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">

View File

@ -50,6 +50,7 @@ _TEST_FILES =\
$(warning test_applicationacc.xul temporarily disabled, see bug 561508) \
test_aria_globals.html \
test_aria_imgmap.html \
test_aria_presentation.html \
test_button.xul \
test_combobox.xul \
test_cssoverflow.html \

View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<title>Test accessible tree when ARIA role presentation is used</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript">
function doTest()
{
// Presentation role don't allow accessible.
var tree =
{ SECTION: [ // container
{ TEXT_LEAF: [ ] } // child text of presentation node
] };
testAccessibleTree("div_cnt", tree);
// Focusable element, presentation role is ignored.
tree =
{ SECTION: [ // container
{ PUSHBUTTON: [ // button
{ TEXT_LEAF: [ ] }
] }
] };
testAccessibleTree("btn_cnt", tree);
// Presentation table, no table structure is exposed.
tree =
{ SECTION: [ // container
{ TEXT_LEAF: [ ] } // cell text
] };
testAccessibleTree("tbl_cnt", tree);
// Focusable table, presentation role is ignored.
tree =
{ SECTION: [ // container
{ TABLE: [ // table
{ ROW: [ // tr
{ CELL: [ //td
{ TEXT_LEAF: [ ] }
] }
] }
] }
] };
testAccessibleTree("tblfocusable_cnt", tree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=548291"
title="Accessible tree of ARIA image maps">
Mozilla Bug 548291
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=666504"
title="Ignore role presentation on focusable elements">
Mozilla Bug 666504
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="div_cnt"><div role="presentation">text</div></div>
<div id="btn_cnt"><button role="presentation">btn</button></div>
<div id="tbl_cnt">
<table role="presentation">
<tr>
<td>cell</td>
</tr>
</table>
</div>
<div id="tblfocusable_cnt">
<table role="presentation" tabindex="0">
<tr>
<td>cell</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -18,7 +18,11 @@ function nsTreeTreeView()
];
}
function nsTreeView() { }
function nsTreeView()
{
this.mTree = null;
this.mData = [];
}
nsTreeView.prototype =
{
@ -205,8 +209,6 @@ nsTreeView.prototype =
return rowIdx;
},
mTree: null,
mData: [],
mCyclerStates: [
createAtom("cyclerState1"),
createAtom("cyclerState2"),

View File

@ -54,8 +54,12 @@ EXTENSIONS = \
$(NULL)
define _INSTALL_EXTENSION
cd $(srcdir)/$(dir) && \
$(ZIP) -r9XD $(DISTROEXT)/$(dir).xpi *
$(NSINSTALL) -D $(dir) && \
$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(srcdir)/$(dir)/install.rdf.in > $(dir)/install.rdf && \
cd $(dir) && \
$(ZIP) -r9XD $(DISTROEXT)/$(dir).xpi install.rdf && \
cd $(srcdir)/$(dir) && \
$(ZIP) -r9XD $(DISTROEXT)/$(dir).xpi * -x install.rdf.in
endef # do not remove the blank line!

View File

@ -1,5 +1,7 @@
<?xml version="1.0"?>
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
@ -13,7 +15,7 @@
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.5</em:minVersion>
<em:maxVersion>6.0</em:maxVersion>
<em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
</Description>
</em:targetApplication>

View File

@ -567,6 +567,7 @@ pref("plugins.hide_infobar_for_missing_plugin", false);
pref("plugins.hide_infobar_for_outdated_plugin", false);
#ifdef XP_MACOSX
pref("plugins.use_layers", false);
pref("plugins.hide_infobar_for_carbon_failure_plugin", false);
#endif

View File

@ -108,13 +108,6 @@
key="printKb"
command="cmd_print"/>
<menuseparator/>
<menuitem id="menu_import"
label="&import.label;"
accesskey="&import.accesskey;"
oncommand="BrowserImport();"/>
#ifndef XP_MACOSX
<menuseparator/>
#endif
<menuitem id="goOfflineMenuitem"
label="&goOfflineCmd.label;"
accesskey="&goOfflineCmd.accesskey;"

View File

@ -215,15 +215,17 @@ var ctrlTab = {
if (this._tabList)
return this._tabList;
let list = gBrowser.visibleTabs;
if (this._closing)
this.detachTab(this._closing, list);
// Using gBrowser.tabs instead of gBrowser.visibleTabs, as the latter
// exlcudes closing tabs, breaking the following loop in case the the
// selected tab is closing.
let list = Array.filter(gBrowser.tabs, function (tab) !tab.hidden);
// Rotate the list until the selected tab is first
while (!list[0].selected)
list.push(list.shift());
list = list.filter(function (tab) !tab.closing);
if (this.recentlyUsedLimit != 0) {
let recentlyUsedTabs = this._recentlyUsedTabs;
if (this.recentlyUsedLimit > 0)
@ -370,11 +372,10 @@ var ctrlTab = {
else
this._recentlyUsedTabs.push(aTab);
},
detachTab: function ctrlTab_detachTab(aTab, aTabs) {
var tabs = aTabs || this._recentlyUsedTabs;
var i = tabs.indexOf(aTab);
detachTab: function ctrlTab_detachTab(aTab) {
var i = this._recentlyUsedTabs.indexOf(aTab);
if (i >= 0)
tabs.splice(i, 1);
this._recentlyUsedTabs.splice(i, 1);
},
open: function ctrlTab_open() {
@ -498,10 +499,8 @@ var ctrlTab = {
return;
}
this._closing = aTab;
this._tabList = null;
this.updatePreviews();
this._closing = null;
if (this.selected.hidden)
this.advanceFocus(false);

View File

@ -519,13 +519,6 @@ var gPopupBlockerObserver = {
else
blockedPopupAllowSite.removeAttribute("disabled");
var item = aEvent.target.lastChild;
while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
var next = item.previousSibling;
item.parentNode.removeChild(item);
item = next;
}
var foundUsablePopupURI = false;
var pageReport = gBrowser.pageReport;
if (pageReport) {
@ -588,6 +581,13 @@ var gPopupBlockerObserver = {
onPopupHiding: function (aEvent) {
if (aEvent.target.anchorNode.id == "page-report-button")
aEvent.target.anchorNode.removeAttribute("open");
let item = aEvent.target.lastChild;
while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
let next = item.previousSibling;
item.parentNode.removeChild(item);
item = next;
}
},
showBlockedPopup: function (aEvent)
@ -2617,24 +2617,6 @@ function PageProxyClickHandler(aEvent)
middleMousePaste(aEvent);
}
function BrowserImport()
{
#ifdef XP_MACOSX
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("Browser:MigrationWizard");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/migration/migration.xul",
"migration", "centerscreen,chrome,resizable=no");
}
#else
window.openDialog("chrome://browser/content/migration/migration.xul",
"migration", "modal,centerscreen,chrome,resizable=no");
#endif
}
/**
* Handle load of some pages (about:*) so that we can make modifications
* to the DOM for unprivileged pages.
@ -2999,9 +2981,8 @@ function FillInHTMLTooltip(tipElement)
XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
}
if (lookingForSVGTitle &&
!(tipElement instanceof SVGElement &&
tipElement.parentNode instanceof SVGElement &&
!(tipElement.parentNode instanceof SVGForeignObjectElement))) {
(!(tipElement instanceof SVGElement) ||
tipElement.parentNode.nodeType == Node.DOCUMENT_NODE)) {
lookingForSVGTitle = false;
}
if (lookingForSVGTitle) {
@ -5481,7 +5462,7 @@ function hrefAndLinkNodeForClickEvent(event)
// If there is no linkNode, try simple XLink.
let href, baseURI;
node = event.target;
while (node) {
while (node && !href) {
if (node.nodeType == Node.ELEMENT_NODE) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href)
@ -8135,8 +8116,6 @@ let gPrivateBrowsingUI = {
this._setPBMenuTitle("stop");
document.getElementById("menu_import").setAttribute("disabled", "true");
// Disable the Clear Recent History... menu item when in PB mode
// temporary fix until bug 463607 is fixed
document.getElementById("Tools:Sanitize").setAttribute("disabled", "true");
@ -8184,8 +8163,6 @@ let gPrivateBrowsingUI = {
gURLBar.editor.transactionManager.clear();
}
document.getElementById("menu_import").removeAttribute("disabled");
// Re-enable the Clear Recent History... menu item on exit of PB mode
// temporary fix until bug 463607 is fixed
document.getElementById("Tools:Sanitize").removeAttribute("disabled");

View File

@ -701,14 +701,10 @@ var InspectorUI = {
if (parentNode.defaultView) {
return parentNode.defaultView.frameElement;
}
if (this.embeddedBrowserParents) {
let skipParent = this.embeddedBrowserParents[node];
// HTML element? could be iframe?
if (skipParent)
return skipParent;
} else // parent is document element, but no window at defaultView.
return null;
} else if (!parentNode.localName) {
// parent is document element, but no window at defaultView.
return null;
}
if (!parentNode.localName) {
return null;
}
return parentNode;
@ -722,25 +718,20 @@ var InspectorUI = {
if (node.contentDocument) {
// then the node is a frame
if (index == 0) {
if (!this.embeddedBrowserParents)
this.embeddedBrowserParents = {};
let skipChild = node.contentDocument.documentElement;
this.embeddedBrowserParents[skipChild] = node;
return skipChild; // the node's HTMLElement
return node.contentDocument.documentElement; // the node's HTMLElement
}
return null;
}
if (node instanceof GetSVGDocument) {
// then the node is a frame
if (index == 0) {
if (!this.embeddedBrowserParents)
this.embeddedBrowserParents = {};
let skipChild = node.getSVGDocument().documentElement;
this.embeddedBrowserParents[skipChild] = node;
return skipChild; // the node's SVGElement
let svgDocument = node.getSVGDocument();
if (svgDocument) {
// then the node is a frame
if (index == 0) {
return svgDocument.documentElement; // the node's SVGElement
}
return null;
}
return null;
}
let child = null;

View File

@ -125,8 +125,8 @@
</hbox>
</row>
<row id="passwordRow" align="center">
<label value="&signIn.password.label;"
accesskey="&signIn.password.accesskey;"
<label value="&setup.choosePassword.label;"
accesskey="&setup.choosePassword.accesskey;"
control="weavePassword"/>
<textbox id="weavePassword"
type="password"

View File

@ -96,7 +96,7 @@
<getter><![CDATA[
return Array.filter(this.tabs, function(tab) {
return !tab.hidden && !tab.closing;
}, this);
});
]]></getter>
</property>
<field name="mURIFixup" readonly="true">
@ -947,7 +947,15 @@
this._tabAttrModified(this.mCurrentTab);
// Adjust focus
oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
do {
// When focus is in the tab bar, retain it there.
if (document.activeElement == oldTab) {
// We need to explicitly focus the new tab, because
// tabbox.xml does this only in some cases.
this.mCurrentTab.focus();
break;
}
// If there's a tabmodal prompt showing, focus it.
if (newBrowser.hasAttribute("tabmodalPromptShowing")) {
@ -961,7 +969,6 @@
// Focus the location bar if it was previously focused for that tab.
// In full screen mode, only bother making the location bar visible
// if the tab is a blank one.
oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
if (newBrowser._urlbarFocused && gURLBar) {
// Explicitly close the popup if the URL bar retains focus
@ -2005,13 +2012,18 @@
in the current window, in which case this will do nothing. -->
<method name="replaceTabWithWindow">
<parameter name="aTab"/>
<parameter name="aOptions"/>
<body>
<![CDATA[
if (this.tabs.length == 1)
return null;
var options = "chrome,dialog=no,all";
for (var name in aOptions)
options += "," + name + "=" + aOptions[name];
// tell a new window to take the "dropped" tab
return window.openDialog(getBrowserURL(), "_blank", "dialog=no,all", aTab);
return window.openDialog(getBrowserURL(), "_blank", options, aTab);
]]>
</body>
</method>
@ -3298,6 +3310,17 @@
let canvas = tabPreviews.capture(tab, false);
dt.setDragImage(canvas, 0, 0);
// _dragOffsetX/Y give the coordinates that the mouse should be
// positioned relative to the corner of the new window created upon
// dragend such that the mouse appears to have the same position
// relative to the corner of the dragged tab.
function clientX(ele) ele.getBoundingClientRect().left;
let tabOffsetX = clientX(tab) -
clientX(this.children[0].pinned ? this.children[0] : this);
tab._dragOffsetX = event.screenX - window.screenX - tabOffsetX;
tab._dragOffsetY = event.screenY - window.screenY;
event.stopPropagation();
]]></handler>
@ -3477,6 +3500,11 @@
}
}
}
// these offsets are only used in dragend, but we need to free them here
// as well
delete draggedTab._dragOffsetX;
delete draggedTab._dragOffsetY;
]]></handler>
<handler event="dragend"><![CDATA[
@ -3491,6 +3519,7 @@
// Disable detach within the browser toolbox
var eX = event.screenX;
var eY = event.screenY;
var wX = window.screenX;
// check if the drop point is horizontally within the window
if (eX > wX && eX < (wX + window.outerWidth)) {
@ -3498,13 +3527,45 @@
// also avoid detaching if the the tab was dropped too close to
// the tabbar (half a tab)
let endScreenY = bo.screenY + 1.5 * bo.height;
let eY = event.screenY;
if (eY < endScreenY && eY > window.screenY)
return;
}
var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
this.tabbrowser.replaceTabWithWindow(draggedTab);
// screen.availLeft et. al. only check the screen that this window is on,
// but we want to look at the screen the tab is being dropped onto.
var sX = {}, sY = {}, sWidth = {}, sHeight = {};
Cc["@mozilla.org/gfx/screenmanager;1"]
.getService(Ci.nsIScreenManager)
.screenForRect(eX, eY, 1, 1)
.GetAvailRect(sX, sY, sWidth, sHeight);
// ensure new window entirely within screen
var winWidth = Math.min(window.outerWidth, sWidth.value);
var winHeight = Math.min(window.outerHeight, sHeight.value);
var left = Math.min(Math.max(eX - draggedTab._dragOffsetX, sX.value),
sX.value + sWidth.value - winWidth);
var top = Math.min(Math.max(eY - draggedTab._dragOffsetY, sY.value),
sY.value + sHeight.value - winHeight);
delete draggedTab._dragOffsetX;
delete draggedTab._dragOffsetY;
if (this.tabbrowser.tabs.length == 1) {
// resize _before_ move to ensure the window fits the new screen. if
// the window is too large for its screen, the window manager may do
// automatic repositioning.
window.resizeTo(winWidth, winHeight);
window.moveTo(left, top);
window.focus();
} else {
this.tabbrowser.replaceTabWithWindow(draggedTab, { screenX: left,
screenY: top,
#ifndef XP_WIN
outerWidth: winWidth,
outerHeight: winHeight
#endif
});
}
event.stopPropagation();
]]></handler>
@ -3670,7 +3731,7 @@
if (this.mOverCloseButton) {
event.stopPropagation();
}
else {
else if (this.selected) {
this.style.MozUserFocus = 'ignore';
this.clientTop; // just using this to flush style updates
}

View File

@ -67,8 +67,7 @@ var resize = {
// Parameters:
// item - The <Item> being dragged
// event - The DOM event that kicks off the drag
// isFauxDrag - (boolean) true if a faux drag, which is used when simply snapping.
function Drag(item, event, isFauxDrag) {
function Drag(item, event) {
Utils.assert(item && (item.isAnItem || item.isAFauxItem),
'must be an item, or at least a faux item');
@ -282,13 +281,16 @@ Drag.prototype = {
Trenches.hideGuides();
this.item.isDragging = false;
if (this.parent && this.parent != this.item.parent)
this.parent.closeIfEmpty();
if (this.parent && this.parent.expanded)
this.parent.arrange();
if (this.item.parent)
this.item.parent.arrange();
if (!this.item.parent) {
if (this.item.isAGroupItem) {
this.item.setZ(drag.zIndex);
drag.zIndex++;

View File

@ -103,7 +103,7 @@ function GroupItem(listOfEls, options) {
if (!rectToBe) {
rectToBe = GroupItems.getBoundingBox(listOfEls);
rectToBe.inset(-30, -30);
rectToBe.inset(-42, -42);
}
var $container = options.container;
@ -249,7 +249,11 @@ function GroupItem(listOfEls, options) {
this._init($container[0]);
// ___ Children
Array.prototype.forEach.call(listOfEls, function(el) {
// We explicitly set dontArrange=true to prevent the groupItem from
// re-arranging its children after a tabItem has been added. This saves us a
// group.arrange() call per child and therefore some tab.setBounds() calls.
options.dontArrange = true;
listOfEls.forEach(function (el) {
self.add(el, options);
});
@ -271,6 +275,9 @@ function GroupItem(listOfEls, options) {
if ($container)
this.setBounds(rectToBe, immediately);
if (!options.immediately && listOfEls.length > 0)
$container.hide().fadeIn();
this._inited = true;
this.save();
@ -645,7 +652,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Options:
// immediately - (bool) if true, no animation will be used
close: function GroupItem_close(options) {
this.removeAll();
this.removeAll({dontClose: true});
GroupItems.unregister(this);
// remove unfreeze event handlers, if item size is frozen
@ -716,7 +723,22 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let closeCenter = this.getBounds().center();
// Find closest tab to make active
let closestTabItem = UI.getClosestTab(closeCenter);
UI.setActive(closestTabItem);
if (closestTabItem)
UI.setActive(closestTabItem);
},
// ----------
// Function: closeIfEmpty
// Closes the group if it's empty, is closable, and autoclose is enabled
// (see pauseAutoclose()). Returns true if the close occurred and false
// otherwise.
closeIfEmpty: function GroupItem_closeIfEmpty() {
if (this.isEmpty() && !UI._closedLastVisibleTab &&
!GroupItems.getUnclosableGroupItemId() && !GroupItems._autoclosePaused) {
this.close();
return true;
}
return false;
},
// ----------
@ -758,13 +780,12 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this._cancelFadeAwayUndoButtonTimer();
// When the last non-empty groupItem is closed and there are no orphan or
// When the last non-empty groupItem is closed and there are no
// pinned tabs then create a new group with a blank tab.
let remainingGroups = GroupItems.groupItems.filter(function (groupItem) {
return (groupItem != self && groupItem.getChildren().length);
});
if (!gBrowser._numPinnedTabs && !GroupItems.getOrphanedTabs().length &&
!remainingGroups.length) {
if (!gBrowser._numPinnedTabs && !remainingGroups.length) {
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
return (groupItem != self && !groupItem.getChildren().length);
});
@ -829,16 +850,17 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let self = this;
if (this.$undoContainer) {
// if there is one or more orphan tabs or there is more than one group
// and other groupS are not empty, fade away the undo button.
let shouldFadeAway = GroupItems.getOrphanedTabs().length > 0;
if (!shouldFadeAway && GroupItems.groupItems.length > 1) {
// if there is more than one group and other groups are not empty,
// fade away the undo button.
let shouldFadeAway = false;
if (GroupItems.groupItems.length > 1) {
shouldFadeAway =
GroupItems.groupItems.some(function(groupItem) {
return (groupItem != self && groupItem.getChildren().length > 0);
});
}
if (shouldFadeAway) {
self.$undoContainer.animate({
color: "transparent",
@ -983,7 +1005,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this._children.splice(index, 0, item);
item.setZ(this.getZ() + 1);
$el.addClass("tabInGroupItem");
if (!wasAlreadyInThisGroupItem) {
item.droppable(false);
@ -992,7 +1013,8 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
item.addSubscriber(this, "close", function() {
let count = self._children.length;
let dontArrange = self.expanded || !self.shouldStack(count);
self.remove(item, {dontArrange: dontArrange});
let dontClose = !item.closedManually && gBrowser._numPinnedTabs > 0;
self.remove(item, {dontArrange: dontArrange, dontClose: dontClose});
if (dontArrange)
self._freezeItemSize(count);
@ -1039,6 +1061,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
//
// Possible options:
// dontArrange - don't rearrange the remaining items
// dontClose - don't close the group even if it normally would
// immediately - don't animate
remove: function GroupItem_remove(a, options) {
try {
@ -1068,7 +1091,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
item.setParent(null);
item.removeClass("tabInGroupItem");
item.removeClass("stacked");
item.isStacked = false;
item.setHidden(false);
@ -1087,7 +1109,15 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
if (typeof item.setResizable == 'function')
item.setResizable(true, options.immediately);
if (!options.dontArrange) {
// if a blank tab is selected while restoring a tab the blank tab gets
// removed. we need to keep the group alive for the restored tab.
if (item.isRemovedAfterRestore)
options.dontClose = true;
let closed = options.dontClose ? false : this.closeIfEmpty();
if (closed)
this._makeClosestTabActive();
else if (!options.dontArrange) {
this.arrange({animate: !options.immediately});
this._unfreezeItemSize({dontArrange: true});
}
@ -1702,7 +1732,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
self.arrange();
var groupItem = drag.info.item.parent;
if (groupItem)
groupItem.remove(drag.info.$el);
groupItem.remove(drag.info.$el, {dontClose: true});
iQ(this.container).removeClass("acceptsDrop");
}
@ -1830,12 +1860,12 @@ let GroupItems = {
nextID: 1,
_inited: false,
_activeGroupItem: null,
_activeOrphanTab: null,
_cleanupFunctions: [],
_arrangePaused: false,
_arrangesPending: [],
_removingHiddenGroups: false,
_delayedModUpdates: [],
_autoclosePaused: false,
minGroupHeight: 110,
minGroupWidth: 125,
@ -2238,84 +2268,56 @@ let GroupItems = {
let activeGroupItem = this.getActiveGroupItem();
// 1. Active group
// 2. Active orphan
// 3. First visible non-app tab (that's not the tab in question), whether it's an
// orphan or not (make a new group if it's an orphan, add it to the group if it's
// not)
// 4. First group
// 5. First orphan that's not the tab in question
// 6. At this point there should be no groups or tabs (except for app tabs and the
// 2. First visible non-app tab (that's not the tab in question)
// 3. First group
// 4. At this point there should be no groups or tabs (except for app tabs and the
// tab in question): make a new group
if (activeGroupItem) {
if (activeGroupItem && !activeGroupItem.hidden) {
activeGroupItem.add(tabItem, options);
return;
}
let orphanTabItem = UI.getActiveOrphanTab();
if (!orphanTabItem) {
let targetGroupItem;
// find first visible non-app tab in the tabbar.
gBrowser.visibleTabs.some(function(tab) {
if (!tab.pinned && tab != tabItem.tab) {
if (tab._tabViewTabItem) {
if (!tab._tabViewTabItem.parent) {
// the first visible tab is an orphan tab, set the orphan tab, and
// create a new group for orphan tab and new tabItem
orphanTabItem = tab._tabViewTabItem;
} else if (!tab._tabViewTabItem.parent.hidden) {
// the first visible tab belongs to a group, add the new tabItem to
// that group
targetGroupItem = tab._tabViewTabItem.parent;
}
let targetGroupItem;
// find first visible non-app tab in the tabbar.
gBrowser.visibleTabs.some(function(tab) {
if (!tab.pinned && tab != tabItem.tab) {
if (tab._tabViewTabItem) {
if (!tab._tabViewTabItem.parent && !tab._tabViewTabItem.parent.hidden) {
// the first visible tab belongs to a group, add the new tabItem to
// that group
targetGroupItem = tab._tabViewTabItem.parent;
}
return true;
}
return false;
});
return true;
}
return false;
});
let visibleGroupItems;
if (!orphanTabItem) {
if (targetGroupItem) {
// add the new tabItem to the first group item
targetGroupItem.add(tabItem);
UI.setActive(targetGroupItem);
return;
} else {
// find the first visible group item
visibleGroupItems = this.groupItems.filter(function(groupItem) {
return (!groupItem.hidden);
});
if (visibleGroupItems.length > 0) {
visibleGroupItems[0].add(tabItem);
UI.setActive(visibleGroupItems[0]);
return;
}
}
let orphanedTabs = this.getOrphanedTabs();
// set the orphan tab, and create a new group for orphan tab and
// new tabItem
if (orphanedTabs.length > 0)
orphanTabItem = orphanedTabs[0];
let visibleGroupItems;
if (targetGroupItem) {
// add the new tabItem to the first group item
targetGroupItem.add(tabItem);
UI.setActive(targetGroupItem);
return;
} else {
// find the first visible group item
visibleGroupItems = this.groupItems.filter(function(groupItem) {
return (!groupItem.hidden);
});
if (visibleGroupItems.length > 0) {
visibleGroupItems[0].add(tabItem);
UI.setActive(visibleGroupItems[0]);
return;
}
}
// create new group for orphan tab and new tabItem
let tabItems;
let newGroupItemBounds;
// the orphan tab would be the same as tabItem when all tabs are app tabs
// and a new tab is created.
if (orphanTabItem && orphanTabItem.tab != tabItem.tab) {
newGroupItemBounds = orphanTabItem.getBounds();
tabItems = [orphanTabItem, tabItem];
} else {
tabItem.setPosition(60, 60, true);
newGroupItemBounds = tabItem.getBounds();
tabItems = [tabItem];
}
// create new group for the new tabItem
tabItem.setPosition(60, 60, true);
let newGroupItemBounds = tabItem.getBounds();
newGroupItemBounds.inset(-40,-40);
let newGroupItem = new GroupItem(tabItems, { bounds: newGroupItemBounds });
let newGroupItem = new GroupItem([tabItem], { bounds: newGroupItemBounds });
newGroupItem.snap();
UI.setActive(newGroupItem);
},
@ -2334,16 +2336,14 @@ let GroupItems = {
// setting the groupItem which will receive new tabs.
//
// Paramaters:
// groupItem - the active <GroupItem> or <null> if no groupItem is active
// (which means we have an orphaned tab selected)
// groupItem - the active <GroupItem>
setActiveGroupItem: function GroupItems_setActiveGroupItem(groupItem) {
Utils.assert(groupItem, "groupItem must be given");
if (this._activeGroupItem)
iQ(this._activeGroupItem.container).removeClass('activeGroupItem');
if (groupItem !== null) {
if (groupItem)
iQ(groupItem.container).addClass('activeGroupItem');
}
iQ(groupItem.container).addClass('activeGroupItem');
this._activeGroupItem = groupItem;
this._save();
@ -2351,23 +2351,14 @@ let GroupItems = {
// ----------
// Function: _updateTabBar
// Hides and shows tabs in the tab bar based on the active groupItem or
// currently active orphan tabItem
// Hides and shows tabs in the tab bar based on the active groupItem
_updateTabBar: function GroupItems__updateTabBar() {
if (!window.UI)
return; // called too soon
let activeOrphanTab;
if (!this._activeGroupItem) {
activeOrphanTab = UI.getActiveOrphanTab();
if (!activeOrphanTab) {
Utils.assert(false, "There must be something to show in the tab bar!");
return;
}
}
Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
let tabItems = this._activeGroupItem == null ?
[activeOrphanTab] : this._activeGroupItem._children;
let tabItems = this._activeGroupItem._children;
gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
},
@ -2381,17 +2372,6 @@ let GroupItems = {
this._updateTabBar();
},
// ----------
// Function: getOrphanedTabs
// Returns an array of all tabs that aren't in a groupItem.
getOrphanedTabs: function GroupItems_getOrphanedTabs() {
var tabs = TabItems.getItems();
tabs = tabs.filter(function(tab) {
return tab.parent == null;
});
return tabs;
},
// ----------
// Function: getNextGroupItemTab
// Paramaters:
@ -2400,7 +2380,6 @@ let GroupItems = {
getNextGroupItemTab: function GroupItems_getNextGroupItemTab(reverse) {
var groupItems = Utils.copy(GroupItems.groupItems);
var activeGroupItem = GroupItems.getActiveGroupItem();
var activeOrphanTab = UI.getActiveOrphanTab();
var tabItem = null;
if (reverse)
@ -2453,11 +2432,6 @@ let GroupItems = {
}
return false;
});
if (!tabItem) {
var orphanedTabs = GroupItems.getOrphanedTabs();
if (orphanedTabs.length > 0)
tabItem = orphanedTabs[0];
}
if (!tabItem) {
var secondGroupItems = groupItems.slice(0, currentIndex);
secondGroupItems.some(function(groupItem) {
@ -2532,7 +2506,7 @@ let GroupItems = {
box.width = 250;
box.height = 200;
new GroupItem([ tab._tabViewTabItem ], { bounds: box });
new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
}
if (shouldUpdateTabBar)
@ -2607,5 +2581,21 @@ let GroupItems = {
return new Point(
Math.max(size.x, GroupItems.minGroupWidth),
Math.max(size.y, GroupItems.minGroupHeight));
},
// ----------
// Function: pauseAutoclose()
// Temporarily disable the behavior that closes groups when they become
// empty. This is used when entering private browsing, to avoid trashing the
// user's groups while private browsing is shuffling things around.
pauseAutoclose: function GroupItems_pauseAutoclose() {
this._autoclosePaused = true;
},
// ----------
// Function: unpauseAutoclose()
// Re-enables the auto-close behavior.
resumeAutoclose: function GroupItems_resumeAutoclose() {
this._autoclosePaused = false;
}
};

View File

@ -164,9 +164,13 @@ Item.prototype = {
},
stop: function() {
drag.info.stop();
drag.info = null;
if (!this.isAGroupItem && !this.parent)
if (!this.isAGroupItem && !this.parent) {
new GroupItem([drag.info.$el], {focusTitle: true});
gTabView.firstUseExperienced = true;
}
drag.info = null;
},
// The minimum the mouse must move after mouseDown in order to move an
// item
@ -179,7 +183,7 @@ Item.prototype = {
out: function() {
let groupItem = drag.info.item.parent;
if (groupItem)
groupItem.remove(drag.info.$el);
groupItem.remove(drag.info.$el, {dontClose: true});
iQ(this.container).removeClass("acceptsDrop");
},
drop: function(event) {
@ -541,9 +545,7 @@ Item.prototype = {
var defaultRadius = Trenches.defaultRadius;
Trenches.defaultRadius = 2 * defaultRadius; // bump up from 10 to 20!
var event = {startPosition:{}}; // faux event
var FauxDragInfo = new Drag(this, event, true);
// true == isFauxDrag
var FauxDragInfo = new Drag(this, {});
FauxDragInfo.snap('none', false);
FauxDragInfo.stop(immediately);

View File

@ -112,69 +112,9 @@ function TabItem(tab, options) {
// ___ drag/drop
// override dropOptions with custom tabitem methods
// This is mostly to support the phantom groupItems.
this.dropOptions.drop = function(e) {
var $target = this.$container;
this.isDropTarget = false;
var phantom = $target.data("phantomGroupItem");
var groupItem = drag.info.item.parent;
if (groupItem) {
groupItem.add(drag.info.$el);
} else {
phantom.removeClass("phantom acceptsDrop");
let opts = {container:phantom, bounds:phantom.bounds(), focusTitle: true};
new GroupItem([$target, drag.info.$el], opts);
}
};
this.dropOptions.over = function(e) {
var $target = this.$container;
this.isDropTarget = true;
$target.removeClass("acceptsDrop");
var phantomMargin = 40;
var groupItemBounds = this.getBounds();
groupItemBounds.inset(-phantomMargin, -phantomMargin);
iQ(".phantom").remove();
var phantom = iQ("<div>")
.addClass("groupItem phantom acceptsDrop")
.css({
position: "absolute",
zIndex: -99
})
.css(groupItemBounds)
.hide()
.appendTo("body");
var defaultRadius = Trenches.defaultRadius;
// Extend the margin so that it covers the case where the target tab item
// is right next to a trench.
Trenches.defaultRadius = phantomMargin + 1;
var updatedBounds = drag.info.snapBounds(groupItemBounds,'none');
Trenches.defaultRadius = defaultRadius;
// Utils.log('updatedBounds:',updatedBounds);
if (updatedBounds)
phantom.css(updatedBounds);
phantom.fadeIn();
$target.data("phantomGroupItem", phantom);
};
this.dropOptions.out = function(e) {
this.isDropTarget = false;
var phantom = this.$container.data("phantomGroupItem");
if (phantom) {
phantom.fadeOut(function() {
iQ(this).remove();
});
}
let groupItem = drag.info.item.parent;
groupItem.add(drag.info.$el);
};
this.draggable();
@ -201,7 +141,6 @@ function TabItem(tab, options) {
}
});
this.setResizable(true, options.immediately);
this.droppable(true);
TabItems.register(this);
@ -289,8 +228,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
return {
bounds: this.getBounds(),
userSize: (Utils.isPoint(this.userSize) ? new Point(this.userSize) : null),
url: this.tab.linkedBrowser.currentURI.spec,
groupID: (this.parent ? this.parent.id : 0),
imageData: imageData,
@ -348,47 +285,33 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
if (self.parent)
self.parent.remove(self, {immediately: true});
self.setBounds(tabData.bounds, true);
if (Utils.isPoint(tabData.userSize))
self.userSize = new Point(tabData.userSize);
let groupItem;
if (tabData.groupID) {
var groupItem = GroupItems.groupItem(tabData.groupID);
if (groupItem) {
groupItem.add(self, {immediately: true});
// if it matches the selected tab or no active tab and the browser
// tab is hidden, the active group item would be set.
if (self.tab == gBrowser.selectedTab ||
(!GroupItems.getActiveGroupItem() && !self.tab.hidden))
UI.setActive(self.parent);
}
groupItem = GroupItems.groupItem(tabData.groupID);
} else {
// When duplicating a non-blank orphaned tab, create a group including both of them.
// This prevents overlaid tabs in Tab View (only one tab appears to be there).
// In addition, as only one active orphaned tab is shown when Tab View is hidden
// and there are two tabs shown after the duplication, it also prevents
// the inactive tab to suddenly disappear when toggling Tab View twice.
//
// Fixes:
// Bug 645653 - Middle-click on reload button to duplicate orphan tabs does not create a group
// Bug 643119 - Ctrl+Drag to duplicate does not work for orphaned tabs
// ... (and any other way of duplicating a non-blank orphaned tab).
if (GroupItems.getActiveGroupItem() == null)
GroupItems.newTab(self, {immediately: true});
groupItem = new GroupItem([], {immediately: true, bounds: tabData.bounds});
}
if (groupItem) {
groupItem.add(self, {immediately: true});
// if it matches the selected tab or no active tab and the browser
// tab is hidden, the active group item would be set.
if (self.tab == gBrowser.selectedTab ||
(!GroupItems.getActiveGroupItem() && !self.tab.hidden))
UI.setActive(self.parent);
}
} else {
// create tab by double click is handled in UI_init().
if (!UI.creatingNewOrphanTab)
GroupItems.newTab(self, {immediately: true});
// create tab group by double click is handled in UI_init().
GroupItems.newTab(self, {immediately: true});
}
self._reconnected = true;
self.save();
self._sendToSubscribers("reconnected");
},
// ----------
// Function: setHidden
// Hide/unhide this item
@ -594,24 +517,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.$container.removeClass(className);
},
// ----------
// Function: setResizable
// If value is true, makes this item resizable, otherwise non-resizable.
// Shows/hides a visible resize handle as appropriate.
setResizable: function TabItem_setResizable(value, immediately) {
var $resizer = iQ('.expander', this.container);
if (value) {
this.resizeOptions.minWidth = TabItems.minTabWidth;
this.resizeOptions.minHeight = TabItems.minTabHeight;
immediately ? $resizer.show() : $resizer.fadeIn();
this.resizable(true);
} else {
immediately ? $resizer.hide() : $resizer.fadeOut();
this.resizable(false);
}
},
// ----------
// Function: makeActive
// Updates this item to visually indicate that it's active.
@ -912,8 +817,7 @@ let TabItems = {
"<img class='cached-thumb' style='display:none'/><canvas moz-opaque/></div>" +
"<div class='favicon'><img/></div>" +
"<span class='tab-title'>&nbsp;</span>" +
"<div class='close'></div>" +
"<div class='expander'></div>";
"<div class='close'></div>";
this._fragment = document.createDocumentFragment();
this._fragment.appendChild(div);
@ -1073,9 +977,6 @@ let TabItems = {
Utils.assertThrow(tab._tabViewTabItem, "should already be linked");
// note that it's ok to unlink an app tab; see .handleTabUnpin
if (tab._tabViewTabItem == UI.getActiveOrphanTab())
UI.setActive(null, { onlyRemoveActiveTab: true });
this.unregister(tab._tabViewTabItem);
tab._tabViewTabItem._sendToSubscribers("close");
tab._tabViewTabItem.$container.remove();
@ -1265,15 +1166,9 @@ let TabItems = {
// Function: storageSanity
// Checks the specified data (as returned by TabItem.getStorageData or loaded from storage)
// and returns true if it looks valid.
// TODO: check everything
// TODO: this is a stub, please implement
storageSanity: function TabItems_storageSanity(data) {
var sane = true;
if (!Utils.isRect(data.bounds)) {
Utils.log('TabItems.storageSanity: bad bounds', data.bounds);
sane = false;
}
return sane;
return true;
},
// ----------

View File

@ -72,6 +72,9 @@ body {
.tab-title {
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.stacked .tab-title {

View File

@ -574,9 +574,7 @@ var Trenches = {
this.trenches.forEach(function(t) {
if (t.el === element)
return;
if (t.parentItem && (t.parentItem.isAFauxItem ||
t.parentItem.isDragging ||
t.parentItem.isDropTarget))
if (t.parentItem && (t.parentItem.isAFauxItem || t.parentItem.isDragging))
return;
t.active = true;
t.calculateActiveRange();
@ -634,7 +632,7 @@ var Trenches = {
for (var i in this.trenches) {
var t = this.trenches[i];
if (!t.active || t.parentItem.isDropTarget)
if (!t.active)
continue;
// newRect will be a new rect, or false
var newRect = t.rectOverlaps(rect,stationaryCorner,assumeConstantSize,keepProportional);

View File

@ -139,10 +139,6 @@ let UI = {
// Used to prevent keypress being handled after quitting search mode.
ignoreKeypressForSearch: false,
// Variable: creatingNewOrphanTab
// Used to keep track of whether we are creating a new oprhan tab or not.
creatingNewOrphanTab: false,
// Variable: _lastOpenedTab
// Used to keep track of the last opened tab.
_lastOpenedTab: null,
@ -197,29 +193,22 @@ let UI = {
self._lastClick = 0;
self._lastClickPositions = null;
} else {
// Create an orphan tab on double click
// Create a group with one tab on double click
if (Date.now() - self._lastClick <= self.DBLCLICK_INTERVAL &&
(self._lastClickPositions.x - self.DBLCLICK_OFFSET) <= e.clientX &&
(self._lastClickPositions.x + self.DBLCLICK_OFFSET) >= e.clientX &&
(self._lastClickPositions.y - self.DBLCLICK_OFFSET) <= e.clientY &&
(self._lastClickPositions.y + self.DBLCLICK_OFFSET) >= e.clientY) {
self.setActive(null);
self.creatingNewOrphanTab = true;
let box =
new Rect(e.clientX - Math.floor(TabItems.tabWidth/2),
e.clientY - Math.floor(TabItems.tabHeight/2),
TabItems.tabWidth, TabItems.tabHeight);
let newTab =
gBrowser.loadOneTab("about:blank", { inBackground: false });
box.inset(-30, -30);
newTab._tabViewTabItem.setBounds(box, true);
newTab._tabViewTabItem.pushAway(true);
self.setActive(newTab._tabViewTabItem);
self.creatingNewOrphanTab = false;
// the bounds of tab item is set and we can zoom in now.
newTab._tabViewTabItem.zoomIn(true);
let opts = {immediately: true, bounds: box};
let groupItem = new GroupItem([], opts);
groupItem.newTab();
self._lastClick = 0;
self._lastClickPositions = null;
@ -422,13 +411,6 @@ let UI = {
}
},
// ----------
// Function: getActiveOrphanTab
// Returns the currently active orphan tab as a <TabItem>
getActiveOrphanTab: function UI_getActiveOrphanTab() {
return (this._activeTab && !this._activeTab.parent) ? this._activeTab : null;
},
// ----------
// Function: setActive
// Sets the active tab item or group item
@ -436,33 +418,18 @@ let UI = {
//
// options
// dontSetActiveTabInGroup bool for not setting active tab in group
// onlyRemoveActiveGroup bool for removing active group
// onlyRemoveActiveTab bool for removing active tab
setActive: function UI_setActive(item, options) {
if (item) {
if (item.isATabItem) {
if (item.parent)
GroupItems.setActiveGroupItem(item.parent);
else
GroupItems.setActiveGroupItem(null);
this._setActiveTab(item);
} else {
GroupItems.setActiveGroupItem(item);
if (!options || !options.dontSetActiveTabInGroup) {
let activeTab = item.getActiveTab()
if (activeTab)
this._setActiveTab(activeTab);
}
}
Utils.assert(item, "item must be given");
if (item.isATabItem) {
GroupItems.setActiveGroupItem(item.parent);
this._setActiveTab(item);
} else {
if (options) {
if (options.onlyRemoveActiveGroup)
GroupItems.setActiveGroupItem(null);
else if (options.onlyRemoveActiveTab)
this._setActiveTab(null);
} else {
GroupItems.setActiveGroupItem(null);
this._setActiveTab(null);
GroupItems.setActiveGroupItem(item);
if (!options || !options.dontSetActiveTabInGroup) {
let activeTab = item.getActiveTab()
if (activeTab)
this._setActiveTab(activeTab);
}
}
},
@ -523,10 +490,6 @@ let UI = {
Storage.saveVisibilityData(gWindow, "true");
let activeGroupItem = null;
if (!UI.getActiveOrphanTab())
activeGroupItem = GroupItems.getActiveGroupItem();
if (zoomOut && currentTab && currentTab._tabViewTabItem) {
item = currentTab._tabViewTabItem;
// If there was a previous currentTab we want to animate
@ -549,7 +512,6 @@ let UI = {
TabItems.resumePainting();
});
} else {
self.setActive(null, { onlyRemoveActiveTab: true });
dispatchEvent(event);
// Flush pending updates
@ -631,8 +593,10 @@ let UI = {
// Pauses the storage activity that conflicts with sessionstore updates and
// private browsing mode switches. Calls can be nested.
storageBusy: function UI_storageBusy() {
if (!this._storageBusyCount)
if (!this._storageBusyCount) {
TabItems.pauseReconnecting();
GroupItems.pauseAutoclose();
}
this._storageBusyCount++;
},
@ -650,6 +614,7 @@ let UI = {
TabItems.resumeReconnecting();
GroupItems._updateTabBar();
GroupItems.resumeAutoclose();
}
},
@ -726,7 +691,7 @@ let UI = {
// if it's an app tab, add it to all the group items
if (tab.pinned)
GroupItems.addAppTab(tab);
else if (self.isTabViewVisible())
else if (self.isTabViewVisible() && !self._storageBusyCount)
self._lastOpenedTab = tab;
};
@ -868,8 +833,7 @@ let UI = {
if (this.isTabViewVisible()) {
if (!this.restoredClosedTab && this._lastOpenedTab == tab &&
tab._tabViewTabItem) {
if (!this.creatingNewOrphanTab)
tab._tabViewTabItem.zoomIn(true);
tab._tabViewTabItem.zoomIn(true);
this._lastOpenedTab = null;
return;
}
@ -917,9 +881,9 @@ let UI = {
}
} else {
// No tabItem; must be an app tab. Base the tab bar on the current group.
// If no current group or orphan tab, figure it out based on what's
// already in the tab bar.
if (!GroupItems.getActiveGroupItem() && !UI.getActiveOrphanTab()) {
// If no current group, figure it out based on what's already in the tab
// bar.
if (!GroupItems.getActiveGroupItem()) {
for (let a = 0; a < gBrowser.tabs.length; a++) {
let theTab = gBrowser.tabs[a];
if (!theTab.pinned) {
@ -930,7 +894,7 @@ let UI = {
}
}
if (GroupItems.getActiveGroupItem() || UI.getActiveOrphanTab())
if (GroupItems.getActiveGroupItem())
GroupItems._updateTabBar();
}
},
@ -979,7 +943,7 @@ let UI = {
let cl = null;
let clDist;
TabItems.getItems().forEach(function (item) {
if (item.parent && item.parent.hidden)
if (!item.parent || item.parent.hidden)
return;
let testDist = tabCenter.distance(item.bounds.center());
if (cl==null || testDist < clDist) {
@ -1224,7 +1188,6 @@ let UI = {
const minMinSize = 15;
let lastActiveGroupItem = GroupItems.getActiveGroupItem();
this.setActive(null, { onlyRemoveActiveGroup: true });
var startPos = { x: e.clientX, y: e.clientY };
var phantom = iQ("<div>")
@ -1317,19 +1280,8 @@ let UI = {
let box = item.getBounds();
if (box.width > minMinSize && box.height > minMinSize &&
(box.width > minSize || box.height > minSize)) {
var bounds = item.getBounds();
// Add all of the orphaned tabs that are contained inside the new groupItem
// to that groupItem.
var tabs = GroupItems.getOrphanedTabs();
var insideTabs = [];
for each(let tab in tabs) {
if (bounds.contains(tab.bounds))
insideTabs.push(tab);
}
let opts = {bounds: bounds, focusTitle: true};
let groupItem = new GroupItem(insideTabs, opts);
let opts = {bounds: item.getBounds(), focusTitle: true};
let groupItem = new GroupItem([], opts);
self.setActive(groupItem);
phantom.remove();
dragOutInfo = null;
@ -1505,9 +1457,9 @@ let UI = {
let unhiddenGroups = GroupItems.groupItems.filter(function(groupItem) {
return (!groupItem.hidden && groupItem.getChildren().length > 0);
});
// no pinned tabs, no visible groups and no orphaned tabs: open a new
// group, a blank tab and return
if (!unhiddenGroups.length && !GroupItems.getOrphanedTabs().length) {
// no pinned tabs and no visible groups: open a new group. open a blank
// tab and return
if (!unhiddenGroups.length) {
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
return (!groupItem.hidden && !groupItem.getChildren().length);
});

View File

@ -6,6 +6,10 @@ function test () {
let doc = gBrowser.contentDocument;
let tooltip = document.getElementById("aHTMLTooltip");
ok(FillInHTMLTooltip(doc.getElementById("svg1"), "should get title"));
is(tooltip.getAttribute("label"), "This is a non-root SVG element title");
ok(FillInHTMLTooltip(doc.getElementById("text1"), "should get title"));
is(tooltip.getAttribute("label"), " This is a title ");

View File

@ -53,7 +53,7 @@ let gTests = [
setup: function() {},
clean: function() {},
event: {},
target: "commonlink",
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
expectedInvokedMethods: [],
preventDefault: false,
},
@ -64,7 +64,7 @@ let gTests = [
clean: function() {},
event: { ctrlKey: true,
metaKey: true },
target: "commonlink",
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
@ -77,17 +77,28 @@ let gTests = [
clean: function() {},
event: { shiftKey: true,
altKey: true },
target: "commonlink",
targets: [ "commonlink", "maplink" ],
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
preventDefault: true,
},
{
desc: "Shift+Alt left click on XLinks",
setup: function() {},
clean: function() {},
event: { shiftKey: true,
altKey: true },
targets: [ "mathxlink", "svgxlink"],
expectedInvokedMethods: [ "saveURL" ],
preventDefault: true,
},
{
desc: "Shift click",
setup: function() {},
clean: function() {},
event: { shiftKey: true },
target: "commonlink",
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
@ -97,17 +108,27 @@ let gTests = [
setup: function() {},
clean: function() {},
event: { altKey: true },
target: "commonlink",
targets: [ "commonlink", "maplink" ],
expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
preventDefault: true,
},
{
desc: "Alt click on XLinks",
setup: function() {},
clean: function() {},
event: { altKey: true },
targets: [ "mathxlink", "svgxlink" ],
expectedInvokedMethods: [ "saveURL" ],
preventDefault: true,
},
{
desc: "Panel click",
setup: function() {},
clean: function() {},
event: {},
target: "panellink",
targets: [ "panellink" ],
expectedInvokedMethods: [ "urlSecurityCheck", "getShortcutOrURI", "loadURI" ],
preventDefault: true,
},
@ -117,7 +138,7 @@ let gTests = [
setup: function() {},
clean: function() {},
event: { button: 1 },
target: "commonlink",
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
@ -133,7 +154,7 @@ let gTests = [
} catch(ex) {}
},
event: { button: 1 },
target: "commonlink",
targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
preventDefault: true,
},
@ -153,7 +174,7 @@ let gTests = [
} catch(ex) {}
},
event: { button: 1 },
target: "emptylink",
targets: [ "emptylink" ],
expectedInvokedMethods: [ "middleMousePaste" ],
preventDefault: true,
},
@ -206,7 +227,7 @@ function test() {
// Click handler used to steal click events.
let gClickHandler = {
handleEvent: function (event) {
let linkId = event.target.id;
let linkId = event.target.id || event.target.localName;
is(event.type, "click",
gCurrentTest.desc + ":Handler received a click event on " + linkId);
@ -223,7 +244,7 @@ let gClickHandler = {
});
if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
is(false, "More than the expected methods have been called");
ok(false, "Wrong number of invoked methods");
gInvokedMethods.forEach(function (method) info(method + " was invoked"));
}
@ -257,35 +278,45 @@ function setupTestBrowserWindow() {
let doc = gTestWin.content.document;
let mainDiv = doc.createElement("div");
mainDiv.innerHTML =
'<a id="commonlink" href="http://mochi.test/moz/">Common link</a>' +
'<a id="panellink" href="http://mochi.test/moz/">Panel link</a>' +
'<a id="emptylink">Empty link</a>';
'<p><a id="commonlink" href="http://mochi.test/moz/">Common link</a></p>' +
'<p><a id="panellink" href="http://mochi.test/moz/">Panel link</a></p>' +
'<p><a id="emptylink">Empty link</a></p>' +
'<p><math id="mathxlink" xmlns="http://www.w3.org/1998/Math/MathML" xlink:type="simple" xlink:href="http://mochi.test/moz/"><mtext>MathML XLink</mtext></math></p>' +
'<p><svg id="svgxlink" xmlns="http://www.w3.org/2000/svg" width="100px" height="50px" version="1.1"><a xlink:type="simple" xlink:href="http://mochi.test/moz/"><text transform="translate(10, 25)">SVG XLink</text></a></svg></p>' +
'<p><map name="map" id="map"><area href="http://mochi.test/moz/" shape="rect" coords="0,0,128,128" /></map><img id="maplink" usemap="#map" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAABGdBTUEAALGPC%2FxhBQAAAOtJREFUeF7t0IEAAAAAgKD9qRcphAoDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGBgwIAAAT0N51AAAAAASUVORK5CYII%3D"/></p>'
doc.body.appendChild(mainDiv);
}
function runNextTest() {
if (gCurrentTest) {
if (!gCurrentTest) {
gCurrentTest = gTests.shift();
gCurrentTest.setup();
}
if (gCurrentTest.targets.length == 0) {
info(gCurrentTest.desc + ": cleaning up...")
gCurrentTest.clean();
gInvokedMethods.length = 0;
if (gTests.length > 0) {
gCurrentTest = gTests.shift();
gCurrentTest.setup();
}
else {
finishTest();
return;
}
}
if (gTests.length > 0) {
gCurrentTest = gTests.shift();
// Move to next target.
gInvokedMethods.length = 0;
let target = gCurrentTest.targets.shift();
info(gCurrentTest.desc + ": starting...");
// Prepare for test.
gCurrentTest.setup();
info(gCurrentTest.desc + ": testing " + target);
// Fire click event.
let target = gTestWin.content.document.getElementById(gCurrentTest.target);
ok(target, gCurrentTest.desc + ": target is valid (" + target.id + ")");
EventUtils.synthesizeMouse(target, 2, 2, gCurrentTest.event, gTestWin.content);
}
else {
// No more tests to run.
finishTest()
}
// Fire click event.
let targetElt = gTestWin.content.document.getElementById(target);
ok(targetElt, gCurrentTest.desc + ": target is valid (" + targetElt.id + ")");
EventUtils.synthesizeMouseAtCenter(targetElt, gCurrentTest.event, gTestWin.content);
}
function finishTest() {

View File

@ -5,7 +5,7 @@ function test() {
gBrowser.addTab();
gBrowser.addTab();
assertTabs(4);
checkTabs(4);
ctrlTabTest([2] , 1, 0);
ctrlTabTest([2, 3, 1], 2, 2);
@ -28,11 +28,21 @@ function test() {
releaseCtrl();
}
assertTabs(3);
{ // test for bug 667314
let tabs = gBrowser.tabs.length;
pressCtrlTab();
pressCtrlTab(true);
EventUtils.synthesizeKey("w", { ctrlKey: true });
is(gBrowser.tabs.length, tabs - 1, "Ctrl+Tab -> Ctrl+W removes the selected tab");
releaseCtrl();
}
gBrowser.addTab();
checkTabs(3);
ctrlTabTest([2, 1, 0], 9, 1);
gBrowser.addTab();
assertTabs(4);
checkTabs(4);
{ // test for bug 445369
selectTabs([1, 2, 0]);
@ -53,12 +63,12 @@ function test() {
"Ctrl+Tab*2 -> Ctrl+W -> Ctrl+Shift+Tab*2 keeps the selected tab");
}
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
assertTabs(2);
checkTabs(2);
ctrlTabTest([1], 1, 0);
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
assertTabs(1);
checkTabs(1);
{ // test for bug 445768
let focusedWindow = document.commandDispatcher.focusedWindow;
@ -89,7 +99,7 @@ function test() {
function isOpen()
ctrlTab.isOpen;
function assertTabs(aTabs) {
function checkTabs(aTabs) {
var tabs = gBrowser.tabs.length;
if (tabs != aTabs) {
while (gBrowser.tabs.length > 1)

View File

@ -15,6 +15,7 @@ function test() {
if (topic != "page-info-dialog-loaded")
return;
Services.obs.removeObserver(observer, topic);
handlePageInfo();
}

View File

@ -82,16 +82,30 @@ function test() {
"focusedWindow after blur in unfocused tab");
is(fm.getFocusedElementForWindow(browser1.contentWindow, false, {}), null, "blur in unfocused tab");
// focusing the url field should switch active focus away from the tab but
// not clear what would be the focus in the tab
// When focus is in the tab bar, it should be retained there
expectFocusShift(function () gBrowser.selectedTab.focus(),
window, gBrowser.selectedTab, true,
"focusing tab element");
expectFocusShift(function () gBrowser.selectedTab = tab1,
window, tab1, true,
"tab change when selected tab element was focused");
expectFocusShift(function () gBrowser.selectedTab = tab2,
window, tab2, true,
"tab change when selected tab element was focused");
expectFocusShift(function () gBrowser.selectedTab.blur(),
window, null, true,
"blurring tab element");
// focusing the url field should switch active focus away from the browser but
// not clear what would be the focus in the browser
button1.focus();
expectFocusShift(function () gURLBar.focus(),
window, gURLBar.inputField, true,
"focusedWindow after url field focused");
is(fm.getFocusedElementForWindow(browser2.contentWindow, false, {}), button2, "url field focused, button in tab");
is(fm.getFocusedElementForWindow(browser2.contentWindow, false, {}), button2, "url field focused, button in browser");
expectFocusShift(function () gURLBar.blur(),
window, null, true,
"focusedWindow after browser focused");
"blurring url field");
// when a chrome element is focused, switching tabs to a tab with a button
// with the current focus should focus the button

View File

@ -54,6 +54,7 @@ _BROWSER_FILES = \
browser_inspector_treePanel_output.js \
browser_inspector_treePanel_input.html \
browser_inspector_treePanel_result.html \
browser_inspector_bug_665880.js \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test()
{
waitForExplicitFinish();
let doc;
let objectNode;
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(setupObjectInspectionTest, content);
}, true);
content.location = "data:text/html,<object style='padding: 100px'><p>foobar</p></object>";
function setupObjectInspectionTest()
{
objectNode = doc.querySelector("object");
ok(objectNode, "we have the object node");
Services.obs.addObserver(runObjectInspectionTest,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runObjectInspectionTest()
{
Services.obs.removeObserver(runObjectInspectionTest,
INSPECTOR_NOTIFICATIONS.OPENED);
executeSoon(function() {
Services.obs.addObserver(performTestComparison,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.inspectNode(objectNode);
});
}
function performTestComparison()
{
Services.obs.removeObserver(performTestComparison,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
is(InspectorUI.selection, objectNode, "selection matches node");
Services.obs.addObserver(finishUp,
INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
}
function finishUp() {
Services.obs.removeObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED);
doc = objectNode = null;
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -100,7 +100,6 @@ _BROWSER_FILES = \
browser_tabview_bug618828.js \
browser_tabview_bug619937.js \
browser_tabview_bug622835.js \
browser_tabview_bug622872.js \
browser_tabview_bug623768.js \
browser_tabview_bug624265.js \
browser_tabview_bug624692.js \
@ -130,7 +129,6 @@ _BROWSER_FILES = \
browser_tabview_bug633788.js \
browser_tabview_bug634077.js \
browser_tabview_bug634085.js \
browser_tabview_bug634158.js \
browser_tabview_bug634672.js \
browser_tabview_bug635696.js \
browser_tabview_bug640765.js \
@ -138,18 +136,19 @@ _BROWSER_FILES = \
browser_tabview_bug642793.js \
browser_tabview_bug643392.js \
browser_tabview_bug644097.js \
browser_tabview_bug645653.js \
browser_tabview_bug648882.js \
browser_tabview_bug649006.js \
browser_tabview_bug649307.js \
browser_tabview_bug649319.js \
browser_tabview_bug650573.js \
browser_tabview_bug651311.js \
browser_tabview_bug654721.js \
browser_tabview_bug654941.js \
browser_tabview_bug655269.js \
browser_tabview_bug656778.js \
browser_tabview_bug656913.js \
browser_tabview_bug662266.js \
browser_tabview_bug663421.js \
browser_tabview_bug665502.js \
browser_tabview_dragdrop.js \
browser_tabview_exit_button.js \
@ -158,7 +157,6 @@ _BROWSER_FILES = \
browser_tabview_group.js \
browser_tabview_launch.js \
browser_tabview_multiwindow_search.js \
browser_tabview_orphaned_tabs.js \
browser_tabview_privatebrowsing.js \
browser_tabview_rtl.js \
browser_tabview_search.js \

View File

@ -72,6 +72,8 @@ function testGroupSwitch(contentWindow, groupItemOne, groupItemTwo) {
"The currently selected tab should be the second tab in the groupItemOne");
// cleanup.
gBrowser.removeTab(groupItemTwo.getChild(0).tab);
gBrowser.removeTab(newTabOne);
closeGroupItem(groupItemTwo, finish);
finish();
}

View File

@ -58,17 +58,15 @@ function onTabViewWindowLoaded() {
gBrowser.unpinTab(appXulTab);
gBrowser.removeTab(appXulTab);
ok(!groupItem.getChildren().length, "the second group is empty");
ok(groupItem.closeIfEmpty(), "the second group was empty");
closeGroupItem(groupItem, function () {
// Verify ending state
is(gBrowser.tabs.length, 1, "we finish with one tab");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
ok(!TabView.isVisible(), "we finish with Tab View hidden");
finish();
});
// Verify ending state
is(gBrowser.tabs.length, 1, "we finish with one tab");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
ok(!TabView.isVisible(), "we finish with Tab View hidden");
finish();
}
window.addEventListener("tabviewhidden", onTabViewHidden, false);

View File

@ -4,37 +4,27 @@
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.show();
}
newWindowWithTabView(function (win) {
registerCleanupFunction(function () win.close());
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
let cw = win.TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
let groupItem = groupItems[0];
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1,
"There is one group item on startup");
is(groupItems.length, 1, "There is one group item on startup");
let groupItem = contentWindow.GroupItems.groupItems[0];
groupItem.addSubscriber(groupItem, "groupHidden", function() {
groupItem.removeSubscriber(groupItem, "groupHidden");
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
is(contentWindow.GroupItems.groupItems.length, 1,
"There is still one group item");
isnot(groupItem.id, contentWindow.GroupItems.groupItems[0].id,
whenTabViewIsHidden(function () {
is(groupItems.length, 1, "There is still one group item");
isnot(groupItem.id, groupItems[0].id,
"The initial group item is not the same as the final group item");
is(gBrowser.tabs.length, 1, "There is only one tab");
ok(!TabView.isVisible(), "Tab View is hidden");
is(win.gBrowser.tabs.length, 1, "There is only one tab");
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
}, win);
// create a new tab
EventUtils.synthesizeKey("t", { accelKey: true });
hideGroupItem(groupItem, function () {
// create a new tab
EventUtils.synthesizeKey("t", { accelKey: true }, cw);
});
});
groupItem.closeAll();
}

View File

@ -58,10 +58,8 @@ function test() {
let onTabViewShow = function() {
newWin.removeEventListener("tabviewshown", onTabViewShow, false);
let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
let contentWindow = newWin.TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 2, "Has two group items");
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphan tabs");
// clean up and finish
newWin.close();

View File

@ -28,15 +28,12 @@ function test() {
EventUtils.synthesizeMouseAtCenter(targetTab, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouseAtCenter(targetTab, {type: 'mouseup'}, cw);
is(cw.GroupItems.groupItems.length, 2, 'there are two groupItems');
is(sourceGroup.getChildren().length, 0, 'source group has no tabs');
is(targetGroup.getChildren().length, 2, 'target group has two tabs');
is(cw.GroupItems.groupItems.length, 1, 'sourceGroup was closed');
isnot(cw.GroupItems.groupItems[0], sourceGroup, 'sourceGroup was closed');
targetGroup.getChild(0).close();
closeGroupItem(sourceGroup, function () {
hideTabView(finish);
});
hideTabView(finish);
}
waitForExplicitFinish();

View File

@ -1,8 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let originalTab;
let orphanedTab;
let contentWindow;
let contentElement;
@ -18,23 +16,17 @@ function test() {
showTabView(function() {
contentWindow = TabView.getContentWindow();
contentElement = contentWindow.document.getElementById("content");
originalTab = gBrowser.visibleTabs[0];
test1();
});
}
function test1() {
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "there is one groupItem");
whenTabViewIsHidden(function() {
showTabView(function() {
is(contentWindow.GroupItems.getOrphanedTabs().length, 1,
"An orphaned tab is created");
hideTabView(function() {
gBrowser.selectedTab = originalTab;
finish();
});
});
is(groupItems.length, 2, "there are two groupItems");
closeGroupItem(groupItems[1], finish);
});
// first click

View File

@ -22,13 +22,11 @@ function test() {
"Tab width is bigger than tab clip width");
is(gBrowser.tabContainer.getAttribute("closebuttons"), "alltabs", "Show button on all tabs.")
let cw = TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
is(groupItems.length, 2, "there are two groupItems");
// clean up and finish
newTabs.forEach(function (tab) gBrowser.removeTab(tab));
closeGroupItem(groupItems[1], finish);
newTabs.forEach(function(tab) {
gBrowser.removeTab(tab);
});
finish();
});
});
}

View File

@ -22,15 +22,16 @@ function test() {
let content = cw.document.getElementById("content");
// drag to create a new group
EventUtils.synthesizeMouse(content, 350, 50, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(content, 400, 50, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(content, 500, 250, {type: "mousemove"}, cw);
EventUtils.synthesizeMouse(content, 500, 250, {type: "mouseup"}, cw);
assertNumberOfGroupItems(2);
// enter a title for the new group
EventUtils.synthesizeKey("t", {}, cw);
EventUtils.synthesizeKey("VK_RETURN", {}, cw);
assertNumberOfGroupItems(2);
let groupItem = cw.GroupItems.groupItems[1];
is(groupItem.getTitle(), "t", "new groupItem's title is correct");
@ -43,12 +44,11 @@ function test() {
groupItem.closeAll();
};
let testDropOnOrphan = function (callback) {
let testDragOutOfGroup = function (callback) {
assertNumberOfGroupItems(1);
let groupItem = cw.GroupItems.groupItems[0];
dragTabOutOfGroup(groupItem);
dragTabOutOfGroup(groupItem);
assertNumberOfGroupItems(2);
// enter a title for the new group
@ -64,7 +64,7 @@ function test() {
registerCleanupFunction(function () win.close());
for (let i = 0; i < 2; i++)
win.gBrowser.loadOneTab("about:blank", {inBackground: true});
win.gBrowser.addTab();
};
let onShow = function (win) {
@ -76,9 +76,7 @@ function test() {
waitForFocus(function () {
testCreateGroup(function () {
testDropOnOrphan(function () {
waitForFocus(finish);
});
testDragOutOfGroup(finish);
});
}, cw);
};

View File

@ -14,11 +14,11 @@ function test() {
// make sure the tab one is selected because undoCloseTab() would remove
// the selected tab if it's a blank tab.
gBrowser.selectedTab = tabOne;
showTabView(onTabViewShown);
showTabView(onTabViewWindowLoaded);
});
}
function onTabViewShown() {
function onTabViewWindowLoaded() {
let contentWindow = TabView.getContentWindow();
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There is only one group");
@ -28,7 +28,8 @@ function onTabViewShown() {
ok(TabView.isVisible(), "Tab View is still visible after removing a tab");
is(groupItems[0].getChildren().length, 2, "The group has two tab items");
restoreTab(function (tabTwo) {
tabTwo = undoCloseTab(0);
whenTabIsReconnected(tabTwo, function() {
ok(TabView.isVisible(), "Tab View is still visible after restoring a tab");
is(groupItems[0].getChildren().length, 3, "The group still has three tab items");
@ -40,3 +41,18 @@ function onTabViewShown() {
});
});
}
// ----------
function whenTabIsReconnected(tab, callback) {
let tabItem = tab._tabViewTabItem;
if (tabItem._reconnected) {
callback();
return;
}
tabItem.addSubscriber(tabItem, "reconnected", function () {
tabItem.removeSubscriber(tabItem, "reconnected");
callback();
});
}

View File

@ -25,11 +25,12 @@ function test() {
is(gBrowser.visibleTabs.length, 1, "The number of visible tabs is 1");
is(gBrowser.visibleTabs[0], origTab,
"The original tab is the only visible tab");
let groupItem = newTab._tabViewTabItem.parent;
isnot(groupItem.id, newTabGroupItemId,
isnot(newTab._tabViewTabItem.parent.id, newTabGroupItemId,
"The moved tab item has a new group id");
closeGroupItem(groupItem, finish);
// clean up
gBrowser.removeTab(newTab);
finish();
});
}

View File

@ -36,14 +36,12 @@ function test() {
// check state after adding tabItem to targetGroup
is(tabItem.parent, targetGroup, 'tabItem changed groups');
is(sourceGroup.getChildren().length, 0, 'source group has no children');
is(cw.GroupItems.groupItems.length, 1, 'source group was closed automatically');
is(targetGroup.getChildren().length, 2, 'target group has now two children');
// cleanup and finish
closeGroupItem(sourceGroup, function () {
tabItem.close();
hideTabView(finishTest);
});
tabItem.close();
hideTabView(finishTest);
});
}

View File

@ -20,7 +20,8 @@ function test() {
groupItem = createEmptyGroupItem(cw, 200, 200, 20);
cw.UI.setActive(groupItem);
executeSoon(function () hideTabView(onHide, win));
whenTabViewIsHidden(onHide, win);
cw.UI.goToTab(win.gBrowser.tabs[0]);
};
let onHide = function () {
@ -35,7 +36,7 @@ function test() {
is(win.gBrowser.visibleTabs.length, 1, "There is one tab displayed");
is(cw.GroupItems.groupItems.length, 2, "There are two groups still");
waitForFocus(finish);
finish();
});
};

View File

@ -20,6 +20,23 @@ function test() {
return groupItem;
}
let hideGroupItem = function (groupItem, callback) {
groupItem.addSubscriber(groupItem, 'groupHidden', function () {
groupItem.removeSubscriber(groupItem, 'groupHidden');
callback();
});
groupItem.closeAll();
}
let closeGroupItem = function (groupItem, callback) {
afterAllTabsLoaded(function () {
hideGroupItem(groupItem, function () {
groupItem.closeHidden();
callback();
});
});
}
let tests = [];
let next = function () {
@ -189,70 +206,6 @@ function test() {
});
}
// setup: 1 orphan tab
// action: exit panorama
// expected: nothing should happen
let testOrphanTab1 = function () {
let groupItem = getGroupItem(0);
let tabItem = groupItem.getChild(0);
groupItem.remove(tabItem);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(0);
hideTabView(function () {
createGroupItem().add(tabItem);
next();
});
});
}
// setup: 1 orphan tab, 1 non-empty group
// action: close the group
// expected: nothing should happen
let testOrphanTab2 = function () {
let groupItem = getGroupItem(0);
let tabItem = groupItem.getChild(0);
groupItem.remove(tabItem);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(1);
closeGroupItem(newGroupItem, function () {
assertNumberOfGroupItems(0);
createGroupItem().add(tabItem);
hideTabView(next);
});
});
}
// setup: 1 orphan tab, 1 non-empty group
// action: hide the group, exit panorama
// expected: nothing should happen
let testOrphanTab3 = function () {
let groupItem = getGroupItem(0);
let tabItem = groupItem.getChild(0);
groupItem.remove(tabItem);
closeGroupItem(groupItem, function () {
assertNumberOfGroupItems(0);
let newGroupItem = createGroupItem(1);
assertNumberOfGroupItems(1);
hideGroupItem(newGroupItem, function () {
hideTabView(function () {
assertNumberOfGroupItems(0);
createGroupItem().add(tabItem);
next();
});
});
});
}
// setup: 1 non-empty group, 1 empty group
// action: close non-empty group
// expected: empty group is re-used, new tab is created and zoomed into
@ -335,10 +288,6 @@ function test() {
tests.push({name: 'testPinnedTab3', func: testPinnedTab3});
tests.push({name: 'testPinnedTab4', func: testPinnedTab4});
tests.push({name: 'testOrphanTab1', func: testOrphanTab1});
tests.push({name: 'testOrphanTab2', func: testOrphanTab2});
tests.push({name: 'testOrphanTab3', func: testOrphanTab3});
tests.push({name: 'testEmptyGroup1', func: testEmptyGroup1});
tests.push({name: 'testEmptyGroup2', func: testEmptyGroup2});

View File

@ -39,6 +39,10 @@ function test() {
tests.push([tab2, tab1]);
tests.push([tab1]);
// test reordering of empty groups - removes the last tab and causes
// the groupItem to close
tests.push([]);
while (tests.length) {
let test = tests.shift();
@ -59,7 +63,7 @@ function test() {
groupItem.reorderTabsBasedOnTabItemOrder();
}
closeGroupItem(groupItem, testMoveBetweenGroups);
testMoveBetweenGroups();
}
let testMoveBetweenGroups = function () {

View File

@ -1,118 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(part1);
}
// PART 1:
// 1. Create a new tab (called newTab)
// 2. Orphan it. Activate this orphan tab.
// 3. Zoom into it.
function part1(win) {
ok(win.TabView.isVisible(), "Tab View is visible");
let contentWindow = win.document.getElementById("tab-view").contentWindow;
is(win.gBrowser.tabs.length, 1, "In the beginning, there was one tab.");
let [originalTab] = win.gBrowser.visibleTabs;
let originalGroup = contentWindow.GroupItems.getActiveGroupItem();
ok(originalGroup.getChildren().some(function(child) {
return child == originalTab._tabViewTabItem;
}),"The current active group is the one with the original tab in it.");
// Create a new tab and orphan it
let newTab = win.gBrowser.loadOneTab("about:mozilla", {inBackground: true});
let newTabItem = newTab._tabViewTabItem;
ok(originalGroup.getChildren().some(function(child) child == newTabItem),"The new tab was made in the current group");
contentWindow.GroupItems.getActiveGroupItem().remove(newTabItem);
ok(!originalGroup.getChildren().some(function(child) child == newTabItem),"The new tab was orphaned");
newTabItem.pushAway();
// activate this tab item
contentWindow.UI.setActive(newTabItem);
// PART 2: close this orphan tab (newTab)
let part2 = function part2() {
win.removeEventListener("tabviewhidden", part2, false);
is(win.gBrowser.selectedTab, newTab, "We zoomed into that new tab.");
ok(!win.TabView.isVisible(), "Tab View is hidden, because we're looking at the new tab");
newTab.addEventListener("TabClose", function() {
newTab.removeEventListener("TabClose", arguments.callee, false);
win.addEventListener("tabviewshown", part3, false);
executeSoon(function() { win.TabView.toggle(); });
}, false);
win.gBrowser.removeTab(newTab);
}
let secondNewTab;
// PART 3: now back in Panorama, open a new tab via the "new tab" menu item (or equivalent)
// We call this secondNewTab.
let part3 = function part3() {
win.removeEventListener("tabviewshown", part3, false);
ok(win.TabView.isVisible(), "Tab View is visible.");
is(win.gBrowser.tabs.length, 1, "Only one tab again.");
is(win.gBrowser.tabs[0], originalTab, "That one tab is the original tab.");
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "Only one group");
ok(!contentWindow.UI.getActiveOrphanTab(), "There is no active orphan tab.");
ok(win.TabView.isVisible(), "Tab View is visible.");
whenTabViewIsHidden(part4, win);
win.document.getElementById("cmd_newNavigatorTab").doCommand();
}
// PART 4: verify it opened in the original group, and go back into Panorama
let part4 = function part4() {
ok(!win.TabView.isVisible(), "Tab View is hidden");
is(win.gBrowser.tabs.length, 2, "There are two tabs total now.");
is(win.gBrowser.visibleTabs.length, 2, "We're looking at both of them.");
let foundOriginalTab = false;
// we can't use forEach because win.gBrowser.tabs is only array-like.
for (let i = 0; i < win.gBrowser.tabs.length; i++) {
let tab = win.gBrowser.tabs[i];
if (tab === originalTab)
foundOriginalTab = true;
else
secondNewTab = tab;
}
ok(foundOriginalTab, "One of those tabs is the original tab.");
ok(secondNewTab, "We found another tab... this is secondNewTab");
is(win.gBrowser.selectedTab, secondNewTab, "This second new tab is what we're looking at.");
win.addEventListener("tabviewshown", part5, false);
win.TabView.toggle();
}
// PART 5: make sure we only have one group with both tabs now, and finish.
let part5 = function part5() {
win.removeEventListener("tabviewshown", part5, false);
is(win.gBrowser.tabs.length, 2, "There are of course still two tabs.");
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There is one group now");
is(groupItems[0], originalGroup, "It's the original group.");
is(originalGroup.getChildren().length, 2, "It has two children.");
// finish!
win.close();
finish();
}
// Okay, all set up now. Let's get this party started!
afterAllTabItemsUpdated(function() {
win.addEventListener("tabviewhidden", part2, false);
win.TabView.toggle();
}, win);
}

View File

@ -41,6 +41,20 @@ function test() {
return createTab('about:blank');
}
let restoreTab = function (callback) {
let tab = undoCloseTab(0);
if (tab._tabViewTabItem._reconnected) {
afterAllTabsLoaded(callback);
return;
}
tab._tabViewTabItem.addSubscriber(tab, 'reconnected', function () {
tab._tabViewTabItem.removeSubscriber(tab, 'reconnected');
afterAllTabsLoaded(callback);
});
}
let finishTest = function () {
prefix = 'finish';
assertValidPrerequisites();

View File

@ -33,10 +33,13 @@ function test() {
ok(!document.getElementById("context_closeTab").disabled, "The 'Close tab' menu item is enabled");
ok(!document.getElementById("context_openTabInWindow").disabled, "The 'Move to New Window' menu item is enabled");
let newTabTwo = gBrowser.selectedTab;
gBrowser.selected = originalTab;
gBrowser.removeTab(newTabOne);
closeGroupItem(newGroup, finish);
gBrowser.removeTab(newTabOne);
gBrowser.removeTab(newTabTwo);
finish();
});
let newGroup = contentWindow.GroupItems.newGroup();
newGroup.newTab();

View File

@ -9,23 +9,6 @@ function test() {
return cw.GroupItems.groupItems[index];
}
let createOrphan = function (callback) {
let tab = win.gBrowser.loadOneTab('about:blank', {inBackground: true});
afterAllTabsLoaded(function () {
let tabItem = tab._tabViewTabItem;
tabItem.parent.remove(tabItem);
callback(tabItem);
});
}
let hideGroupItem = function (groupItem, callback) {
groupItem.addSubscriber(groupItem, 'groupHidden', function () {
groupItem.removeSubscriber(groupItem, 'groupHidden');
callback();
});
groupItem.closeAll();
}
let newWindow = function (test) {
newWindowWithTabView(function (tvwin) {
registerCleanupFunction(function () {
@ -35,6 +18,11 @@ function test() {
win = tvwin;
cw = win.TabView.getContentWindow();
// setup group items
getGroupItem(0).setSize(200, 200, true);
createGroupItemWithBlankTabs(win, 200, 200, 300, 1);
test();
});
}
@ -45,31 +33,11 @@ function test() {
}
let testDragOnHiddenGroup = function () {
createOrphan(function (orphan) {
let groupItem = getGroupItem(0);
hideGroupItem(groupItem, function () {
let drag = orphan.container;
let drop = groupItem.$undoContainer[0];
let groupItem = getGroupItem(1);
assertNumberOfTabsInGroupItem(groupItem, 1);
EventUtils.synthesizeMouseAtCenter(drag, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mouseup'}, cw);
assertNumberOfTabsInGroupItem(groupItem, 1);
win.close();
newWindow(testDragOnVisibleGroup);
});
});
}
let testDragOnVisibleGroup = function () {
createOrphan(function (orphan) {
let groupItem = getGroupItem(0);
let drag = orphan.container;
let drop = groupItem.container;
hideGroupItem(groupItem, function () {
let drag = groupItem.getChild(0).container;
let drop = groupItem.$undoContainer[0];
assertNumberOfTabsInGroupItem(groupItem, 1);
@ -77,13 +45,30 @@ function test() {
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mouseup'}, cw);
assertNumberOfTabsInGroupItem(groupItem, 2);
assertNumberOfTabsInGroupItem(groupItem, 1);
win.close();
finish();
newWindow(testDragOnVisibleGroup);
});
}
let testDragOnVisibleGroup = function () {
let groupItem = getGroupItem(0);
let drag = getGroupItem(1).getChild(0).container;
let drop = groupItem.container;
assertNumberOfTabsInGroupItem(groupItem, 1);
EventUtils.synthesizeMouseAtCenter(drag, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouseAtCenter(drop, {type: 'mouseup'}, cw);
assertNumberOfTabsInGroupItem(groupItem, 2);
win.close();
finish();
}
waitForExplicitFinish();
newWindow(testDragOnHiddenGroup);
}

View File

@ -39,9 +39,7 @@ function test() {
synthesizeMiddleMouseDrag(tabContainer, 10);
ok(!groupItem.getChild(0), 'tabItem was closed');
closeGroupItem(groupItem, function () {
hideTabView(finish);
});
hideTabView(finish);
}
waitForExplicitFinish();

View File

@ -25,25 +25,20 @@ function onTabViewWindowLoaded(win) {
is(group.getChildren().length, 1, "The group has one child now.");
let tab = group.getChild(0);
function finalize() {
is(contentWindow.GroupItems.getActiveGroupItem(), originalGroup,
"The original group is active.");
is(contentWindow.UI.getActiveTab(), originalTab._tabViewTabItem,
"The original tab is active");
callback();
}
function check() {
if (groupOrTab == 'group') {
group.removeSubscriber(group, "groupHidden", check);
group.closeHidden();
finalize();
} else {
} else
tab.removeSubscriber(tab, "tabRemoved", check);
closeGroupItem(group, finalize);
}
is(contentWindow.GroupItems.getActiveGroupItem(), originalGroup,
"The original group is active.");
is(contentWindow.UI.getActiveTab(), originalTab._tabViewTabItem,
"The original tab is active");
callback();
}
if (groupOrTab == 'group') {
@ -63,4 +58,4 @@ function onTabViewWindowLoaded(win) {
finish();
});
});
}
}

View File

@ -25,6 +25,20 @@ function test() {
return cw.GroupItems.groupItems[index];
}
let restoreTab = function (callback) {
let tab = undoCloseTab(0);
if (tab._tabViewTabItem._reconnected) {
callback();
return;
}
tab._tabViewTabItem.addSubscriber(tab, 'reconnected', function () {
tab._tabViewTabItem.removeSubscriber(tab, 'reconnected');
afterAllTabsLoaded(callback);
});
}
let activateFirstGroupItem = function () {
let activeTabItem = getGroupItem(0).getChild(0);
cw.GroupItems.updateActiveGroupItemAndTabBar(activeTabItem);
@ -77,7 +91,9 @@ function test() {
assertNumberOfTabsInGroup(groupItem, 2);
activateFirstGroupItem();
closeGroupItem(groupItem, finishTest);
gBrowser.removeTab(gBrowser.tabs[1]);
gBrowser.removeTab(gBrowser.tabs[1]);
finishTest();
});
}

View File

@ -33,21 +33,26 @@ function test() {
EventUtils.synthesizeMouseAtCenter(container, {type: "mouseup"}, cw);
ok(aspectRange.contains(getTabItemAspect(tabItem)), "tabItem's aspect is correct");
tabItem.close();
}
let testDragOutOfStackedGroup = function () {
dragTabItem();
testDragOutOfExpandedStackedGroup();
let secondGroup = cw.GroupItems.groupItems[1];
closeGroupItem(secondGroup, testDragOutOfExpandedStackedGroup);
}
let testDragOutOfExpandedStackedGroup = function () {
groupItem.addSubscriber(groupItem, "expanded", function () {
groupItem.removeSubscriber(groupItem, "expanded");
dragTabItem();
closeGroupItem(groupItem, function () hideTabView(finishTest));
});
groupItem.addSubscriber(groupItem, "collapsed", function () {
groupItem.removeSubscriber(groupItem, "collapsed");
let secondGroup = cw.GroupItems.groupItems[1];
closeGroupItem(secondGroup, function () hideTabView(finishTest));
});
groupItem.expand();
@ -64,14 +69,17 @@ function test() {
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(function () {
if (!win.closed)
win.close();
});
registerCleanupFunction(function () win.close());
cw = win.TabView.getContentWindow();
groupItem = createGroupItemWithBlankTabs(win, 200, 200, 10, 10);
groupItem = cw.GroupItems.groupItems[0];
groupItem.setSize(200, 200, true);
for (let i = 0; i < 9; i++)
win.gBrowser.addTab();
ok(groupItem.isStacked(), "groupItem is stacked");
testDragOutOfStackedGroup();
});
}

View File

@ -1,31 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(function (win) {
registerCleanupFunction(function () {
if (!win.closed)
win.close();
});
let tabItem = win.gBrowser.tabs[0]._tabViewTabItem;
tabItem.parent.remove(tabItem);
let cw = win.TabView.getContentWindow();
let container = cw.iQ(tabItem.container);
let expander = cw.iQ('.expander', container);
let bounds = container.bounds();
let halfWidth = bounds.width / 2;
let halfHeight = bounds.height / 2;
let rect = new cw.Rect(bounds.left + halfWidth, bounds.top + halfHeight,
halfWidth, halfHeight);
ok(rect.contains(expander.bounds()), "expander is in the tabItem's bottom-right corner");
win.close();
finish();
});
}

View File

@ -17,19 +17,6 @@ function test() {
return groupItem;
}
let createOrphan = function () {
let tab = gBrowser.loadOneTab('about:blank', {inBackground: true});
registerCleanupFunction(function () {
if (gBrowser.tabs.length > 1)
gBrowser.removeTab(gBrowser.tabs[1])
});
let tabItem = tab._tabViewTabItem;
tabItem.parent.remove(tabItem);
return tabItem;
}
let testSingleGroupItem = function () {
let groupItem = cw.GroupItems.groupItems[0];
is(cw.GroupItems.getActiveGroupItem(), groupItem, "groupItem is active");
@ -38,9 +25,8 @@ function test() {
is(cw.UI.getActiveTab(), tabItem, "tabItem is active");
hideGroupItem(groupItem, function () {
is(cw.GroupItems.getActiveGroupItem(), null, "groupItem is not active");
unhideGroupItem(groupItem, function () {
is(cw.GroupItems.getActiveGroupItem(), groupItem, "groupItem is active again");
is(cw.GroupItems.getActiveGroupItem(), groupItem, "groupItem is still active");
is(cw.UI.getActiveTab(), tabItem, "tabItem is still active");
next();
});
@ -63,22 +49,7 @@ function test() {
});
}
let testOrphanTab = function () {
let groupItem = cw.GroupItems.groupItems[0];
let tabItem = groupItem.getChild(0);
let tabItem2 = createOrphan();
hideGroupItem(groupItem, function () {
is(cw.UI.getActiveTab(), tabItem2, "tabItem2 is active");
unhideGroupItem(groupItem, function () {
cw.UI.setActive(tabItem);
tabItem2.close();
next();
});
});
}
let tests = [testSingleGroupItem, testTwoGroupItems, testOrphanTab];
let tests = [testSingleGroupItem, testTwoGroupItems];
let next = function () {
let test = tests.shift();

View File

@ -1,8 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
let state = {
windows: [{
tabs: [{

View File

@ -1,83 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* Orphans a non-blank tab, duplicates it and checks whether a new group is created with two tabs.
* The original one should be the first tab of the new group.
*
* This prevents overlaid tabs in Tab View (only one tab appears to be there).
* In addition, as only one active orphaned tab is shown when Tab View is hidden
* and there are two tabs shown after the duplication, it also prevents
* the inactive tab to suddenly disappear when toggling Tab View twice.
*
* Covers:
* Bug 645653 - Middle-click on reload button to duplicate orphan tabs does not create a group
* Bug 643119 - Ctrl+Drag to duplicate does not work for orphaned tabs
* ... (and any other way of duplicating a non-blank orphaned tab).
*
* See tabitems.js::_reconnect() for the fix.
*
* Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
*/
function loadedAboutMozilla(tab) {
return tab.linkedBrowser.contentDocument.getElementById('moztext');
}
function test() {
waitForExplicitFinish();
showTabView(function() {
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = TabView.getContentWindow();
is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item on startup.");
let originalGroupItem = contentWindow.GroupItems.groupItems[0];
is(originalGroupItem.getChildren().length, 1, "There is one tab item in that group.");
let originalTabItem = originalGroupItem.getChild(0);
ok(originalTabItem, "The tabitem has been found.");
// close the group => orphan the tab
originalGroupItem.close();
contentWindow.UI.setActive(originalGroupItem);
is(contentWindow.GroupItems.groupItems.length, 0, "There are not any groups now.");
ok(TabView.isVisible(), "Tab View is still shown.");
hideTabView(function() {
ok(!TabView.isVisible(), "Tab View is not shown anymore.");
// load a non-blank page
loadURI('about:mozilla');
afterAllTabsLoaded(function() {
ok(loadedAboutMozilla(originalTabItem.tab), "The original tab loaded about:mozilla.");
// duplicate it
duplicateTabIn(originalTabItem.tab, "tabshift");
afterAllTabsLoaded(function() {
// check
is(gBrowser.selectedTab, originalTabItem.tab, "The selected tab is the original one.");
is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item again.");
let groupItem = contentWindow.GroupItems.groupItems[0];
is(groupItem.getChildren().length, 2, "There are two tab items in that group.");
is(originalTabItem, groupItem.getChild(0), "The first tab item in the group is the original one.");
let otherTab = groupItem.getChild(1);
ok(loadedAboutMozilla(otherTab.tab), "The other tab loaded about:mozilla.");
// clean up
gBrowser.removeTab(otherTab.tab);
is(contentWindow.GroupItems.groupItems.length, 1, "There is one group item after closing the second tab.");
is(groupItem.getChildren().length, 1, "There is only one tab item after closing the second tab.");
is(originalTabItem, groupItem.getChild(0), "The first tab item in the group is still the original one.");
loadURI("about:blank");
afterAllTabsLoaded(function() {
finish();
});
});
});
});
});
}

View File

@ -53,20 +53,10 @@ function testScenarios(win) {
is(cw.GroupItems.getActiveGroupItem(), groupItem2, "second groupItem is active");
is(cw.UI.getActiveTab(), tabItem, "second groupItem's third tab is active");
// create orphan
// drag tab out of group
tabItem = groupItem2.getChild(0);
dragOutOfGroup(tabItem.container);
// move orphan
cw.UI.setActive(groupItem2);
simulateDragDrop(tabItem.container);
assertActiveOrphan(tabItem);
// resize orphan
cw.UI.setActive(groupItem2);
let $resizer = cw.iQ('.iq-resizable-handle', tabItem.container);
simulateDragDrop($resizer[0]);
assertActiveOrphan(tabItem);
is(cw.UI.getActiveTab(), tabItem, "the dragged tab is active");
// drag back into group
dragIntoGroup(tabItem.container);

View File

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let state = {
windows: [{
tabs: [{
entries: [{ url: "about:home" }],
hidden: true,
extData: {"tabview-tab": '{"url":"about:home","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}
},{
entries: [{ url: "about:home" }],
hidden: false,
// this is an existing orphan tab from a previous Fx version and we want
// to make sure this gets transformed into a group
extData: {"tabview-tab": '{"url":"about:home","groupID":0,"bounds":{"left":300,"top":300,"width":200,"height":200}}'},
}],
selected: 2,
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":1}',
"tabview-group":
'{"1":{"bounds":{"left":20,"top":20,"width":200,"height":200},"id":1}}'
}
}]
};
function test() {
waitForExplicitFinish();
newWindowWithState(state, function (win) {
registerCleanupFunction(function () win.close());
showTabView(function () {
let cw = win.TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
is(groupItems.length, 2, "two groupItems");
let [group1, group2] = groupItems;
let bounds1 = new cw.Rect(20, 20, 200, 200);
ok(bounds1.equals(group1.getBounds()), "bounds for group1 are correct");
let bounds2 = new cw.Rect(300, 300, 200, 200);
ok(bounds2.equals(group2.getBounds()), "bounds for group2 are correct");
cw.UI.setActive(group2);
win.gBrowser.loadOneTab("about:blank", {inBackground: true});
let tabItem = group2.getChild(0);
let target = tabItem.container;
EventUtils.synthesizeMouse(target, 10, 10, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouse(target, 20, -200, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouse(target, 10, 10, {type: 'mouseup'}, cw);
is(groupItems.length, 3, "three groupItems");
let latestGroup = groupItems[groupItems.length - 1];
is(tabItem, latestGroup.getChild(0), "dragged tab has its own groupItem");
finish();
}, win);
});
}

View File

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let win, cw, groupItem;
function checkNumberOfGroupItems(num) {
is(cw.GroupItems.groupItems.length, num, "there are " + num + " groupItems");
}
function next() {
if (tests.length)
tests.shift()();
else
finish();
}
// Empty groups should not be closed when toggling Panorama on and off.
function test1() {
hideTabView(function () {
showTabView(function () {
checkNumberOfGroupItems(2);
next();
}, win);
}, win);
}
// Groups should not be closed when their last tab is closed outside of Panorama.
function test2() {
whenTabViewIsHidden(function () {
whenTabViewIsShown(function () {
checkNumberOfGroupItems(2);
next();
}, win);
win.gBrowser.removeTab(win.gBrowser.selectedTab);
}, win);
groupItem.newTab();
}
// Groups should be closed when their last tab is closed.
function test3() {
whenTabViewIsHidden(function () {
showTabView(function () {
let tab = win.gBrowser.tabs[1];
tab._tabViewTabItem.close();
checkNumberOfGroupItems(1);
next();
}, win);
}, win);
win.gBrowser.addTab();
}
// Groups should be closed when their last tab is dragged out.
function test4() {
groupItem = createGroupItemWithBlankTabs(win, 200, 200, 20, 1);
checkNumberOfGroupItems(2);
let tab = win.gBrowser.tabs[1];
let target = tab._tabViewTabItem.container;
waitForFocus(function () {
EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(target, 600, 5, {type: "mousemove"}, cw);
EventUtils.synthesizeMouse(target, 600, 5, {type: "mouseup"}, cw);
checkNumberOfGroupItems(2);
next();
}, win);
}
let tests = [test1, test2, test3, test4];
waitForExplicitFinish();
newWindowWithTabView(function (aWin) {
registerCleanupFunction(function () aWin.close());
win = aWin;
cw = win.TabView.getContentWindow();
groupItem = createEmptyGroupItem(cw, 200, 200, 20);
checkNumberOfGroupItems(2);
next();
});
}

View File

@ -85,7 +85,7 @@ function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
};
groupTwo.addSubscriber(groupTwo, "close", function() {
groupTwo.removeSubscriber(groupTwo, "close");
closeGroupItem(groupOne, finish);
finish();
});
window.addEventListener("tabviewhidden", onTabViewHidden, false);
gBrowser.selectedTab = originalTab;

View File

@ -40,10 +40,6 @@ function checkFirstRun(win) {
is(groupItems.length, 1, "There should be one group");
is(groupItems[0].getChildren().length, 1, "...with one child");
let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
// Welcome tab disabled by bug 626754. To be fixed via bug 626926.
is(orphanTabCount, 0, "There should also be no orphaned tabs");
ok(!experienced(), "we're not experienced");
}
@ -55,9 +51,6 @@ function checkNotFirstRun(win) {
let groupItems = contentWindow.GroupItems.groupItems;
is(groupItems.length, 1, "There should be one group");
is(groupItems[0].getChildren().length, 1, "...with one child");
let orphanTabCount = contentWindow.GroupItems.getOrphanedTabs().length;
is(orphanTabCount, 0, "There should also be no orphaned tabs");
}
function endGame() {

View File

@ -95,7 +95,7 @@ function testGroupItemWithTabItem(contentWindow) {
let endGame = function() {
window.removeEventListener("tabviewhidden", endGame, false);
ok(!TabView.isVisible(), "Tab View is hidden");
closeGroupItem(groupItem, finish);
finish();
};
window.addEventListener("tabviewhidden", endGame, false);

View File

@ -1,83 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let tabViewShownCount = 0;
let timerId;
let newWin;
// ----------
function test() {
waitForExplicitFinish();
// verify initial state
ok(!TabView.isVisible(), "Tab View starts hidden");
// launch tab view for the first time
window.addEventListener("tabviewshown", onTabViewLoadedAndShown, false);
TabView.toggle();
newWindowWithTabView(function() {}, function(win) {
newWin = win;
let onSelect = function(event) {
if (deck != event.target)
return;
let iframe = win.document.getElementById("tab-view");
if (deck.selectedPanel != iframe)
return;
deck.removeEventListener("select", onSelect, true);
whenTabViewIsShown(function() {
executeSoon(function() {
testMethodToHideAndShowTabView(function() {
newWin.document.getElementById("menu_tabview").doCommand();
}, function() {
testMethodToHideAndShowTabView(function() {
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, newWin);
}, finish);
});
});
}, win);
};
let deck = win.document.getElementById("tab-view-deck");
deck.addEventListener("select", onSelect, true);
});
registerCleanupFunction(function () {
window.removeEventListener("tabviewshown", onTabViewLoadedAndShown, false);
if (timerId)
clearTimeout(timerId);
TabView.hide()
newWin.close();
});
}
// ----------
function onTabViewLoadedAndShown() {
window.removeEventListener("tabviewshown", onTabViewLoadedAndShown, false);
// Evidently sometimes isVisible (which is based on the selectedIndex of the
// tabview deck) isn't updated immediately when called from button.doCommand,
// so we add a little timeout here to get outside of the doCommand call.
// If the initial timeout isn't enough, we keep waiting in case it's taking
// longer than expected.
// See bug 594909.
let deck = document.getElementById("tab-view-deck");
let iframe = document.getElementById("tab-view");
ok(iframe, "The tab view iframe exists");
function waitForSwitch() {
if (deck.selectedPanel == iframe) {
ok(TabView.isVisible(), "Tab View is visible. Count: " + tabViewShownCount);
tabViewShownCount++;
// kick off the series
window.addEventListener("tabviewshown", onTabViewShown, false);
window.addEventListener("tabviewhidden", onTabViewHidden, false);
registerCleanupFunction(function () {
window.removeEventListener("tabviewshown", onTabViewShown, false);
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
});
TabView.toggle();
} else {
timerId = setTimeout(waitForSwitch, 10);
}
}
timerId = setTimeout(waitForSwitch, 1);
}
// ----------
function onTabViewShown() {
// add the count to the message so we can track things more easily.
ok(TabView.isVisible(), "Tab View is visible. Count: " + tabViewShownCount);
tabViewShownCount++;
TabView.toggle();
}
// ----------
function onTabViewHidden() {
ok(!TabView.isVisible(), "Tab View is hidden. Count: " + tabViewShownCount);
if (tabViewShownCount == 1) {
document.getElementById("menu_tabview").doCommand();
} else if (tabViewShownCount == 2) {
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true });
} else if (tabViewShownCount == 3) {
window.removeEventListener("tabviewshown", onTabViewShown, false);
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
finish();
}
function testMethodToHideAndShowTabView(executeFunc, callback) {
whenTabViewIsHidden(function() {
ok(!newWin.TabView.isVisible(), "Tab View is not visible after executing the function");
whenTabViewIsShown(function() {
ok(newWin.TabView.isVisible(), "Tab View is visible after executing the function again");
callback();
}, newWin);
executeFunc();
}, newWin);
executeFunc();
}

View File

@ -1,81 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let tabOne;
let newWin;
function test() {
waitForExplicitFinish();
newWindowWithTabView(onTabViewWindowLoaded, function(win) {
newWin = win;
tabOne = newWin.gBrowser.addTab();
});
}
function onTabViewWindowLoaded() {
newWin.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(newWin.TabView.isVisible(), "Tab View is visible");
let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
// 1) the tab should belong to a group, and no orphan tabs
ok(tabOne._tabViewTabItem.parent, "Tab one belongs to a group");
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
// 2) create a group, add a blank tab
let groupItem = createEmptyGroupItem(contentWindow, 300, 300, 200);
let onTabViewHidden = function() {
newWin.removeEventListener("tabviewhidden", onTabViewHidden, false);
// 3) the new group item should have one child and no orphan tab
is(groupItem.getChildren().length, 1, "The group item has an item");
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
let checkAndFinish = function() {
// 4) check existence of stored group data for tab before finishing
let tabData = contentWindow.Storage.getTabData(tabItem.tab, function () {});
ok(tabData && contentWindow.TabItems.storageSanity(tabData) && tabData.groupID,
"Tab two has stored group data");
// clean up and finish the test
newWin.gBrowser.removeTab(tabOne);
newWin.gBrowser.removeTab(tabItem.tab);
whenWindowObservesOnce(newWin, "domwindowclosed", function() {
finish();
});
newWin.close();
};
let tabItem = groupItem.getChild(0);
// the item may not be connected so subscriber would be used in that case.
if (tabItem._reconnected) {
checkAndFinish();
} else {
tabItem.addSubscriber(tabItem, "reconnected", function() {
tabItem.removeSubscriber(tabItem, "reconnected");
checkAndFinish();
});
}
};
newWin.addEventListener("tabviewhidden", onTabViewHidden, false);
// click on the + button
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
ok(newTabButton[0], "New tab button exists");
EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
}
function whenWindowObservesOnce(win, topic, callback) {
let windowWatcher =
Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
function windowObserver(subject, topicName, aData) {
if (win == subject.QueryInterface(Ci.nsIDOMWindow) && topic == topicName) {
windowWatcher.unregisterNotification(windowObserver);
callback();
}
}
windowWatcher.registerNotification(windowObserver);
}

View File

@ -81,19 +81,13 @@ function newWindowWithTabView(shownCallback, loadCallback, width, height) {
let win = window.openDialog(getBrowserURL(), "_blank",
"chrome,all,dialog=no,height=" + winHeight +
",width=" + winWidth);
let onLoad = function() {
win.removeEventListener("load", onLoad, false);
whenWindowLoaded(win, function () {
if (typeof loadCallback == "function")
loadCallback(win);
let onShown = function() {
win.removeEventListener("tabviewshown", onShown, false);
shownCallback(win);
};
win.addEventListener("tabviewshown", onShown, false);
win.TabView.toggle();
}
win.addEventListener("load", onLoad, false);
showTabView(function () shownCallback(win), win);
});
}
// ----------
@ -192,7 +186,7 @@ function whenTabViewIsShown(callback, win) {
function showSearch(callback, win) {
win = win || window;
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let contentWindow = win.TabView.getContentWindow();
if (contentWindow.isSearchEnabled()) {
callback();
return;
@ -206,7 +200,7 @@ function showSearch(callback, win) {
function hideSearch(callback, win) {
win = win || window;
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let contentWindow = win.TabView.getContentWindow();
if (!contentWindow.isSearchEnabled()) {
callback();
return;
@ -220,7 +214,7 @@ function hideSearch(callback, win) {
function whenSearchIsEnabled(callback, win) {
win = win || window;
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let contentWindow = win.TabView.getContentWindow();
if (contentWindow.isSearchEnabled()) {
callback();
return;
@ -236,7 +230,7 @@ function whenSearchIsEnabled(callback, win) {
function whenSearchIsDisabled(callback, win) {
win = win || window;
let contentWindow = win.document.getElementById("tab-view").contentWindow;
let contentWindow = win.TabView.getContentWindow();
if (!contentWindow.isSearchEnabled()) {
callback();
return;
@ -313,21 +307,21 @@ function newWindowWithState(state, callback) {
let opts = "chrome,all,dialog=no,height=800,width=800";
let win = window.openDialog(getBrowserURL(), "_blank", opts);
let numConditions = 2;
let check = function () {
if (!--numConditions)
callback(win);
};
whenWindowLoaded(win, function () {
whenWindowStateReady(win, function () {
afterAllTabsLoaded(check, win);
});
ss.setWindowState(win, JSON.stringify(state), true);
whenDelayedStartupFinished(win, check);
});
let numConditions = 2;
let check = function () {
if (!--numConditions)
callback(win);
};
whenDelayedStartupFinished(win, check);
}
// ----------

View File

@ -1,5 +1,14 @@
<svg width="640px" height="480px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0">
<title>This is a root SVG element's title</title>
<foreignObject>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<svg xmlns="http://www.w3.org/2000/svg" id="svg1">
<title>This is a non-root SVG element title</title>
</svg>
</body>
</html>
</foreignObject>
<text id="text1" x="10px" y="32px" font-size="24px">
This contains only &lt;title&gt;
<title>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1001,7 +1001,7 @@
// undetermined state and then schedule a proper check at the next
// opportunity
this.setProgress(0, -1);
setTimeout(this.updateProgress.bind(this), 0);
this._updateProgressTimeout = setTimeout(this.updateProgress.bind(this), 0);
]]></constructor>
<destructor><![CDATA[
@ -1028,6 +1028,7 @@
this.notification.options.installs.forEach(function(aInstall) {
aInstall.removeListener(this);
}, this);
clearTimeout(this._updateProgressTimeout);
]]></body>
</method>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 289 KiB

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