--HG--
rename : js/src/jsfun.cpp => js/src/vm/ArgumentsObject.cpp
This commit is contained in:
David Anderson 2012-03-19 14:13:34 -07:00
Родитель b1bb3dd801 fa9f7aeced
Коммит 952c9edc86
599 изменённых файлов: 14872 добавлений и 11044 удалений

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

@ -322,20 +322,6 @@ nsAccUtils::GetSelectableContainer(nsAccessible* aAccessible, PRUint64 aState)
return parent;
}
nsAccessible*
nsAccUtils::GetMultiSelectableContainer(nsINode* aNode)
{
nsAccessible* accessible = GetAccService()->GetAccessible(aNode, nsnull);
if (accessible) {
nsAccessible* container = GetSelectableContainer(accessible,
accessible->State());
if (container && container->State() & states::MULTISELECTABLE)
return container;
}
return nsnull;
}
bool
nsAccUtils::IsARIASelected(nsAccessible *aAccessible)
{

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

@ -196,11 +196,6 @@ public:
static nsAccessible* GetSelectableContainer(nsAccessible* aAccessible,
PRUint64 aState);
/**
* Return multi selectable container for the given item.
*/
static nsAccessible *GetMultiSelectableContainer(nsINode *aNode);
/**
* Return true if the DOM node of given accessible has aria-selected="true"
* attribute.

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

@ -298,23 +298,24 @@ already_AddRefed<nsAccessible>
nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent,
nsIPresShell* aPresShell)
{
nsAutoString mapElmName;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, mapElmName);
nsCOMPtr<nsIDOMHTMLMapElement> mapElm;
if (nsIDocument* document = aContent->GetCurrentDoc()) {
mapElm = do_QueryInterface(document->FindImageMap(mapElmName));
}
nsAccessible* accessible = mapElm ?
new nsHTMLImageMapAccessible(aContent,
nsAccUtils::GetDocAccessibleFor(aPresShell),
mapElm) :
nsAccessible* accessible =
new nsHTMLImageAccessibleWrap(aContent,
nsAccUtils::GetDocAccessibleFor(aPresShell));
NS_ADDREF(accessible);
return accessible;
}
already_AddRefed<nsAccessible>
nsAccessibilityService::CreateHTMLImageMapAccessible(nsIContent* aContent,
nsIPresShell* aPresShell)
{
nsAccessible* accessible =
new nsHTMLImageMapAccessible(aContent,
nsAccUtils::GetDocAccessibleFor(aPresShell));
NS_ADDREF(accessible);
return accessible;
}
already_AddRefed<nsAccessible>
nsAccessibilityService::CreateHTMLGroupboxAccessible(nsIContent* aContent,
nsIPresShell* aPresShell)
@ -611,6 +612,28 @@ nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
}
}
void
nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame)
{
nsIPresShell* presShell = aImageFrame->PresContext()->PresShell();
nsDocAccessible* document = GetDocAccessible(presShell->GetDocument());
if (document) {
nsAccessible* accessible =
document->GetAccessible(aImageFrame->GetContent());
if (accessible) {
nsHTMLImageMapAccessible* imageMap = accessible->AsImageMap();
if (imageMap) {
imageMap->UpdateChildAreas();
return;
}
// If image map was initialized after we created an accessible (that'll
// be an image accessible) then recreate it.
RecreateAccessible(presShell, aImageFrame->GetContent());
}
}
}
void
nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
{

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

@ -48,6 +48,8 @@
#include "nsIObserver.h"
class nsImageFrame;
namespace mozilla {
namespace a11y {
@ -109,6 +111,8 @@ public:
CreateHTMLHRAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
virtual already_AddRefed<nsAccessible>
CreateHTMLImageAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
already_AddRefed<nsAccessible>
CreateHTMLImageMapAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
virtual already_AddRefed<nsAccessible>
CreateHTMLLabelAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
virtual already_AddRefed<nsAccessible>
@ -155,6 +159,11 @@ public:
nsIContent* aHTMLListItemContent,
bool aHasBullet);
/**
* Update the image map.
*/
void UpdateImageMap(nsImageFrame* aImageFrame);
virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget);
virtual void PresShellDestroyed(nsIPresShell* aPresShell);

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

@ -1042,47 +1042,42 @@ nsIFrame* nsAccessible::GetBoundsFrame()
return GetFrame();
}
/* void removeSelection (); */
NS_IMETHODIMP nsAccessible::SetSelected(bool aSelect)
{
// Add or remove selection
if (IsDefunct())
return NS_ERROR_FAILURE;
if (State() & states::SELECTABLE) {
nsAccessible* multiSelect =
nsAccUtils::GetMultiSelectableContainer(mContent);
if (!multiSelect) {
return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
nsAccessible* select = nsAccUtils::GetSelectableContainer(this, State());
if (select) {
if (select->State() & states::MULTISELECTABLE) {
if (mRoleMapEntry) {
if (aSelect) {
return mContent->SetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), true);
}
return mContent->UnsetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected, true);
}
return NS_OK;
}
if (mRoleMapEntry) {
if (aSelect) {
return mContent->SetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), true);
}
return mContent->UnsetAttr(kNameSpaceID_None,
nsGkAtoms::aria_selected, true);
}
return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
}
return NS_OK;
}
/* void takeSelection (); */
NS_IMETHODIMP nsAccessible::TakeSelection()
{
// Select only this item
if (IsDefunct())
return NS_ERROR_FAILURE;
if (State() & states::SELECTABLE) {
nsAccessible* multiSelect =
nsAccUtils::GetMultiSelectableContainer(mContent);
if (multiSelect)
multiSelect->ClearSelection();
nsAccessible* select = nsAccUtils::GetSelectableContainer(this, State());
if (select) {
if (select->State() & states::MULTISELECTABLE)
select->ClearSelection();
return SetSelected(true);
}

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

@ -62,6 +62,7 @@ class KeyBinding;
class nsAccessible;
class nsHyperTextAccessible;
class nsHTMLImageAccessible;
class nsHTMLImageMapAccessible;
class nsHTMLLIAccessible;
struct nsRoleMapEntry;
class Relation;
@ -458,6 +459,9 @@ public:
inline bool IsImageAccessible() const { return mFlags & eImageAccessible; }
nsHTMLImageAccessible* AsImage();
bool IsImageMapAccessible() const { return mFlags & eImageMapAccessible; }
nsHTMLImageMapAccessible* AsImageMap();
inline bool IsListControl() const { return mFlags & eListControlAccessible; }
inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
@ -689,11 +693,12 @@ protected:
eHTMLFileInputAccessible = 1 << 8,
eHTMLListItemAccessible = 1 << 9,
eImageAccessible = 1 << 10,
eListControlAccessible = 1 << 11,
eMenuButtonAccessible = 1 << 12,
eMenuPopupAccessible = 1 << 13,
eRootAccessible = 1 << 14,
eTextLeafAccessible = 1 << 15
eImageMapAccessible = 1 << 11,
eListControlAccessible = 1 << 12,
eMenuButtonAccessible = 1 << 13,
eMenuPopupAccessible = 1 << 14,
eRootAccessible = 1 << 15,
eTextLeafAccessible = 1 << 16
};
//////////////////////////////////////////////////////////////////////////////

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

@ -52,15 +52,16 @@
#include "nsImageMap.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageMapAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLImageMapAccessible::
nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc,
nsIDOMHTMLMapElement* aMapElm) :
nsHTMLImageAccessibleWrap(aContent, aDoc), mMapElement(aMapElm)
nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsHTMLImageAccessibleWrap(aContent, aDoc)
{
mFlags |= eImageMapAccessible;
}
////////////////////////////////////////////////////////////////////////////////
@ -103,40 +104,76 @@ nsHTMLImageMapAccessible::AnchorURIAt(PRUint32 aAnchorIndex)
return linkContent ? linkContent->GetHrefURI() : nsnull;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageMapAccessible: public
void
nsHTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
{
nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
// If image map is not initialized yet then we trigger one time more later.
nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
if (!imageMapObj)
return;
bool doReorderEvent = false;
// Remove areas that are not a valid part of the image map anymore.
for (PRInt32 childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
nsAccessible* area = mChildren.ElementAt(childIdx);
if (area->GetContent()->GetPrimaryFrame())
continue;
if (aDoFireEvents) {
nsRefPtr<AccEvent> event = new AccHideEvent(area, area->GetContent());
mDoc->FireDelayedAccessibleEvent(event);
doReorderEvent = true;
}
RemoveChild(area);
}
// Insert new areas into the tree.
PRUint32 areaElmCount = imageMapObj->AreaCount();
for (PRUint32 idx = 0; idx < areaElmCount; idx++) {
nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
nsAccessible* area = mChildren.SafeElementAt(idx);
if (!area || area->GetContent() != areaContent) {
nsRefPtr<nsAccessible> area = new nsHTMLAreaAccessible(areaContent, mDoc);
if (!mDoc->BindToDocument(area, nsAccUtils::GetRoleMapEntry(areaContent)))
break;
if (!InsertChildAt(idx, area)) {
mDoc->UnbindFromDocument(area);
break;
}
if (aDoFireEvents) {
nsRefPtr<AccEvent> event = new AccShowEvent(area, areaContent);
mDoc->FireDelayedAccessibleEvent(event);
doReorderEvent = true;
}
}
}
// Fire reorder event if needed.
if (doReorderEvent) {
nsRefPtr<AccEvent> reorderEvent =
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, mContent,
eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
mDoc->FireDelayedAccessibleEvent(reorderEvent);
}
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLImageMapAccessible: nsAccessible protected
void
nsHTMLImageMapAccessible::CacheChildren()
{
if (!mMapElement)
return;
nsCOMPtr<nsIDOMHTMLCollection> mapAreas;
mMapElement->GetAreas(getter_AddRefs(mapAreas));
if (!mapAreas)
return;
nsDocAccessible* document = Document();
PRUint32 areaCount = 0;
mapAreas->GetLength(&areaCount);
for (PRUint32 areaIdx = 0; areaIdx < areaCount; areaIdx++) {
nsCOMPtr<nsIDOMNode> areaNode;
mapAreas->Item(areaIdx, getter_AddRefs(areaNode));
if (!areaNode)
return;
nsCOMPtr<nsIContent> areaContent(do_QueryInterface(areaNode));
nsRefPtr<nsAccessible> area =
new nsHTMLAreaAccessible(areaContent, mDoc);
if (!document->BindToDocument(area, nsAccUtils::GetRoleMapEntry(areaContent)) ||
!AppendChild(area)) {
return;
}
}
UpdateChildAreas(false);
}
@ -226,6 +263,17 @@ nsHTMLAreaAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY,
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLAreaAccessible: nsAccessNode public
bool
nsHTMLAreaAccessible::IsPrimaryForNode() const
{
// Make HTML area DOM element not accessible. HTML image map accessible
// manages its tree itself.
return false;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLAreaAccessible: nsAccessible public

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

@ -51,8 +51,8 @@
class nsHTMLImageMapAccessible : public nsHTMLImageAccessibleWrap
{
public:
nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc,
nsIDOMHTMLMapElement* aMapElm);
nsHTMLImageMapAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
virtual ~nsHTMLImageMapAccessible() { }
// nsISupports and cycle collector
NS_DECL_ISUPPORTS_INHERITED
@ -65,16 +65,27 @@ public:
virtual nsAccessible* AnchorAt(PRUint32 aAnchorIndex);
virtual already_AddRefed<nsIURI> AnchorURIAt(PRUint32 aAnchorIndex);
/**
* Update area children of the image map.
*/
void UpdateChildAreas(bool aDoFireEvents = true);
protected:
// nsAccessible
virtual void CacheChildren();
private:
// Reference on linked map element if any.
nsCOMPtr<nsIDOMHTMLMapElement> mMapElement;
};
////////////////////////////////////////////////////////////////////////////////
// nsAccessible downcasting method
inline nsHTMLImageMapAccessible*
nsAccessible::AsImageMap()
{
return IsImageMapAccessible() ?
static_cast<nsHTMLImageMapAccessible*>(this) : nsnull;
}
/**
* Accessible for image map areas - must be child of image.
@ -89,6 +100,9 @@ public:
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
// nsAccessNode
virtual bool IsPrimaryForNode() const;
// nsAccessible
virtual void Description(nsString& aDescription);
virtual nsresult GetNameInternal(nsAString& aName);

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

@ -486,6 +486,21 @@ function testDefunctAccessible(aAcc, aNodeOrId)
ok(success, "parent" + msg);
}
/**
* Ensure that image map accessible tree is created.
*/
function ensureImageMapTree(aID)
{
// XXX: We send a useless mouse move to the image to force it to setup its
// image map, because flushing layout won't do it. Hopefully bug 135040
// will make this not suck.
synthesizeMouse(getNode(aID), 10, 10, { type: "mousemove" });
// XXX This may affect a11y more than other code because imagemaps may not
// get drawn or have an mouse event over them. Bug 570322 tracks a11y
// dealing with this.
todo(false, "Need to remove this image map workaround.");
}
/**
* Convert role to human readable string.

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

@ -9,6 +9,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=418368
<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>
@ -88,6 +90,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=418368
//////////////////////////////////////////////////////////////////////////
// image map and its link children
ensureImageMapTree("imgmap");
var imageMapHyperlinkAcc = getAccessible("imgmap",
[nsIAccessibleHyperLink]);
testThis("imgmap", imageMapHyperlinkAcc, ROLE_IMAGE_MAP, 2, "b", true,
@ -268,7 +272,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=418368
><img width="447" id="imgmap"
height="15"
usemap="#atoz_map"
src="letters.gif"><br>Empty link:<br
src="../letters.gif"><br>Empty link:<br
><a id="emptyLink" href=""><img src=""></a
><br>Link with embedded span<br
><a id="LinkWithSpan" href="http://www.heise.de/"><span lang="de">Heise Online</span></a

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

@ -9,6 +9,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=428248
<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>
@ -53,6 +55,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=428248
testThis("InvalidAriaHyperlink", 63, 2, "Invalid link");
// image map, but not its link children. They are not part of hypertext.
ensureImageMapTree("imgmap");
testThis("imgmap", 76, 3, "b");
// empty hyperlink
@ -131,7 +134,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=428248
><img width="447" id="imgmap"
height="15"
usemap="#atoz_map"
src="letters.gif"></img><br
src="../letters.gif"></img><br
>Empty link:<br
><a id="emptyLink" href=""><img src=""></img></a><br
>Link with embedded span<br

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

@ -19,21 +19,22 @@
<script type="application/javascript">
function doTest()
{
//XXX We send a useless mouse move to the image to force it to setup its
// image map, because flushing layout won't do it. Hopefully bug 135040
// will make this not suck.
synthesizeMouse($("imagemap"), 10, 10, { type: "mousemove" });
//XXX This may affect a11y more than other code because imagemaps may not
// get drawn or have an mouse event over them. Bug 570322 tracks a11y
// dealing with this.
todo(false, "Need to remove this image map workaround.");
ensureImageMapTree("imagemap");
testStates("t1", 0, EXT_STATE_EDITABLE, STATE_LINKED);
testStates("t2", 0, EXT_STATE_EDITABLE, STATE_LINKED);
testStates("rb1", (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
testStates("rb2", STATE_CHECKABLE, 0, STATE_CHECKED, STATE_LINKED);
testStates("cb1", (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
testStates("cbox", (STATE_HASPOPUP | STATE_COLLAPSED),
var imageMap = getAccessible("imagemap");
var t1 = imageMap.getChildAt(0);
testStates(t1, 0, EXT_STATE_EDITABLE, STATE_LINKED);
var t2 = imageMap.getChildAt(1);
testStates(t2, 0, EXT_STATE_EDITABLE, STATE_LINKED);
var rb1 = imageMap.getChildAt(2);
testStates(rb1, (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
var rb2 = imageMap.getChildAt(3);
testStates(rb2, STATE_CHECKABLE, 0, STATE_CHECKED, STATE_LINKED);
var cb1 = imageMap.getChildAt(4);
testStates(cb1, (STATE_CHECKABLE | STATE_CHECKED), 0, STATE_LINKED);
var cbox = imageMap.getChildAt(5);
testStates(cbox, (STATE_HASPOPUP | STATE_COLLAPSED),
EXT_STATE_EXPANDABLE, STATE_LINKED);
SimpleTest.finish();

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

@ -19,14 +19,7 @@
<script type="application/javascript">
function doTest()
{
//XXX We send a useless mouse move to the image to force it to setup its
// image map, because flushing layout won't do it. Hopefully bug 135040
// will make this not suck.
synthesizeMouse($("imagemap"), 10, 10, { type: "mousemove" });
//XXX This may affect a11y more than other code because imagemaps may not
// get drawn or have an mouse event over them. Bug 570322 tracks a11y
// dealing with this.
todo(false, "Need to remove this image map workaround.");
ensureImageMapTree("imagemap");
var accTree = {
role: ROLE_IMAGE_MAP,

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

@ -54,6 +54,7 @@ _TEST_FILES =\
test_doc.html \
test_gencontent.html \
test_hidden.html \
test_imagemap.html \
test_list_editabledoc.html \
test_list.html \
test_menu.xul \

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

@ -0,0 +1,394 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML img map accessible tree update tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<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"
src="../events.js"></script>
<script type="application/javascript">
function insertArea(aImageMapID, aMapID)
{
this.imageMap = getAccessible(aImageMapID);
this.mapNode = getNode(aMapID);
function getInsertedArea(aThisObj)
{
return aThisObj.imageMap.firstChild;
}
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getInsertedArea, this),
new invokerChecker(EVENT_REORDER, this.imageMap)
];
this.invoke = function insertArea_invoke()
{
var areaElm = document.createElement("area");
areaElm.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#a");
areaElm.setAttribute("coords", "0,0,13,14");
areaElm.setAttribute("alt", "a");
areaElm.setAttribute("shape", "rect");
this.mapNode.insertBefore(areaElm, this.mapNode.firstChild);
}
this.finalCheck = function insertArea_finalCheck()
{
var accTree =
{ IMAGE_MAP: [
{
role: ROLE_LINK,
name: "a",
children: [ ]
},
{
role: ROLE_LINK,
name: "b",
children: [ ]
},
] };
testAccessibleTree(this.imageMap, accTree);
}
this.getID = function insertArea_getID()
{
return "insert area element";
}
}
function appendArea(aImageMapID, aMapID)
{
this.imageMap = getAccessible(aImageMapID);
this.mapNode = getNode(aMapID);
function getAppendedArea(aThisObj)
{
return aThisObj.imageMap.lastChild;
}
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getAppendedArea, this),
new invokerChecker(EVENT_REORDER, this.imageMap)
];
this.invoke = function appendArea_invoke()
{
var areaElm = document.createElement("area");
areaElm.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#c");
areaElm.setAttribute("coords", "34,0,47,14");
areaElm.setAttribute("alt", "c");
areaElm.setAttribute("shape", "rect");
this.mapNode.appendChild(areaElm);
}
this.finalCheck = function appendArea_finalCheck()
{
var accTree =
{ IMAGE_MAP: [
{
role: ROLE_LINK,
name: "a",
children: [ ]
},
{
role: ROLE_LINK,
name: "b",
children: [ ]
},
{
role: ROLE_LINK,
name: "c",
children: [ ]
}
] };
testAccessibleTree(this.imageMap, accTree);
}
this.getID = function appendArea_getID()
{
return "append area element";
}
}
function removeArea(aImageMapID, aMapID)
{
this.imageMap = getAccessible(aImageMapID);
this.area = null;
this.mapNode = getNode(aMapID);
function getRemovedArea(aThisObj)
{
return aThisObj.area;
}
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getRemovedArea, this),
new invokerChecker(EVENT_REORDER, this.imageMap)
];
this.invoke = function removeArea_invoke()
{
this.area = this.imageMap.firstChild;
this.mapNode.removeChild(this.mapNode.firstElementChild);
}
this.finalCheck = function removeArea_finalCheck()
{
var accTree =
{ IMAGE_MAP: [
{
role: ROLE_LINK,
name: "b",
children: [ ]
},
{
role: ROLE_LINK,
name: "c",
children: [ ]
}
] };
testAccessibleTree(this.imageMap, accTree);
}
this.getID = function removeArea_getID()
{
return "remove area element";
}
}
function removeNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
{
this.container = getAccessible(aImageMapContainerID);
this.containerNode = this.container.DOMNode;
this.imageMap = getAccessible(aImageMapID);
this.imgNode = this.imageMap.DOMNode;
this.mapNode = getNode(aMapID);
this.eventSeq = [
new invokerChecker(EVENT_HIDE, this.imageMap),
new invokerChecker(EVENT_SHOW, this.imgNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function removeNameOnMap_invoke()
{
this.mapNode.removeAttribute("name");
}
this.finalCheck = function removeNameOnMap_finalCheck()
{
var accTree =
{ SECTION: [
{ GRAPHIC: [ ] }
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function removeNameOnMap_getID()
{
return "remove @name on map element";
}
}
function restoreNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
{
this.container = getAccessible(aImageMapContainerID);
this.containerNode = this.container.DOMNode;
this.imageMap = null;
this.imgNode = getNode(aImageMapID);
this.mapNode = getNode(aMapID);
function getImageMap(aThisObj)
{
return aThisObj.imageMap;
}
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getImageMap, this),
new invokerChecker(EVENT_SHOW, this.imgNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function restoreNameOnMap_invoke()
{
this.imageMap = getAccessible(aImageMapID);
this.mapNode.setAttribute("name", "atoz_map");
}
this.finalCheck = function removeNameOnMap_finalCheck()
{
var accTree =
{ SECTION: [
{ IMAGE_MAP: [
{ LINK: [ ] },
{ LINK: [ ] }
] }
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function removeNameOnMap_getID()
{
return "restore @name on map element";
}
}
function removeMap(aImageMapContainerID, aImageMapID, aMapID)
{
this.container = getAccessible(aImageMapContainerID);
this.containerNode = this.container.DOMNode;
this.imageMap = null;
this.imgNode = getNode(aImageMapID);
this.mapNode = getNode(aMapID);
function getImageMap(aThisObj)
{
return aThisObj.imageMap;
}
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getImageMap, this),
new invokerChecker(EVENT_SHOW, this.imgNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function removeMap_invoke()
{
this.imageMap = getAccessible(aImageMapID);
this.mapNode.parentNode.removeChild(this.mapNode);
}
this.finalCheck = function removeMap_finalCheck()
{
var accTree =
{ SECTION: [
{ GRAPHIC: [ ] }
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function removeMap_getID()
{
return "remove map element";
}
}
function insertMap(aImageMapContainerID, aImageID)
{
this.container = getAccessible(aImageMapContainerID);
this.containerNode = this.container.DOMNode;
this.image = null;
this.imgMapNode = getNode(aImageID);
function getImage(aThisObj)
{
return aThisObj.image;
}
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getImage, this),
new invokerChecker(EVENT_SHOW, this.imgMapNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function insertMap_invoke()
{
this.image = getAccessible(aImageID);
var map = document.createElement("map");
map.setAttribute("name", "atoz_map");
map.setAttribute("id", "map");
var area = document.createElement("area")
area.setAttribute("href",
"http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
area.setAttribute("coords", "17,0,30,14");
area.setAttribute("alt", "b");
area.setAttribute("shape", "rect");
map.appendChild(area);
this.containerNode.appendChild(map);
ensureImageMapTree(aImageID);
}
this.finalCheck = function insertMap_finalCheck()
{
var accTree =
{ SECTION: [
{ IMAGE_MAP: [
{ LINK: [ ] }
] }
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function insertMap_getID()
{
return "insert map element";
}
}
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new insertArea("imgmap", "map"));
gQueue.push(new appendArea("imgmap", "map"));
gQueue.push(new removeArea("imgmap", "map"));
gQueue.push(new removeNameOnMap("container", "imgmap", "map"));
gQueue.push(new restoreNameOnMap("container", "imgmap", "map"));
gQueue.push(new removeMap("container", "imgmap", "map"));
gQueue.push(new insertMap("container", "imgmap"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Image map accessible tree is not updated when image map is changed"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=732389">
Mozilla Bug 732389
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<map name="atoz_map" id="map">
<area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
coords="17,0,30,14" alt="b" shape="rect">
</map>
<div id="container">
<img id="imgmap" width="447" height="15"
usemap="#atoz_map"
src="../letters.gif">
</div>
</body>
</html>

1
aclocal.m4 поставляемый
Просмотреть файл

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

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

@ -147,7 +147,7 @@ pref("dom.disable_open_during_load", true);
pref("privacy.popups.showBrowserMessage", true);
pref("keyword.enabled", true);
pref("keyword.URL", "http://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
pref("keyword.URL", "https://www.google.com/m?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
pref("accessibility.typeaheadfind", false);
pref("accessibility.typeaheadfind.timeout", 5000);

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

@ -17,6 +17,7 @@ const LocalFile = CC('@mozilla.org/file/local;1',
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/ContactService.jsm');
Cu.import('resource://gre/modules/Webapps.jsm');
XPCOMUtils.defineLazyGetter(Services, 'env', function() {
return Cc['@mozilla.org/process/environment;1']
@ -66,7 +67,7 @@ function startupHttpd(baseDir, port) {
function addPermissions(urls) {
let permissions = [
'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app',
'content-camera', 'webcontacts-manage', 'wifi-manage'
'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification'
];
urls.forEach(function(url) {
let uri = Services.io.newURI(url, null, null);
@ -165,6 +166,10 @@ var shell = {
dump('Error loading ' + frameScriptUrl + ' as a frame script: ' + e + '\n');
}
CustomEventManager.init();
WebappsHelper.init();
let browser = this.contentBrowser;
browser.homePage = homeURL;
browser.goHome();
@ -421,3 +426,70 @@ Services.obs.addObserver(function onConsoleAPILogEvent(subject, topic, data) {
serverSocket.asyncListen(listener);
})();
CustomEventManager = {
init: function custevt_init() {
window.addEventListener("ContentStart", (function(evt) {
content.addEventListener("mozContentEvent", this, false, true);
}).bind(this), false);
},
handleEvent: function custevt_handleEvent(evt) {
let detail = evt.detail;
dump("XXX FIXME : Got a mozContentEvent: " + detail.type);
switch(detail.type) {
case "desktop-notification-click":
case "desktop-notification-close":
AlertsHelper.handleEvent(detail);
break;
}
}
}
AlertsHelper = {
_listeners: {},
_count: 0,
handleEvent: function alert_handleEvent(detail) {
if (!detail || !detail.id)
return;
let listener = this._listeners[detail.id];
let topic = detail.type == "desktop-notification-click" ? "alertclickcallback" : "alertfinished";
listener.observer.observe(null, topic, listener.cookie);
// we're done with this notification
if (topic === "alertfinished")
delete this._listeners[detail.id];
},
registerListener: function alert_registerListener(cookie, alertListener) {
let id = "alert" + this._count++;
this._listeners[id] = { observer: alertListener, cookie: cookie };
return id;
},
showAlertNotification: function alert_showAlertNotification(imageUrl, title, text, textClickable,
cookie, alertListener, name) {
let id = this.registerListener(cookie, alertListener);
shell.sendEvent(content, "mozChromeEvent", { type: "desktop-notification", id: id, icon: imageUrl,
title: title, text: text } );
}
}
WebappsHelper = {
init: function webapps_init() {
Services.obs.addObserver(this, "webapps-launch", false);
},
observe: function webapps_observe(subject, topic, data) {
let json = JSON.parse(data);
DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
if (!aManifest)
return;
let manifest = new DOMApplicationManifest(aManifest, json.origin);
shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin });
});
}
}

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

@ -0,0 +1,27 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// -----------------------------------------------------------------------
// Alerts Service
// -----------------------------------------------------------------------
function AlertsService() { }
AlertsService.prototype = {
classID: Components.ID("{5dce03b2-8faa-4b6e-9242-6ddb0411750c}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName);
}
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([AlertsService]);

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

@ -5,3 +5,11 @@ category agent-style-sheets browser-content-stylesheet chrome://browser/content/
component {eff4231b-abce-4f7f-a40a-d646e8fde3ce} CameraContent.js
contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce}
category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
# AlertsService.js
component {5dce03b2-8faa-4b6e-9242-6ddb0411750c} AlertsService.js
contract @mozilla.org/alerts-service;1 {5dce03b2-8faa-4b6e-9242-6ddb0411750c}
# ContentPermissionPrompt.js
component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js
contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467}

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

@ -62,7 +62,7 @@ CameraContent.prototype = {
let perm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "content-camera");
//only pages with perm set and chrome pages can use the camera in content
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION || from.schemeIs("chrome");
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
Services.obs.addObserver(this, "inner-window-destroyed", false);
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);

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

@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function ContentPermissionPrompt() {}
ContentPermissionPrompt.prototype = {
handleExistingPermission: function handleExistingPermission(request) {
let result = Services.perms.testExactPermission(request.uri, request.type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
}
if (result == Ci.nsIPermissionManager.DENY_ACTION) {
request.cancel();
return true;
}
return false;
},
prompt: function(request) {
// returns true if the request was handled
if (this.handleExistingPermission(request))
return;
// TODO : show UI to grant or deny permission
},
classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
};
//module initialization
const NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);

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

@ -51,6 +51,8 @@ XPIDLSRCS = \
EXTRA_PP_COMPONENTS = \
B2GComponents.manifest \
CameraContent.js \
AlertsService.js \
ContentPermissionPrompt.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -2,9 +2,9 @@
#export GONK_PRODUCT=generic
#gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION"
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir-prof-gonk
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
mk_add_options MOZ_MAKE_FLAGS="-s -j16"
mk_add_options MOZ_MAKE_FLAGS="-j8"
ac_add_options --enable-application=b2g

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

@ -144,6 +144,7 @@
@BINPATH@/components/directory.xpt
@BINPATH@/components/docshell.xpt
@BINPATH@/components/dom.xpt
@BINPATH@/components/dom_apps.xpt
@BINPATH@/components/dom_base.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_telephony.xpt
@ -290,7 +291,6 @@
@BINPATH@/components/xuldoc.xpt
@BINPATH@/components/xultmpl.xpt
@BINPATH@/components/zipwriter.xpt
@BINPATH@/components/webapps.xpt
; JavaScript components
@BINPATH@/components/ConsoleAPI.manifest
@ -407,10 +407,10 @@
@BINPATH@/components/RadioInterfaceLayer.js
@BINPATH@/components/SmsDatabaseService.manifest
@BINPATH@/components/SmsDatabaseService.js
@BINPATH@/components/nsWifiWorker.js
@BINPATH@/components/nsWifiWorker.manifest
@BINPATH@/components/nsDOMWifiManager.js
@BINPATH@/components/nsDOMWifiManager.manifest
@BINPATH@/components/WifiWorker.js
@BINPATH@/components/WifiWorker.manifest
@BINPATH@/components/DOMWifiManager.js
@BINPATH@/components/DOMWifiManager.manifest
#endif
#ifdef XP_MACOSX
@BINPATH@/components/libalerts.dylib
@ -430,6 +430,8 @@
#endif
@BINPATH@/components/TelemetryPing.js
@BINPATH@/components/TelemetryPing.manifest
@BINPATH@/components/Webapps.js
@BINPATH@/components/Webapps.manifest
; Modules
@BINPATH@/modules/*
@ -615,3 +617,5 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/B2GComponents.manifest
@BINPATH@/components/B2GComponents.xpt
@BINPATH@/components/CameraContent.js
@BINPATH@/components/AlertsService.js
@BINPATH@/components/ContentPermissionPrompt.js

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

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331241604000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1331848989000">
<emItems>
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
<versionRange minVersion="0" maxVersion="*">
@ -65,8 +65,8 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i72" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
<versionRange minVersion="0" maxVersion="3.4.1.194" severity="1">
<emItem blockID="i72" os="WINNT" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
<versionRange minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
</versionRange>
</emItem>
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
@ -153,6 +153,10 @@
<versionRange minVersion="2.0" maxVersion="2.0">
</versionRange>
</emItem>
<emItem blockID="i73" id="a1g0a9g219d@a1.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i51" id="admin@youtubeplayer.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Двоичные данные
browser/base/content/aboutHome-restore-icon.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.4 KiB

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

@ -1,384 +0,0 @@
%if 0
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License
* Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is aboutHome.xhtml.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (original author)
* Mihai Sucan <mihai.sucan@gmail.com>
* Stephen Horlander <shorlander@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
%endif
html {
font-family: sans-serif;
background: -moz-Field;
color: -moz-FieldText;
height: 100%;
}
body {
display: inline-block;
position: relative;
margin: 0;
width: 100%;
height: 100%;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#brandStart {
text-align: center;
height: 19%;
max-height: 256px;
min-height: 92px;
}
#brandStartSpacer {
height: 6.5%;
}
#brandStartLogo {
height: 100%;
}
#searchContainer {
height: 15%;
min-height: 90px;
}
#searchContainer::before {
content: " ";
display: block;
height: 23%;
}
#searchForm {
display: table;
width: 100%;
max-width: 1830px;
margin: 0 auto;
}
@media all and (max-height: 700px) {
#searchContainer { height: 20% }
}
@media all and (max-height: 500px) {
#searchContainer { height: 25% }
}
@media all and (max-height: 370px) {
#searchContainer { height: 30% }
}
#searchLogoContainer {
display: table-cell;
width: 30%;
text-align: end;
line-height: 32px;
}
#searchEngineLogo {
-moz-margin-end: 2.5%;
vertical-align: middle;
}
#searchInputContainer {
display: table-cell;
width: 38%;
max-width: 700px;
min-width: 150px;
}
#searchText {
width: 100%;
height: 24px;
padding: 3px 6px;
border-radius: 2px;
border: 1px solid rgb(150,150,150);
border-top-color: rgb(100,100,100);
box-shadow: 0 1px 0 rgba(255,255,255,0.5);
font-size: 1.2em;
}
#searchButtons {
display: table-cell;
width: 31%;
-moz-padding-start: 13px;
vertical-align: top;
}
@media all and (max-width: 470px) {
#searchLogoContainer { width: 10% }
#searchButtons { width: 11% }
#searchInputContainer { width: 40% }
}
@media all and (min-width: 470px) and (max-width: 600px) {
#searchLogoContainer { width: 15% }
#searchButtons { width: 16%; white-space: nowrap }
#searchInputContainer { width: 45% }
}
@media all and (min-width: 600px) and (max-width: 850px) {
#searchLogoContainer { width: 20% }
#searchButtons { width: 21%; white-space: nowrap }
#searchInputContainer { width: 49% }
}
#searchSubmit {
background: -moz-linear-gradient(#f1f1f1, #dfdfdf);
padding: 4px 8px;
height: 32px;
border: 1px solid #ccc;
border-top-color: #ccc;
border-bottom-color: #999;
-moz-border-start-color: #afafaf;
-moz-border-end-color: #999;
box-shadow: 1px 1px 0 #e7e7e7,
0 1px 0 #fcfcfc inset,
0 -1px 0 #d7d7d7 inset;
font-size: 1em;
color: #000;
cursor: pointer;
}
body[dir=rtl] #searchSubmit {
box-shadow: -1px 1px 0 #e7e7e7,
0 1px 0 #fcfcfc inset,
0 -1px 0 #d7d7d7 inset;
}
#searchSubmit:active {
background: -moz-linear-gradient(#c5c5c5, #c5c5c5);
box-shadow: 1px 1px 0 #e7e7e7;
}
body[dir=rtl] #searchSubmit:active {
box-shadow: -1px 1px 0 #e7e7e7;
}
#contentContainer {
height: 30%;
background-image: -moz-radial-gradient(center top, ellipse farthest-side, rgba(16,83,130,.5), rgba(16,83,130,0) 75%),
-moz-radial-gradient(center top, ellipse farthest-side, rgba(180,218,244,.5), rgba(180,218,244,0)),
-moz-radial-gradient(center top, ellipse farthest-side, rgba(180,218,244,.3), rgba(180,218,244,0));
background-size: 100% 5px,
100% 50px,
100% 100%;
background-repeat: no-repeat;
}
@media all and (max-height: 400px) {
#contentContainer { height: 20% }
}
#snippetContainer {
position: relative;
top: -24px;
text-align: center;
}
#snippets {
display: inline-block;
padding: 14px;
width: 30%;
max-width: 600px;
background-image: -moz-linear-gradient(rgba(255,255,255,.8), rgba(255,255,255,.1));
background-color: rgb(250,250,250);
border-radius: 4px;
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset,
0 -2px 0 rgba(0,0,0,.1) inset,
0 0 10px rgba(255,255,255,.5) inset,
0 0 0 1px rgba(0,0,0,.1),
0 2px 4px rgba(0,0,0,.2);
color: rgb(60,60,60);
font-size: .85em;
cursor: pointer;
}
#snippets:empty {
visibility: hidden;
}
@media all and (max-width: 470px) {
#snippets { width: 65% }
}
@media all and (min-width: 470px) and (max-width: 850px) {
#snippets { width: 45% }
}
#snippets:hover {
background-color: rgb(255,255,255);
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset,
0 -2px 0 rgba(0,0,0,.1) inset,
0 0 10px rgba(255,255,255,.5) inset,
0 0 5px rgba(0,0,0,.1),
0 0 0 1px rgba(0,0,0,.1),
0 2px 4px rgba(0,0,0,.2);
}
#snippets:hover:active {
background-color: rgb(210,210,210);
box-shadow: 0 2px 3px rgba(0,0,0,.3) inset,
0 1px 0 rgba(255,255,255,.5);
}
#defaultSnippet1,
#defaultSnippet2 {
display: table-row;
text-align: start;
}
#defaultSnippet1::before,
#defaultSnippet2::before {
display: table-cell;
vertical-align: middle;
-moz-padding-end: 1em;
}
#defaultSnippet1::before {
content: url("chrome://browser/content/aboutHome-snippet1.png");
}
#defaultSnippet2::before {
content: url("chrome://browser/content/aboutHome-snippet2.png");
}
#sessionRestoreContainer {
padding-top: 1.5%;
text-align: center;
}
@media all and (max-height: 500px) {
#sessionRestoreContainer {
position: relative;
top: -15px;
padding-top: 0;
}
}
#restorePreviousSession {
padding: 10px;
border: 0;
border-radius: 4px;
box-shadow: 0 0 0 1px rgba(9,37,59,0),
0 1px 2px rgba(9,37,59,0),
0 0 10px rgba(255,255,255,0),
0 -3px 0 rgba(180,194,212,0) inset;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.25s;
-moz-transition-timing-function: ease-out;
background: transparent;
color: rgb(50,50,50);
font-weight: bold;
font-size: 1em;
cursor: pointer;
}
#restorePreviousSession::before {
display: inline-block;
content: url("chrome://browser/content/aboutHome-restore-icon.png");
-moz-margin-end: 10px;
vertical-align: middle;
height: 66px; /* Needed to avoid a blank space under the image */
}
body[dir=rtl] #restorePreviousSession::before {
-moz-transform: scaleX(-1);
}
@media all and (max-height: 500px) {
#restorePreviousSession::before {
content: url("chrome://browser/content/aboutHome-restore-icon-small.png");
height: 41px;
}
}
@media all and (max-width: 500px) {
#restorePreviousSession::before {
content: url("chrome://browser/content/aboutHome-restore-icon-small.png");
height: 41px;
}
}
#restorePreviousSession:disabled {
display: none;
}
#restorePreviousSession:hover {
background-image: -moz-linear-gradient(rgba(255,255,255,.7), rgba(255,255,255,.2));
border-radius: 4px;
box-shadow: 0 0 0 1px rgba(9,37,59,.2),
0 1px 2px rgba(9,37,59,.2),
0 0 10px rgba(255,255,255,.4),
0 -3px 0 rgba(180,194,212,.3) inset;
}
#restorePreviousSession:hover:active {
background-image: -moz-linear-gradient(rgba(255,255,255,.0), rgba(255,255,255,.2));
background-color: rgba(23,75,115,.1);
box-shadow: 0 0 0 1px rgba(9,37,59,.2),
0 1px 2px rgba(9,37,59,.4) inset,
0 1px 5px rgba(9,37,59,.15) inset;
}
#bottomSection {
position: absolute;
color: rgb(150,150,150);
font-size: .8em;
width: 100%;
text-align: center;
bottom: 2%;
}
#syncLinksContainer {
padding-top: 1em;
}
.sync-link {
padding: 1em;
}
@media all and (max-height: 370px) {
#bottomSection {
visibility: hidden;
}
}

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

@ -0,0 +1,362 @@
%if 0
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License
* Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is aboutHome.xhtml.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (original author)
* Mihai Sucan <mihai.sucan@gmail.com>
* Stephen Horlander <shorlander@mozilla.com>
* Frank Yan <fyan@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
%endif
html {
font: message-box;
font-size: 100%;
background-color: hsl(0,0%,90%);
background-image: url(chrome://browser/content/abouthome/noise.png),
-moz-linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
background-attachment: fixed;
color: #000;
height: 100%;
}
body {
margin: 0;
height: 100%;
}
#container {
display: -moz-box;
-moz-box-orient: vertical;
width: 100%;
height: 100%;
}
input,
button {
font-size: inherit;
font-family: inherit;
}
a {
color: -moz-nativehyperlinktext;
text-decoration: none;
}
.spacer {
-moz-box-flex: 1;
}
#topSection {
text-align: center;
}
#brandLogo {
height: 154px;
margin: 22px 0 31px;
}
#searchForm,
#snippets {
width: 470px;
}
#searchForm {
display: -moz-box;
}
#searchLogoContainer {
display: -moz-box;
-moz-box-align: center;
padding-top: 2px;
-moz-padding-end: 8px;
}
#searchEngineLogo {
display: inline-block;
}
#searchText {
-moz-box-flex: 1;
padding: 6px 8px;
background: hsla(0,0%,100%,.9) padding-box;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
0 0 2px hsla(210,65%,9%,.1) inset,
0 1px 0 hsla(0,0%,100%,.2);
border-radius: 2.5px 0 0 2.5px;
}
body[dir=rtl] #searchText {
border-radius: 0 2.5px 2.5px 0;
}
#searchText:focus {
border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
}
#searchSubmit {
-moz-margin-start: -1px;
background: -moz-linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
padding: 0 9px;
border: 1px solid;
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
-moz-border-start: 1px solid transparent;
border-radius: 0 2.5px 2.5px 0;
box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.2);
cursor: pointer;
-moz-transition-property: background-color, border-color, box-shadow;
-moz-transition-duration: 150ms;
}
body[dir=rtl] #searchSubmit {
border-radius: 2.5px 0 0 2.5px;
}
#searchText:focus + #searchSubmit,
#searchText + #searchSubmit:hover {
border-color: #59b5fc #45a3e7 #3294d5;
color: white;
}
#searchText:focus + #searchSubmit {
background-image: -moz-linear-gradient(#4cb1ff, #1793e5);
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
0 0 0 1px hsla(0,0%,100%,.1) inset,
0 1px 0 hsla(210,54%,20%,.03);
}
#searchText + #searchSubmit:hover {
background-image: -moz-linear-gradient(#66bdff, #0d9eff);
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
0 0 0 1px hsla(0,0%,100%,.1) inset,
0 1px 0 hsla(210,54%,20%,.03),
0 0 4px hsla(206,100%,20%,.2);
}
#searchText + #searchSubmit:hover:active {
box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
0 0 1px hsla(211,79%,6%,.2) inset;
-moz-transition-duration: 0ms;
}
#defaultSnippet1,
#defaultSnippet2 {
display: block;
min-height: 38px;
background: 30px center no-repeat;
padding: 6px 0;
-moz-padding-start: 79px;
}
body[dir=rtl] #defaultSnippet1,
body[dir=rtl] #defaultSnippet2 {
background-position: right 30px center;
}
#defaultSnippet1 {
background-image: url("chrome://browser/content/abouthome/snippet1.png");
}
#defaultSnippet2 {
background-image: url("chrome://browser/content/abouthome/snippet2.png");
}
#snippets {
display: inline-block;
text-align: start;
margin: 12px 0;
color: #3c3c3c;
font-size: 75%;
}
#launcher {
display: -moz-box;
-moz-box-align: center;
-moz-box-pack: center;
width: 100%;
background-color: hsla(0,0%,0%,.03);
border-top: 1px solid hsla(0,0%,0%,.03);
box-shadow: 0 1px 2px hsla(0,0%,0%,.02) inset,
0 -1px 0 hsla(0,0%,100%,.25);
}
#launcher:not([session]),
body[narrow] #launcher[session] {
display: block; /* display separator and restore button on separate lines */
text-align: center;
white-space: nowrap; /* prevent navigational buttons from wrapping */
}
.launchButton {
display: -moz-box;
-moz-box-orient: vertical;
margin: 16px 1px;
padding: 14px 6px;
min-width: 88px;
max-width: 176px;
max-height: 85px;
vertical-align: top;
white-space: normal;
background: transparent padding-box;
border: 1px solid transparent;
border-radius: 2.5px;
color: #525c66;
font-size: 75%;
cursor: pointer;
-moz-transition-property: background-color, border-color, box-shadow;
-moz-transition-duration: 150ms;
}
body[narrow] #launcher[session] > .launchButton {
margin: 4px 1px;
}
.launchButton:hover {
background-color: hsla(211,79%,6%,.03);
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
}
.launchButton:hover:active {
background-image: -moz-linear-gradient(hsla(211,79%,6%,.02), hsla(211,79%,6%,.05));
border-color: hsla(210,54%,20%,.2) hsla(210,54%,20%,.23) hsla(210,54%,20%,.25);
box-shadow: 0 1px 1px hsla(211,79%,6%,.05) inset,
0 0 1px hsla(211,79%,6%,.1) inset;
-moz-transition-duration: 0ms;
}
#launcher:not([session]) > #restorePreviousSessionSeparator,
#launcher:not([session]) > #restorePreviousSession {
display: none;
}
#restorePreviousSessionSeparator {
width: 3px;
height: 116px;
margin: 0 10px;
background-image: -moz-linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
-moz-linear-gradient(hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
-moz-linear-gradient(hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
background-position: left top, center, right bottom;
background-size: 1px auto;
background-repeat: no-repeat;
}
body[narrow] #restorePreviousSessionSeparator {
margin: 0 auto;
width: 512px;
height: 3px;
background-image: -moz-linear-gradient(0, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0)),
-moz-linear-gradient(0, hsla(211,79%,6%,0), hsla(211,79%,6%,.2), hsla(211,79%,6%,0)),
-moz-linear-gradient(0, hsla(0,0%,100%,0), hsla(0,0%,100%,.35), hsla(0,0%,100%,0));
background-size: auto 1px;
}
#restorePreviousSession {
max-width: none;
font-size: 90%;
}
body[narrow] #restorePreviousSession {
font-size: 80%;
}
.launchButton::before {
display: block;
margin-bottom: 6px;
line-height: 0; /* remove extra vertical space due to non-zero font-size */
}
#bookmarks::before {
content: url("chrome://browser/content/abouthome/bookmarks.png");
}
#history::before {
content: url("chrome://browser/content/abouthome/history.png");
}
#settings::before {
content: url("chrome://browser/content/abouthome/settings.png");
}
#addons::before {
content: url("chrome://browser/content/abouthome/addons.png");
}
#downloads::before {
content: url("chrome://browser/content/abouthome/downloads.png");
}
#sync::before {
content: url("chrome://browser/content/abouthome/sync.png");
}
#restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore-large.png");
display: inline-block; /* display on same line as text label */
vertical-align: middle;
margin-bottom: 0;
-moz-margin-end: 8px;
}
body[dir=rtl] #restorePreviousSession::before {
-moz-transform: scaleX(-1);
}
body[narrow] #restorePreviousSession::before {
content: url("chrome://browser/content/abouthome/restore.png");
}
#aboutMozilla {
display: block;
position: relative; /* pin wordmark to edge of document, not of viewport */
-moz-box-ordinal-group: 0;
opacity: .5;
-moz-transition: opacity 150ms;
}
#aboutMozilla:hover {
opacity: 1;
}
#aboutMozilla::before {
content: url("chrome://browser/content/abouthome/mozilla.png");
display: block;
position: absolute;
top: 12px;
right: 12px;
}

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

@ -22,6 +22,7 @@
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (original author)
* Mihai Sucan <mihai.sucan@gmail.com>
* Frank Yan <fyan@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -155,6 +156,9 @@ function onLoad(event)
document.getElementById("searchText").focus();
loadSnippets();
fitToWidth();
window.addEventListener("resize", fitToWidth);
}
@ -210,13 +214,17 @@ function loadSnippets()
let updateURL = localStorage["snippets-update-url"];
if (updateURL && (!lastUpdate ||
Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS)) {
// Try to update from network.
let xhr = new XMLHttpRequest();
try {
xhr.open("GET", updateURL, true);
} catch (ex) {
showSnippets();
return;
}
// Even if fetching should fail we don't want to spam the server, thus
// set the last update time regardless its results. Will retry tomorrow.
localStorage["snippets-last-update"] = Date.now();
// Try to update from network.
let xhr = new XMLHttpRequest();
xhr.open('GET', updateURL, true);
xhr.onerror = function (event) {
showSnippets();
};
@ -260,7 +268,7 @@ function showSnippets()
let defaultSnippetsElt = document.getElementById("defaultSnippets");
let entries = defaultSnippetsElt.querySelectorAll("span");
// Choose a random snippet. Assume there is always at least one.
let randIndex = Math.round(Math.random() * (entries.length - 1));
let randIndex = Math.floor(Math.random() * entries.length);
let entry = entries[randIndex];
// Inject url in the eventual link.
if (DEFAULT_SNIPPETS_URLS[randIndex]) {
@ -269,27 +277,17 @@ function showSnippets()
// up in the translation.
if (links.length == 1) {
links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
activateSnippetsButtonClick(entry);
}
}
// Move the default snippet to the snippets element.
snippetsElt.appendChild(entry);
}
/**
* Searches a single link element in aElt and binds its href to the click
* action of the snippets button.
*
* @param aElt
* Element to search the link into.
*/
function activateSnippetsButtonClick(aElt) {
let links = aElt.getElementsByTagName("a");
if (links.length == 1) {
document.getElementById("snippets")
.addEventListener("click", function(aEvent) {
if (aEvent.target.nodeName != "a")
window.location = links[0].href;
}, false);
function fitToWidth() {
if (window.scrollMaxX) {
document.body.setAttribute("narrow", "true");
} else if (document.body.hasAttribute("narrow")) {
document.body.removeAttribute("narrow");
fitToWidth();
}
}

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

@ -25,6 +25,7 @@
# Marco Bonardo <mak77@bonardo.net> (original author)
# Mihai Sucan <mihai.sucan@gmail.com>
# Stephen Horlander <shorlander@mozilla.com>
# Frank Yan <fyan@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -60,52 +61,48 @@
<link rel="icon" type="image/png" id="favicon"
href="chrome://branding/content/icon16.png"/>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://browser/content/aboutHome.css"/>
href="chrome://browser/content/abouthome/aboutHome.css"/>
<script type="text/javascript;version=1.8"
src="chrome://browser/content/aboutHome.js"/>
src="chrome://browser/content/abouthome/aboutHome.js"/>
</head>
<body dir="&locale.dir;" onload="onLoad(event)">
<div id="brandStartSpacer" />
<div id="brandStart">
<img id="brandStartLogo" src="chrome://branding/content/about-logo.png" alt="" />
</div>
<div id="container">
<div class="spacer"/>
<div id="topSection">
<img id="brandLogo" src="chrome://branding/content/about-logo.png" alt=""/>
<div id="searchContainer">
<form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
<div id="searchLogoContainer"><img id="searchEngineLogo" /></div>
<div id="searchInputContainer">
<input type="text" name="q" value="" id="searchText" maxlength="256" />
<div id="searchContainer">
<form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
<div id="searchLogoContainer"><img id="searchEngineLogo"/></div>
<input type="text" name="q" value="" id="searchText" maxlength="256"/>
<input id="searchSubmit" type="submit" value="&abouthome.searchEngineButton.label;"/>
</form>
</div>
<div id="searchButtons">
<input id="searchSubmit" type="submit" value="&abouthome.searchEngineButton.label;" />
<div id="snippetContainer">
<div id="defaultSnippets" hidden="true">
<span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span>
<span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span>
</div>
<div id="snippets"/>
</div>
</form>
</div>
</div>
<div class="spacer"/>
<div id="contentContainer">
<div id="snippetContainer">
<div id="defaultSnippets" hidden="true">
<span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span>
<span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span>
</div>
<div id="snippets"/>
<div id="launcher" session="true">
<button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
<button class="launchButton" id="history">&abouthome.historyButton.label;</button>
<button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
<button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
<button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
<button class="launchButton" id="sync">&syncBrand.shortName.label;</button>
<div id="restorePreviousSessionSeparator"/>
<button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
</div>
<div id="sessionRestoreContainer">
<button id="restorePreviousSession">&historyRestoreLastSession.label;</button>
</div>
</div>
<div id="bottomSection">
<div id="aboutMozilla">
<a href="http://www.mozilla.com/about/">&abouthome.aboutMozilla;</a>
</div>
<div id="syncLinksContainer">
<a href="javascript:void(0);" class="sync-link" id="setupSyncLink">&abouthome.syncSetup.label;</a>
<a href="javascript:void(0);" class="sync-link" id="pairDeviceLink">&abouthome.pairDevice.label;</a>
</div>
<a id="aboutMozilla" href="http://www.mozilla.com/about/"/>
</div>
</body>
</html>

Двоичные данные
browser/base/content/abouthome/addons.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
browser/base/content/abouthome/bookmarks.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
browser/base/content/abouthome/downloads.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 898 B

Двоичные данные
browser/base/content/abouthome/history.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
browser/base/content/abouthome/mozilla.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичные данные
browser/base/content/abouthome/noise.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Двоичные данные
browser/base/content/abouthome/restore-large.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
browser/base/content/abouthome/restore.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Двоичные данные
browser/base/content/abouthome/settings.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

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

До

Ширина:  |  Высота:  |  Размер: 1.8 KiB

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

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

До

Ширина:  |  Высота:  |  Размер: 3.2 KiB

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
browser/base/content/abouthome/sync.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

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

@ -175,21 +175,7 @@ let gSyncUI = {
this.clearError(title);
},
// Set visibility of "Setup Sync" link
showSetupSyncAboutHome: function SUI_showSetupSyncAboutHome(toShow) {
let browsers = gBrowser.browsers;
for (let i = 0; i < browsers.length; i++) {
let b = browsers[i];
if ("about:home" == b.currentURI.spec) {
b.contentDocument.getElementById("setupSyncLink").hidden = !toShow;
}
}
},
onSetupComplete: function SUI_onSetupComplete() {
// Remove "setup sync" link in about:home if it is open.
this.showSetupSyncAboutHome(false);
onLoginFinish();
},
@ -237,8 +223,6 @@ let gSyncUI = {
onStartOver: function SUI_onStartOver() {
this.clearError();
// Make "setup sync" link visible in about:home if it is open.
this.showSetupSyncAboutHome(true);
},
onQuotaNotice: function onQuotaNotice(subject, data) {

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

@ -110,6 +110,15 @@ let gBrowserThumbnails = {
let channel = aBrowser.docShell.currentDocumentChannel;
// No valid document channel. We shouldn't take a screenshot.
if (!channel)
return false;
// Don't take screenshots of internally redirecting about: pages.
// This includes error pages.
if (channel.originalURI.schemeIs("about"))
return false;
try {
// If the channel is a nsIHttpChannel get its http status code.
let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);

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

@ -56,6 +56,7 @@
# Patrick Walton <pcwalton@mozilla.com>
# Mihai Sucan <mihai.sucan@gmail.com>
# Victor Porof <vporof@mozilla.com>
# Frank Yan <fyan@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -2706,11 +2707,7 @@ function BrowserOnAboutPageLoad(document) {
let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
getService(Components.interfaces.nsISessionStore);
if (!ss.canRestoreLastSession)
document.getElementById("sessionRestoreContainer").hidden = true;
// Sync-related links
if (Services.prefs.prefHasUserValue("services.sync.username")) {
document.getElementById("setupSyncLink").hidden = true;
}
document.getElementById("launcher").removeAttribute("session");
}
}
@ -2718,19 +2715,17 @@ function BrowserOnAboutPageLoad(document) {
* Handle command events bubbling up from error page content
*/
function BrowserOnClick(event) {
// Don't trust synthetic events
if (!event.isTrusted ||
(event.target.localName != "button" &&
event.target.className != "sync-link"))
if (!event.isTrusted || // Don't trust synthetic events
event.button == 2 || event.target.localName != "button")
return;
var ot = event.originalTarget;
var errorDoc = ot.ownerDocument;
var ownerDoc = ot.ownerDocument;
// If the event came from an ssl error page, it is probably either the "Add
// Exception…" or "Get me out of here!" button
if (/^about:certerror/.test(errorDoc.documentURI)) {
if (ot == errorDoc.getElementById('exceptionDialogButton')) {
if (/^about:certerror/.test(ownerDoc.documentURI)) {
if (ot == ownerDoc.getElementById('exceptionDialogButton')) {
var params = { exceptionAdded : false, handlePrivateBrowsing : true };
try {
@ -2738,7 +2733,7 @@ function BrowserOnClick(event) {
case 2 : // Pre-fetch & pre-populate
params.prefetchCert = true;
case 1 : // Pre-populate
params.location = errorDoc.location.href;
params.location = ownerDoc.location.href;
}
} catch (e) {
Components.utils.reportError("Couldn't get ssl_override pref: " + e);
@ -2749,22 +2744,22 @@ function BrowserOnClick(event) {
// If the user added the exception cert, attempt to reload the page
if (params.exceptionAdded)
errorDoc.location.reload();
ownerDoc.location.reload();
}
else if (ot == errorDoc.getElementById('getMeOutOfHereButton')) {
else if (ot == ownerDoc.getElementById('getMeOutOfHereButton')) {
getMeOutOfHere();
}
}
else if (/^about:blocked/.test(errorDoc.documentURI)) {
else if (/^about:blocked/.test(ownerDoc.documentURI)) {
// The event came from a button on a malware/phishing block page
// First check whether it's malware or phishing, so that we can
// use the right strings/links
var isMalware = /e=malwareBlocked/.test(errorDoc.documentURI);
var isMalware = /e=malwareBlocked/.test(ownerDoc.documentURI);
if (ot == errorDoc.getElementById('getMeOutButton')) {
if (ot == ownerDoc.getElementById('getMeOutButton')) {
getMeOutOfHere();
}
else if (ot == errorDoc.getElementById('reportButton')) {
else if (ot == ownerDoc.getElementById('reportButton')) {
// This is the "Why is this site blocked" button. For malware,
// we can fetch a site-specific report, for phishing, we redirect
// to the generic page describing phishing protection.
@ -2774,7 +2769,7 @@ function BrowserOnClick(event) {
// append the current url, and go there.
try {
let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
reportURL += errorDoc.location.href;
reportURL += ownerDoc.location.href;
content.location = reportURL;
} catch (e) {
Components.utils.reportError("Couldn't get malware report URL: " + e);
@ -2788,7 +2783,7 @@ function BrowserOnClick(event) {
}
}
}
else if (ot == errorDoc.getElementById('ignoreWarningButton')) {
else if (ot == ownerDoc.getElementById('ignoreWarningButton')) {
// Allow users to override and continue through to the site,
// but add a notify bar as a reminder, so that they don't lose
// track after, e.g., tab switching.
@ -2843,23 +2838,31 @@ function BrowserOnClick(event) {
);
}
}
else if (/^about:home$/i.test(errorDoc.documentURI)) {
if (ot == errorDoc.getElementById("restorePreviousSession")) {
else if (/^about:home$/i.test(ownerDoc.documentURI)) {
if (ot == ownerDoc.getElementById("restorePreviousSession")) {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
if (ss.canRestoreLastSession)
ss.restoreLastSession();
errorDoc.getElementById("sessionRestoreContainer").hidden = true;
ownerDoc.getElementById("launcher").removeAttribute("session");
}
else if (ot == errorDoc.getElementById("pairDeviceLink")) {
if (Services.prefs.prefHasUserValue("services.sync.username")) {
gSyncUI.openAddDevice();
} else {
gSyncUI.openSetup("pair");
}
else if (ot == ownerDoc.getElementById("bookmarks")) {
PlacesCommandHook.showPlacesOrganizer("AllBookmarks");
}
else if (ot == errorDoc.getElementById("setupSyncLink")) {
gSyncUI.openSetup(null);
else if (ot == ownerDoc.getElementById("history")) {
PlacesCommandHook.showPlacesOrganizer("History");
}
else if (ot == ownerDoc.getElementById("settings")) {
openPreferences();
}
else if (ot == ownerDoc.getElementById("addons")) {
BrowserOpenAddonsMgr();
}
else if (ot == ownerDoc.getElementById("downloads")) {
BrowserDownloadsUI();
}
else if (ot == ownerDoc.getElementById("sync")) {
openPreferences("paneSync");
}
}
}
@ -5120,6 +5123,7 @@ var TabsProgressListener = {
// document URI is not yet the about:-uri of the error page.
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
Components.isSuccessCode(aStatus) &&
/^about:/.test(aWebProgress.DOMWindow.document.documentURI)) {
aBrowser.addEventListener("click", BrowserOnClick, false);
aBrowser.addEventListener("pagehide", function () {

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

@ -94,7 +94,11 @@ let gDrop = {
// A new link was dragged onto the grid. Create it by pinning its URL.
let dt = aEvent.dataTransfer;
let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/);
gPinnedLinks.pin({url: url, title: title}, index);
let link = {url: url, title: title};
gPinnedLinks.pin(link, index);
// Make sure the newly added link is not blocked.
gBlockedLinks.unblock(link);
}
},

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

@ -92,6 +92,7 @@ nsContextMenu.prototype = {
} catch (e) { }
this.isTextSelected = this.isTextSelection();
this.isContentSelected = this.isContentSelection();
this.onPlainTextLink = false;
// Initialize (disable/remove) menu items.
this.initItems();
@ -132,7 +133,6 @@ nsContextMenu.prototype = {
// Time to do some bad things and see if we've highlighted a URL that
// isn't actually linked.
var onPlainTextLink = false;
if (this.isTextSelected && !this.onLink) {
// Ok, we have some text, let's figure out if it looks like a URL.
let selection = document.commandDispatcher.focusedWindow
@ -190,14 +190,14 @@ nsContextMenu.prototype = {
if (uri && uri.host) {
this.linkURI = uri;
this.linkURL = this.linkURI.spec;
onPlainTextLink = true;
this.onPlainTextLink = true;
}
}
var shouldShow = this.onSaveableLink || isMailtoInternal || onPlainTextLink;
var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
this.showItem("context-openlink", shouldShow);
this.showItem("context-openlinkintab", shouldShow);
this.showItem("context-openlinkincurrent", onPlainTextLink);
this.showItem("context-openlinkincurrent", this.onPlainTextLink);
this.showItem("context-sep-open", shouldShow);
},
@ -222,9 +222,9 @@ nsContextMenu.prototype = {
this.showItem("context-savepage", shouldShow);
this.showItem("context-sendpage", shouldShow);
// Save+Send link depends on whether we're in a link.
this.showItem("context-savelink", this.onSaveableLink);
this.showItem("context-sendlink", this.onSaveableLink);
// Save+Send link depends on whether we're in a link, or selected text matches valid URL pattern.
this.showItem("context-savelink", this.onSaveableLink || this.onPlainTextLink);
this.showItem("context-sendlink", this.onSaveableLink || this.onPlainTextLink);
// Save image depends on having loaded its content, video and audio don't.
this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas);
@ -310,7 +310,7 @@ nsContextMenu.prototype = {
this.showItem("context-bookmarkpage",
!(this.isContentSelected || this.onTextInput || this.onLink ||
this.onImage || this.onVideo || this.onAudio));
this.showItem("context-bookmarklink", this.onLink && !this.onMailtoLink);
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink) || this.onPlainTextLink);
this.showItem("context-searchselect", isTextSelected);
this.showItem("context-keywordfield",
this.onTextInput && this.onKeywordField);
@ -1073,9 +1073,15 @@ nsContextMenu.prototype = {
// Save URL of clicked-on link.
saveLink: function() {
var doc = this.target.ownerDocument;
var linkText;
// If selected text is found to match valid URL pattern.
if (this.onPlainTextLink)
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
else
linkText = this.linkText();
urlSecurityCheck(this.linkURL, doc.nodePrincipal);
this.saveHelper(this.linkURL, this.linkText(), null, true, doc);
this.saveHelper(this.linkURL, linkText, null, true, doc);
},
sendLink: function() {
@ -1390,8 +1396,14 @@ nsContextMenu.prototype = {
},
bookmarkLink: function CM_bookmarkLink() {
var linkText;
// If selected text is found to match valid URL pattern.
if (this.onPlainTextLink)
linkText = document.commandDispatcher.focusedWindow.getSelection().toString().trim();
else
linkText = this.linkText();
window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId, this.linkURL,
this.linkText());
linkText);
},
addBookmarkForFrame: function CM_addBookmarkForFrame() {

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

@ -10,9 +10,6 @@ registerCleanupFunction(function() {
try {
Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
} catch (ex) {}
try {
Services.prefs.clearUserPref("services.sync.username");
} catch (ex) {}
});
let gTests = [
@ -112,121 +109,11 @@ let gTests = [
ok(snippetsElt, "Found snippets element");
is(snippetsElt.getElementsByTagName("span").length, 1,
"A default snippet is visible.");
let storage = getStorage();
storage.removeItem("snippets");
executeSoon(runNextTest);
}
},
{
desc: "Check sync links visibility before and after Sync setup",
setup: function ()
{
try {
Services.prefs.clearUserPref("services.sync.username");
} catch (ex) {}
Services.obs.notifyObservers(null, "weave:service:ready", null);
},
run: function ()
{
let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
let pairLink = doc.getElementById("pairDeviceLink");
let setupLink = doc.getElementById("setupSyncLink");
ok(pairLink, "Found 'Pair Device' link");
ok(setupLink, "Found 'Set Up Sync' link");
ok(!pairLink.hidden, "'Pair' link is visible before setup");
ok(!setupLink.hidden, "'Set Up' link is visible before setup");
Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
executeSoon(function () {
setupLink = doc.getElementById("setupSyncLink");
ok(setupLink.hidden, "'Set Up' link is hidden after setup");
ok(!pairLink.hidden, "'Pair' link is visible after setup");
executeSoon(runNextTest);
});
}
},
{
desc: "Check sync links visibility before and after Sync unlink",
setup: function ()
{
Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
Services.obs.notifyObservers(null, "weave:service:ready", null);
},
run: function ()
{
let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
let pairLink = doc.getElementById("pairDeviceLink");
let setupLink = doc.getElementById("setupSyncLink");
ok(!pairLink.hidden, "'Pair' link is visible before unlink");
ok(setupLink.hidden, "'Set Up' link is hidden before unlink");
Services.obs.notifyObservers(null, "weave:service:start-over", null);
executeSoon(function () {
setupLink = doc.getElementById("setupSyncLink");
ok(!setupLink.hidden, "'Set Up' link is visible after unlink");
ok(!pairLink.hidden, "'Pair' link is visible after unlink");
executeSoon(runNextTest);
});
}
},
{
desc: "Check Pair Device link opens correct dialog with Sync account ",
setup: function ()
{
Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
Services.obs.notifyObservers(null, "weave:service:ready", null);
},
run: function ()
{
expectDialogWindow("Sync:AddDevice");
let browser = gBrowser.selectedTab.linkedBrowser;
let button = browser.contentDocument.getElementById("pairDeviceLink");
EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
}
},
{
desc: "Check Pair Device link opens correct dialog without Sync account",
setup: function ()
{
try {
Services.prefs.clearUserPref("services.sync.username");
} catch (ex) {}
Services.obs.notifyObservers(null, "weave:service:ready", null);
},
run: function ()
{
expectDialogWindow("Weave:AccountSetup");
let browser = gBrowser.selectedTab.linkedBrowser;
let button = browser.contentDocument.getElementById("pairDeviceLink");
EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
}
},
{
desc: "Check Sync Setup link opens correct dialog (without Sync account)",
setup: function ()
{
try {
Services.prefs.clearUserPref("services.sync.username");
} catch (ex) {}
Services.obs.notifyObservers(null, "weave:service:ready", null);
},
run: function ()
{
expectDialogWindow("Weave:AccountSetup");
let browser = gBrowser.selectedTab.linkedBrowser;
let button = browser.contentDocument.getElementById("setupSyncLink");
EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
}
},
];
function test()
@ -272,22 +159,6 @@ function runNextTest()
}
}
function expectDialogWindow(expectedDialog) {
Services.ww.registerNotification(function onWindow(subject, topic) {
let win = subject.QueryInterface(Components.interfaces.nsIDOMWindow);
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
let wintype = win.document.documentElement.getAttribute("windowtype");
if (topic == "domwindowopened" && wintype == expectedDialog) {
Services.ww.unregisterNotification(onWindow);
// Clean up dialog.
win.close();
executeSoon(runNextTest);
}
}, false);
});
}
function getStorage()
{
let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);

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

@ -25,6 +25,7 @@ _BROWSER_FILES = \
browser_newtab_bug723121.js \
browser_newtab_bug725996.js \
browser_newtab_bug734043.js \
browser_newtab_bug735987.js \
head.js \
$(NULL)

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

@ -25,7 +25,7 @@ function runTests() {
checkGrid("0,1,2,3,7,8,9,,");
// we removed a pinned site
reset();
yield restore();
setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",1");
@ -37,7 +37,7 @@ function runTests() {
// we remove the last site on the grid (which is pinned) and expect the gap
// to be re-filled and the new site to be unpinned
reset();
yield restore();
setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks(",,,,,,,,8");
@ -49,7 +49,7 @@ function runTests() {
// we remove the first site on the grid with the last one pinned. all cells
// but the last one should shift to the left and a new site fades in
reset();
yield restore();
setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks(",,,,,,,,8");

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

@ -2,13 +2,11 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
// TODO Bug 735166 - Intermittent timeout in browser_newtab_bug734043.js
return;
setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
let receivedError = false;
let block = cw.document.querySelector(".newtab-control-block");
@ -19,10 +17,8 @@ function runTests() {
cw.addEventListener("error", onError);
for (let i = 0; i < 3; i++) {
for (let i = 0; i < 3; i++)
EventUtils.synthesizeMouseAtCenter(block, {}, cw);
yield executeSoon(TestRunner.next);
}
yield whenPagesUpdated();
ok(!receivedError, "we got here without any errors");

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

@ -0,0 +1,22 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[1]);
checkGrid("0,99p,1,2,3,4,5,6,7");
yield blockCell(cells[1]);
checkGrid("0,1,2,3,4,5,6,7,8");
yield simulateDrop(cells[1]);
checkGrid("0,99p,1,2,3,4,5,6,7");
yield blockCell(cells[1]);
checkGrid("0,1,2,3,4,5,6,7,8");
}

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

@ -10,8 +10,6 @@ Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
let NewTabUtils = tmp.NewTabUtils;
registerCleanupFunction(function () {
reset();
while (gBrowser.tabs.length > 1)
gBrowser.removeTab(gBrowser.tabs[1]);
@ -57,8 +55,29 @@ let TestRunner = {
try {
TestRunner._iter.next();
} catch (e if e instanceof StopIteration) {
finish();
TestRunner.finish();
}
},
/**
* Finishes all tests and cleans up.
*/
finish: function () {
function cleanupAndFinish() {
// Restore the old provider.
NewTabUtils.links._provider = originalProvider;
whenPagesUpdated(finish);
NewTabUtils.restore();
}
let callbacks = NewTabUtils.links._populateCallbacks;
let numCallbacks = callbacks.length;
if (numCallbacks)
callbacks.splice(0, numCallbacks, cleanupAndFinish);
else
cleanupAndFinish();
}
};
@ -106,13 +125,11 @@ function setPinnedLinks(aLinksPattern) {
}
/**
* Resets the lists of blocked and pinned links and clears the storage.
* Restore the grid state.
*/
function reset() {
NewTabUtils.reset();
// Restore the old provider to prevent memory leaks.
NewTabUtils.links._provider = originalProvider;
function restore() {
whenPagesUpdated();
NewTabUtils.restore();
}
/**
@ -269,11 +286,11 @@ function simulateDrop(aDropTarget, aDragSource) {
/**
* Resumes testing when all pages have been updated.
*/
function whenPagesUpdated() {
function whenPagesUpdated(aCallback) {
let page = {
update: function () {
NewTabUtils.allPages.unregister(this);
executeSoon(TestRunner.next);
executeSoon(aCallback || TestRunner.next);
}
};

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

@ -58,6 +58,8 @@ Browser context menu subtest.
<menuitem></menuitem>
</menu>
</div>
<div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
<div id="test-select-text-link">http://mozilla.com</div>
</body>
</html>

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

@ -20,6 +20,7 @@ Browser context menu tests.
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -72,6 +73,16 @@ function invokeItemAction(generatedItemId)
ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
}
function selectText(element) {
// Clear any previous selections before selecting new element.
subwindow.getSelection().removeAllRanges();
var div = subwindow.document.createRange();
div.setStartBefore(element);
div.setEndAfter(element);
subwindow.getSelection().addRange(div);
}
function getVisibleMenuItems(aMenu, aData) {
var items = [];
var accessKeys = {};
@ -667,6 +678,45 @@ function runTest(testNum) {
"context-viewinfo", true
].concat(inspectItems));
closeContextMenu();
selectText(selecttext); // Select text prior to opening context menu.
openContextMenuFor(selecttext); // Invoke context menu for next test.
return;
case 22:
// Context menu for selected text
if (Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
checkContextMenu(["context-copy", true,
"context-selectall", true,
"---", null,
"context-searchselect", true,
"context-viewpartialsource-selection", true
].concat(inspectItems));
}
closeContextMenu();
selectText(selecttextlink); // Select text prior to opening context menu.
openContextMenuFor(selecttextlink); // Invoke context menu for next test.
return;
case 23:
// Context menu for selected text which matches valid URL pattern
if (Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
checkContextMenu(["context-openlinkincurrent", true,
"context-openlinkintab", true,
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
"context-savelink", true,
"context-sendlink", true,
"context-copy", true,
"context-selectall", true,
"---", null,
"context-searchselect", true,
"context-viewpartialsource-selection", true
].concat(inspectItems));
}
closeContextMenu();
subwindow.close();
SimpleTest.finish();
@ -674,7 +724,6 @@ function runTest(testNum) {
/*
* Other things that would be nice to test:
* - selected text
* - spelling / misspelled word (in text input?)
* - check state of disabled items
* - test execution of menu items (maybe as a separate test?)
@ -734,6 +783,8 @@ function startTest() {
contenteditable.focus(); // content editable needs to be focused to enable spellcheck
inputspell = subwindow.document.getElementById("test-input-spellcheck");
pagemenu = subwindow.document.getElementById("test-pagemenu");
selecttext = subwindow.document.getElementById("test-select-text");
selecttextlink = subwindow.document.getElementById("test-select-text-link");
contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false);
runTest(1);

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

@ -110,11 +110,33 @@ function getBoolPref(prefname, def)
}
}
// openUILink handles clicks on UI elements that cause URLs to load.
function openUILink( url, e, ignoreButton, ignoreAlt, allowKeywordFixup, postData, referrerUrl )
{
var where = whereToOpenLink(e, ignoreButton, ignoreAlt);
openUILinkIn(url, where, allowKeywordFixup, postData, referrerUrl);
/* openUILink handles clicks on UI elements that cause URLs to load.
*
* As the third argument, you may pass an object with the same properties as
* accepted by openUILinkIn, plus "ignoreButton" and "ignoreAlt".
*/
function openUILink(url, event, aIgnoreButton, aIgnoreAlt, aAllowThirdPartyFixup,
aPostData, aReferrerURI) {
let params;
if (aIgnoreButton && typeof aIgnoreButton == "object") {
params = aIgnoreButton;
// don't forward "ignoreButton" and "ignoreAlt" to openUILinkIn
aIgnoreButton = params.ignoreButton;
aIgnoreAlt = params.ignoreAlt;
delete params.ignoreButton;
delete params.ignoreAlt;
} else {
params = {
allowThirdPartyFixup: aAllowThirdPartyFixup,
postData: aPostData,
referrerURI: aReferrerURI
};
}
let where = whereToOpenLink(event, aIgnoreButton, aIgnoreAlt);
openUILinkIn(url, where, params);
}

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

@ -16,13 +16,21 @@ browser.jar:
* content/browser/aboutDialog.js (content/aboutDialog.js)
* content/browser/aboutDialog.css (content/aboutDialog.css)
* content/browser/aboutRobots.xhtml (content/aboutRobots.xhtml)
* content/browser/aboutHome.xhtml (content/aboutHome.xhtml)
* content/browser/aboutHome.js (content/aboutHome.js)
* content/browser/aboutHome.css (content/aboutHome.css)
content/browser/aboutHome-restore-icon.png (content/aboutHome-restore-icon.png)
content/browser/aboutHome-restore-icon-small.png (content/aboutHome-restore-icon-small.png)
content/browser/aboutHome-snippet1.png (content/aboutHome-snippet1.png)
content/browser/aboutHome-snippet2.png (content/aboutHome-snippet2.png)
* content/browser/abouthome/aboutHome.xhtml (content/abouthome/aboutHome.xhtml)
* content/browser/abouthome/aboutHome.js (content/abouthome/aboutHome.js)
* content/browser/abouthome/aboutHome.css (content/abouthome/aboutHome.css)
content/browser/abouthome/snippet1.png (content/abouthome/snippet1.png)
content/browser/abouthome/snippet2.png (content/abouthome/snippet2.png)
content/browser/abouthome/bookmarks.png (content/abouthome/bookmarks.png)
content/browser/abouthome/history.png (content/abouthome/history.png)
content/browser/abouthome/settings.png (content/abouthome/settings.png)
content/browser/abouthome/addons.png (content/abouthome/addons.png)
content/browser/abouthome/downloads.png (content/abouthome/downloads.png)
content/browser/abouthome/sync.png (content/abouthome/sync.png)
content/browser/abouthome/restore.png (content/abouthome/restore.png)
content/browser/abouthome/restore-large.png (content/abouthome/restore-large.png)
content/browser/abouthome/mozilla.png (content/abouthome/mozilla.png)
content/browser/abouthome/noise.png (content/abouthome/noise.png)
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
* content/browser/browser.css (content/browser.css)

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

@ -102,7 +102,7 @@ static RedirEntry kRedirMap[] = {
{ "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
nsIAboutModule::ALLOW_SCRIPT },
#endif
{ "home", "chrome://browser/content/aboutHome.xhtml",
{ "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT },
{ "newtab", "chrome://browser/content/newtab/newTab.xul",

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

@ -887,7 +887,7 @@ let AboutHomeUtils = {
loadSnippetsURL: function AHU_loadSnippetsURL()
{
const STARTPAGE_VERSION = 1;
const STARTPAGE_VERSION = 2;
let updateURL = Services.prefs
.getCharPref(this.SNIPPETS_URL_PREF)
.replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);

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

@ -68,7 +68,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "KeywordURLResetPrompter",
"resource:///modules/KeywordURLResetPrompter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "webappsUI",
"resource://gre/modules/webappsUI.jsm");
"resource:///modules/webappsUI.jsm");
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";

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

@ -231,73 +231,8 @@ var tests = [
}
catch (e) {}
}
},
{
desc: "HTML restore into folder: normal restore should succeed",
currTopic: NSIOBSERVER_TOPIC_BEGIN,
finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
data: NSIOBSERVER_DATA_HTML,
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.html");
addBookmarks();
importer.exportHTMLToFile(this.file);
remove_all_bookmarks();
this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
"test folder",
bmsvc.DEFAULT_INDEX);
print(" Sanity check: createFolder() should have succeeded");
do_check_true(this.folderId > 0);
try {
importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
}
catch (e) {
do_throw(" Restore should not have failed");
}
}
},
{
desc: "HTML restore into folder: empty file should succeed",
currTopic: NSIOBSERVER_TOPIC_BEGIN,
finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
data: NSIOBSERVER_DATA_HTML,
run: function () {
this.file = createFile("bookmarks-test_restoreNotification.init.html");
this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
"test folder",
bmsvc.DEFAULT_INDEX);
print(" Sanity check: createFolder() should have succeeded");
do_check_true(this.folderId > 0);
try {
importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
}
catch (e) {
do_throw(" Restore should not have failed");
}
}
},
{
desc: "HTML restore into folder: nonexistent file should fail",
currTopic: NSIOBSERVER_TOPIC_BEGIN,
finalTopic: NSIOBSERVER_TOPIC_FAILED,
data: NSIOBSERVER_DATA_HTML,
run: function () {
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
"test folder",
bmsvc.DEFAULT_INDEX);
print(" Sanity check: createFolder() should have succeeded");
do_check_true(this.folderId > 0);
try {
importer.importHTMLFromFileToFolder(this.file, this.folderId, false);
do_throw(" Restore should have failed");
}
catch (e) {}
}
}
];
// nsIObserver that observes bookmarks-restore-begin.

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

@ -218,58 +218,6 @@ add_test(function test_emptytitle_export()
});
});
add_test(function test_import_preplaces_to_folder()
{
// Test importing a pre-Places canonical bookmarks file to a specific folder.
// 1. create a new folder
// 2. import bookmarks.preplaces.html to that folder
// 3. run the test-suite
let testFolder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarksMenuFolderId, "test-import",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
try {
importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
waitForAsyncUpdates(function () {
// Import-to-folder creates subfolders for toolbar and unfiled.
testImportedBookmarksToFolder(testFolder);
waitForAsyncUpdates(function () {
remove_all_bookmarks();
run_next_test();
});
});
});
add_test(function test_import_to_folder()
{
// Test importing a Places canonical bookmarks file to a specific folder.
// 1. create a new folder
// 2. import bookmarks.exported.html to that folder
// 3. run the test-suite
let testFolder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarksMenuFolderId, "test-import",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
try {
importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
waitForAsyncUpdates(function () {
// Import-to-folder creates subfolders for toolbar and unfiled.
testImportedBookmarksToFolder(testFolder);
waitForAsyncUpdates(function () {
remove_all_bookmarks();
run_next_test();
});
});
});
add_test(function test_import_ontop()
{
// Test importing the exported bookmarks.html file *on top of* the existing

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

@ -72,7 +72,7 @@ const Cr = Components.results;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
const STATE_RUNNING_STR = "running";
const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes

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

@ -131,7 +131,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/debug.js");
Cu.import("resource:///modules/TelemetryTimestamps.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
Cu.import("resource://gre/modules/NetUtil.jsm");

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

@ -36,9 +36,8 @@
function test() {
/** Test for Bug 484108 **/
requestLongerTimeout(2);
waitForExplicitFinish();
requestLongerTimeout(3);
// builds the tests state based on a few parameters
function buildTestState(num, selected, hidden) {
@ -54,109 +53,105 @@ function test() {
return state;
}
// builds an array of the indexs we expect to see in the order they get loaded
function buildExpectedOrder(num, selected, shown) {
// assume selected is 1-based index
selected--;
let expected = [selected];
// fill left to selected if space
for (let i = selected - (shown - expected.length); i >= 0 && i < selected; i++)
expected.push(i);
// fill from left to right until right length or end
for (let i = selected + 1; expected.length < shown && i < num; i++)
expected.push(i);
// fill in the remaining
for (let i = 0; i < num; i++) {
if (expected.indexOf(i) == -1) {
expected.push(i);
}
let tests = [
{ testNum: 1,
totalTabs: 13,
selectedTab: 1,
shownTabs: 6,
hiddenTabs: [],
order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
},
{ testNum: 2,
totalTabs: 13,
selectedTab: 13,
shownTabs: 6,
hiddenTabs: [],
order: [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]
},
{ testNum: 3,
totalTabs: 13,
selectedTab: 4,
shownTabs: 6,
hiddenTabs: [],
order: [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]
},
{ testNum: 4,
totalTabs: 13,
selectedTab: 11,
shownTabs: 6,
hiddenTabs: [],
order: [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]
},
{ testNum: 5,
totalTabs: 13,
selectedTab: 13,
shownTabs: 6,
hiddenTabs: [0, 4, 9],
order: [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]
},
{ testNum: 6,
totalTabs: 13,
selectedTab: 4,
shownTabs: 6,
hiddenTabs: [1, 7, 12],
order: [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]
},
{ testNum: 7,
totalTabs: 13,
selectedTab: 4,
shownTabs: 6,
hiddenTabs: [0, 1, 2],
order: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]
}
return expected;
}
// the number of tests we're running
let numTests = 7;
let completedTests = 0;
];
let tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
let testIndex = 0;
function runTest(testNum, totalTabs, selectedTab, shownTabs, hiddenTabs, order) {
let test = {
state: buildTestState(totalTabs, selectedTab, hiddenTabs),
numTabsToShow: shownTabs,
expectedOrder: order,
actualOrder: [],
windowWidth: null,
callback: null,
window: null,
function runNextTest() {
if (tests.length == 0) {
finish();
return;
}
handleSSTabRestoring: function (aEvent) {
let tab = aEvent.originalTarget;
let tabbrowser = this.window.gBrowser;
let currentIndex = Array.indexOf(tabbrowser.tabs, tab);
this.actualOrder.push(currentIndex);
info ("Starting test " + (++testIndex));
let test = tests.shift();
let state = buildTestState(test.totalTabs, test.selectedTab, test.hiddenTabs);
let tabbarWidth = Math.floor((test.shownTabs - 0.5) * tabMinWidth);
let win = openDialog(location, "_blank", "chrome,all,dialog=no");
let actualOrder = [];
if (this.actualOrder.length < this.state.windows[0].tabs.length)
return;
win.addEventListener("SSTabRestoring", function onSSTabRestoring(aEvent) {
let tab = aEvent.originalTarget;
let currentIndex = Array.indexOf(win.gBrowser.tabs, tab);
actualOrder.push(currentIndex);
// all of the tabs should be restoring or restored by now
is(this.actualOrder.length, this.state.windows[0].tabs.length,
"Test #" + testNum + ": Number of restored tabs is as expected");
if (actualOrder.length < state.windows[0].tabs.length)
return;
is(this.actualOrder.join(" "), this.expectedOrder.join(" "),
"Test #" + testNum + ": 'visible' tabs restored first");
// all of the tabs should be restoring or restored by now
is(actualOrder.length, state.windows[0].tabs.length,
"Test #" + testIndex + ": Number of restored tabs is as expected");
// cleanup
this.window.close();
// if we're all done, explicitly finish
if (++completedTests == numTests) {
this.window.removeEventListener("load", this, false);
this.window.removeEventListener("SSTabRestoring", this, false);
finish();
}
},
is(actualOrder.join(" "), test.order.join(" "),
"Test #" + testIndex + ": 'visible' tabs restored first");
handleLoad: function (aEvent) {
let _this = this;
executeSoon(function () {
let extent = _this.window.outerWidth - _this.window.gBrowser.tabContainer.mTabstrip.scrollClientSize;
let windowWidth = _this.tabbarWidth + extent;
_this.window.resizeTo(windowWidth, _this.window.outerHeight);
ss.setWindowState(_this.window, JSON.stringify(_this.state), true);
});
},
// Cleanup.
win.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
win.close();
executeSoon(runNextTest);
}, false);
// Implement nsIDOMEventListener for handling various window and tab events
handleEvent: function (aEvent) {
switch (aEvent.type) {
case "load":
this.handleLoad(aEvent);
break;
case "SSTabRestoring":
this.handleSSTabRestoring(aEvent);
break;
}
},
win.addEventListener("load", function onLoad(aEvent) {
win.removeEventListener("load", onLoad, false);
executeSoon(function () {
let extent = win.outerWidth - win.gBrowser.tabContainer.mTabstrip.scrollClientSize;
let windowWidth = tabbarWidth + extent;
win.resizeTo(windowWidth, win.outerHeight);
ss.setWindowState(win, JSON.stringify(state), true);
});
}, false);
};
// setup and actually run the test
run: function () {
this.tabbarWidth = Math.floor((this.numTabsToShow - 0.5) * tabMinWidth);
this.window = openDialog(location, "_blank", "chrome,all,dialog=no");
this.window.addEventListener("SSTabRestoring", this, false);
this.window.addEventListener("load", this, false);
}
};
test.run();
}
// actually create & run the tests
runTest(1, 13, 1, 6, [], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
runTest(2, 13, 13, 6, [], [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]);
runTest(3, 13, 4, 6, [], [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]);
runTest(4, 13, 11, 6, [], [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]);
runTest(5, 13, 13, 6, [0, 4, 9], [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]);
runTest(6, 13, 4, 6, [1, 7, 12], [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]);
runTest(7, 13, 4, 6, [0, 1, 2], [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]);
// finish() is run by the last test to finish, so no cleanup down here
runNextTest();
}

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

@ -2,6 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let assertNumberOfTabs = function (num, msg) {
is(gBrowser.tabs.length, num, msg);
}
@ -25,11 +27,13 @@ function test() {
assertNumberOfPinnedTabs(2, "both tabs are now pinned");
// run the test
ss.setBrowserState(JSON.stringify({ windows: [{ tabs: [{ url: "about:blank" }] }] }));
assertNumberOfTabs(1, "one tab left after setBrowserState()");
assertNumberOfPinnedTabs(0, "there are no pinned tabs");
is(gBrowser.tabs[0].linkedBrowser, linkedBrowser, "first tab's browser got re-used");
waitForExplicitFinish();
waitForSaveState(finish);
waitForBrowserState(
{ windows: [{ tabs: [{ url: "about:blank" }] }] },
function () {
assertNumberOfTabs(1, "one tab left after setBrowserState()");
assertNumberOfPinnedTabs(0, "there are no pinned tabs");
is(gBrowser.tabs[0].linkedBrowser, linkedBrowser, "first tab's browser got re-used");
finish();
}
);
}

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

@ -14,10 +14,14 @@ function test() {
// window is now in _closedWindows.
waitForExplicitFinish();
requestLongerTimeout(2);
// We speed up the interval between session saves to ensure that the test
// runs quickly.
Services.prefs.setIntPref("browser.sessionstore.interval", 2000);
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.sessionstore.interval");
});
// We'll clear all closed windows to make sure our state is clean
// forgetClosedWindow doesn't trigger a delayed save
@ -97,7 +101,6 @@ function openTab() {
}
function done() {
Services.prefs.clearUserPref("browser.sessionstore.interval");
gBrowser.removeTab(newTab);
// The API still represents the closed window as closed, so we can clear it
// with the API, but just to make sure...

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

@ -7,9 +7,14 @@ let tabState = {
function test() {
waitForExplicitFinish();
requestLongerTimeout(2);
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.sessionstore.interval");
});
let tab = gBrowser.addTab("about:blank");
registerCleanupFunction(function () gBrowser.removeTab(tab));
let browser = tab.linkedBrowser;
@ -26,7 +31,9 @@ function test() {
is(entries.length, 1, "tab has one history entry");
ok(!entries[0].children, "history entry has no subframes");
finish();
// Make sure that we reset the state.
let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
waitForBrowserState(blankState, finish);
});
// reload the browser to deprecate the subframes
@ -36,8 +43,8 @@ function test() {
// create a dynamic subframe
let doc = browser.contentDocument;
let iframe = doc.createElement("iframe");
iframe.setAttribute("src", "about:mozilla");
doc.body.appendChild(iframe);
iframe.setAttribute("src", "about:mozilla");
});
});
}
@ -53,5 +60,5 @@ function whenChildCount(aEntry, aChildCount, aCallback) {
if (aEntry.childCount == aChildCount)
aCallback();
else
executeSoon(function () whenChildCount(aEntry, aChildCount, aCallback));
setTimeout(function () whenChildCount(aEntry, aChildCount, aCallback), 100);
}

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

@ -7,9 +7,14 @@ let tabState = {
function test() {
waitForExplicitFinish();
requestLongerTimeout(2);
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.sessionstore.interval");
});
let tab = gBrowser.addTab("about:blank");
registerCleanupFunction(function () gBrowser.removeTab(tab));
let browser = tab.linkedBrowser;
@ -25,7 +30,11 @@ function test() {
let sessionHistory = browser.sessionHistory;
let entry = sessionHistory.getEntryAtIndex(0, false);
whenChildCount(entry, 0, finish);
whenChildCount(entry, 0, function () {
// Make sure that we reset the state.
let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
waitForBrowserState(blankState, finish);
});
});
// reload the browser to deprecate the subframes
@ -35,8 +44,8 @@ function test() {
// create a dynamic subframe
let doc = browser.contentDocument;
let iframe = doc.createElement("iframe");
iframe.setAttribute("src", "about:mozilla");
doc.body.appendChild(iframe);
iframe.setAttribute("src", "about:mozilla");
});
});
}
@ -52,5 +61,5 @@ function whenChildCount(aEntry, aChildCount, aCallback) {
if (aEntry.childCount == aChildCount)
aCallback();
else
executeSoon(function () whenChildCount(aEntry, aChildCount, aCallback));
setTimeout(function () whenChildCount(aEntry, aChildCount, aCallback), 100);
}

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

@ -94,11 +94,21 @@ let WindowMessageHandler = {
!webProgress.isLoadingDocument);
sendAsyncMessage(cx.name, {isLoaded: isLoaded});
},
// ----------
// Function: isImageDocument
// Checks if the currently active document is an image document or not.
isImageDocument: function WMH_isImageDocument(cx) {
let isImageDocument = (content.document instanceof Ci.nsIImageDocument);
sendAsyncMessage(cx.name, {isImageDocument: isImageDocument});
}
};
// add message listeners
addMessageListener("Panorama:isDocumentLoaded", WindowMessageHandler.isDocumentLoaded);
addMessageListener("Panorama:isImageDocument", WindowMessageHandler.isImageDocument);
// ----------
// WebProgressListener

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

@ -234,10 +234,12 @@ function GroupItem(listOfEls, options) {
.addClass("appTabTray")
.appendTo(appTabTrayContainer);
AllTabs.tabs.forEach(function(xulTab) {
let pinnedTabCount = gBrowser._numPinnedTabs;
AllTabs.tabs.forEach(function (xulTab, index) {
// only adjust tray when it's the last app tab.
if (xulTab.pinned)
self.addAppTab(xulTab, {dontAdjustTray: true});
});
this.addAppTab(xulTab, {dontAdjustTray: index + 1 < pinnedTabCount});
}, this);
// ___ Undo Close
this.$undoContainer = null;
@ -758,7 +760,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
UI.setActive(self);
self._sendToSubscribers("groupShown", { groupItemId: self.id });
self._sendToSubscribers("groupShown");
};
let $container = iQ(this.container).show();
@ -927,7 +929,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
easing: "tabviewBounce",
duration: 170,
complete: function() {
self._sendToSubscribers("groupHidden", { groupItemId: self.id });
self._sendToSubscribers("groupHidden");
}
});
}, 50);
@ -1052,7 +1054,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.arrange({animate: !options.immediately});
this._unfreezeItemSize({dontArrange: true});
this._sendToSubscribers("childAdded",{ groupItemId: this.id, item: item });
this._sendToSubscribers("childAdded", { item: item });
UI.setReorderTabsOnHide(this);
} catch(e) {
@ -1155,7 +1157,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this._unfreezeItemSize({dontArrange: true});
}
this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
this._sendToSubscribers("childRemoved", { item: item });
} catch(e) {
Utils.log(e);
}
@ -1181,36 +1183,46 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Adds the given xul:tab as an app tab in this group's apptab tray
//
// Parameters:
// xulTab - the xul:tab.
// options - change how the app tab is added.
//
// Options:
// dontAdjustTray - (boolean) if true, the $appTabTray size is not adjusted,
// which means that the adjustAppTabTray() method is not
// called.
// position - the position of the app tab should be added to.
// dontAdjustTray - (boolean) if true, do not adjust the tray.
addAppTab: function GroupItem_addAppTab(xulTab, options) {
let self = this;
GroupItems.getAppTabFavIconUrl(xulTab, function(iconUrl) {
let self = this;
let $appTab = iQ("<img>")
.addClass("appTabIcon")
.attr("src", iconUrl)
.data("xulTab", xulTab)
.mousedown(function GroupItem_addAppTab_onAppTabMousedown(event) {
// stop mousedown propagation to disable group dragging on app tabs
event.stopPropagation();
})
.click(function GroupItem_addAppTab_onAppTabClick(event) {
if (!Utils.isLeftClick(event))
return;
let iconUrl = GroupItems.getAppTabFavIconUrl(xulTab);
let $appTab = iQ("<img>")
.addClass("appTabIcon")
.attr("src", iconUrl)
.data("xulTab", xulTab)
.appendTo(this.$appTabTray)
.mousedown(function onAppTabMousedown(event) {
// stop mousedown propagation to disable group dragging on app tabs
event.stopPropagation();
})
.click(function(event) {
if (!Utils.isLeftClick(event))
return;
UI.setActive(self, { dontSetActiveTabInGroup: true });
UI.goToTab(iQ(this).data("xulTab"));
});
UI.setActive(self, { dontSetActiveTabInGroup: true });
UI.goToTab(iQ(this).data("xulTab"));
});
if (options && "position" in options) {
let children = this.$appTabTray[0].childNodes;
// adjust the tray, if needed.
if (!options || !options.dontAdjustTray)
this.adjustAppTabTray(true);
if (options.position >= children.length)
$appTab.appendTo(this.$appTabTray);
else
this.$appTabTray[0].insertBefore($appTab[0], children[options.position]);
} else {
$appTab.appendTo(this.$appTabTray);
}
if (!options || !options.dontAdjustTray)
this.adjustAppTabTray(true);
this._sendToSubscribers("appTabIconAdded", { item: $appTab });
}.bind(this));
},
// ----------
@ -2078,16 +2090,11 @@ let GroupItems = {
if (!xulTab.pinned)
return;
let iconUrl = this.getAppTabFavIconUrl(xulTab);
this.groupItems.forEach(function(groupItem) {
iQ(".appTabIcon", groupItem.$appTabTray).each(function(icon) {
let $icon = iQ(icon);
if ($icon.data("xulTab") != xulTab)
return true;
if (iconUrl != $icon.attr("src"))
$icon.attr("src", iconUrl);
return false;
this.getAppTabFavIconUrl(xulTab, function(iconUrl) {
iQ(".appTabIcon").each(function GroupItems__updateAppTabIcons_forEach(icon) {
let $icon = iQ(icon);
if ($icon.data("xulTab") == xulTab && iconUrl != $icon.attr("src"))
$icon.attr("src", iconUrl);
});
});
},
@ -2095,15 +2102,10 @@ let GroupItems = {
// ----------
// Function: getAppTabFavIconUrl
// Gets the fav icon url for app tab.
getAppTabFavIconUrl: function GroupItems_getAppTabFavIconUrl(xulTab) {
let iconUrl;
if (UI.shouldLoadFavIcon(xulTab.linkedBrowser))
iconUrl = UI.getFavIconUrlForTab(xulTab);
else
iconUrl = gFavIconService.defaultFavicon.spec;
return iconUrl;
getAppTabFavIconUrl: function GroupItems_getAppTabFavIconUrl(xulTab, callback) {
UI.getFavIconUrlForTab(xulTab, function GroupItems_getAppTabFavIconUrl_getFavIconUrlForTab(iconUrl) {
callback(iconUrl || gFavIconService.defaultFavicon.spec);
});
},
// ----------

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

@ -985,20 +985,21 @@ let TabItems = {
let tabItem = tab._tabViewTabItem;
// Even if the page hasn't loaded, display the favicon and title
// ___ icon
if (UI.shouldLoadFavIcon(tab.linkedBrowser)) {
let iconUrl = UI.getFavIconUrlForTab(tab);
if (tabItem.$favImage[0].src != iconUrl)
tabItem.$favImage[0].src = iconUrl;
iQ(tabItem.$fav[0]).show();
} else {
if (tabItem.$favImage[0].hasAttribute("src"))
tabItem.$favImage[0].removeAttribute("src");
iQ(tabItem.$fav[0]).hide();
}
UI.getFavIconUrlForTab(tab, function TabItems__update_getFavIconUrlCallback(iconUrl) {
let favImage = tabItem.$favImage[0];
let fav = tabItem.$fav;
if (iconUrl) {
if (favImage.src != iconUrl)
favImage.src = iconUrl;
fav.show();
} else {
if (favImage.hasAttribute("src"))
favImage.removeAttribute("src");
fav.hide();
}
tabItem._sendToSubscribers("iconUpdated");
});
// ___ label
let label = tab.label;

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

@ -158,6 +158,7 @@ _BROWSER_FILES = \
browser_tabview_bug673196.js \
browser_tabview_bug673729.js \
browser_tabview_bug677310.js \
browser_tabview_bug678374.js \
browser_tabview_bug679853.js \
browser_tabview_bug681599.js \
browser_tabview_bug685476.js \
@ -192,6 +193,8 @@ _BROWSER_FILES = \
search2.html \
test_bug600645.html \
test_bug644097.html \
test_bug678374.html \
test_bug678374_icon16.png \
$(NULL)
# browser_tabview_bug597980.js is disabled for leaking, see bug 711907

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

@ -4,15 +4,13 @@
function test() {
waitForExplicitFinish();
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
showTabView(onTabViewWindowLoaded);
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let contentWindow = TabView.getContentWindow();
// establish initial state
is(contentWindow.GroupItems.groupItems.length, 1,
@ -36,60 +34,61 @@ function onTabViewWindowLoaded() {
is(appTabCount(groupItemOne), 0, "there are no app tab icons");
// pin the tab, make sure the TabItem goes away and the icon comes on
whenAppTabIconAdded(function() {
is(groupItemOne._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
// create a second group and make sure it gets the icon too
box.offset(box.width + 20, 0);
let groupItemTwo = new contentWindow.GroupItem([],
{ bounds: box, title: "test2" });
whenAppTabIconAdded(function() {
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
is(appTabCount(groupItemTwo), 1,
"there's an app tab icon in the second group");
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItemOne);
// unpin the tab, make sure the icon goes away and the TabItem comes on
gBrowser.unpinTab(xulTab);
is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
is(appTabCount(groupItemOne), 0, "the icon is gone from group one");
is(appTabCount(groupItemTwo), 0, "the icon is gone from group two");
whenAppTabIconAdded(function() {
// close the second group
groupItemTwo.close();
// find app tab in group and hit it
whenTabViewIsHidden(function() {
ok(!TabView.isVisible(),
"Tab View is hidden because we clicked on the app tab");
// delete the app tab and make sure its icon goes away
gBrowser.removeTab(xulTab);
is(appTabCount(groupItemOne), 0, "closing app tab removes its icon");
// clean up
groupItemOne.close();
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
ok(!TabView.isVisible(), "we finish with Tab View not visible");
finish();
});
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
});
gBrowser.pinTab(xulTab);
});
});
gBrowser.pinTab(xulTab);
is(groupItemOne._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItemOne), 1, "there's now one app tab icon");
// create a second group and make sure it gets the icon too
box.offset(box.width + 20, 0);
let groupItemTwo = new contentWindow.GroupItem([],
{ bounds: box, title: "test2" });
is(contentWindow.GroupItems.groupItems.length, 3, "we now have three groups");
is(appTabCount(groupItemTwo), 1,
"there's an app tab icon in the second group");
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItemOne);
// unpin the tab, make sure the icon goes away and the TabItem comes on
gBrowser.unpinTab(xulTab);
is(groupItemOne._children.length, 1, "the app tab's TabItem is back");
is(appTabCount(groupItemOne), 0, "the icon is gone from group one");
is(appTabCount(groupItemTwo), 0, "the icon is gone from group 2");
// pin the tab again
gBrowser.pinTab(xulTab);
// close the second group
groupItemTwo.close();
// find app tab in group and hit it
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
ok(!TabView.isVisible(),
"Tab View is hidden because we clicked on the app tab");
// delete the app tab and make sure its icon goes away
gBrowser.removeTab(xulTab);
is(appTabCount(groupItemOne), 0, "closing app tab removes its icon");
// clean up
groupItemOne.close();
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
ok(!TabView.isVisible(), "we finish with Tab View not visible");
finish();
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
let appTabIcons = groupItemOne.container.getElementsByClassName("appTabIcon");
EventUtils.sendMouseEvent({ type: "click" }, appTabIcons[0], contentWindow);
}
function appTabCount(groupItem) {

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

@ -3,6 +3,7 @@
function test() {
waitForExplicitFinish();
requestLongerTimeout(2);
newWindowWithTabView(onTabViewWindowLoaded);
}
@ -105,8 +106,8 @@ function onTabViewWindowLoaded(win) {
// Close the window and we're done!
win.close();
finish();
}, 6000, false);
},1000);
}, 10000, false);
}, 2000);
});

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

@ -53,87 +53,98 @@ function onTabViewShown(win) {
"$appTabTray container is not visible");
// pin the tab, make sure the TabItem goes away and the icon comes on
gBrowser.pinTab(xulTabs[0]);
is(groupItem._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
whenAppTabIconAdded(function() {
is(groupItem._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
isnot(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is visible");
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
isnot(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is visible");
let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
let trayHeight = parseInt(trayContainer.css("height"));
let rows = Math.floor(trayHeight / iconHeight);
let icons = rows * 2;
// add enough tabs to have two columns
for (let i = 1; i < icons; i++) {
xulTabs.push(gBrowser.loadOneTab("about:blank"));
gBrowser.pinTab(xulTabs[i]);
}
let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
let trayHeight = parseInt(trayContainer.css("height"));
let rows = Math.floor(trayHeight / iconHeight);
let icons = rows * 2;
is(appTabCount(groupItem), icons, "number of app tab icons is correct");
function pinnedSomeTabs() {
is(appTabCount(groupItem), icons, "number of app tab icons is correct");
is(tray.css("-moz-column-count"), 2,
"$appTabTray column count is 2");
is(tray.css("-moz-column-count"), 2,
"$appTabTray column count is 2");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// add one more tab
xulTabs.push(gBrowser.loadOneTab("about:blank"));
gBrowser.pinTab(xulTabs[xulTabs.length-1]);
// add one more tab
xulTabs.push(gBrowser.loadOneTab("about:blank"));
whenAppTabIconAdded(function() {
is(tray.css("-moz-column-count"), 3,
"$appTabTray column count is 3");
is(tray.css("-moz-column-count"), 3,
"$appTabTray column count is 3");
ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container hasClass .appTabTrayContainerTruncated");
ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container hasClass .appTabTrayContainerTruncated");
// remove all but one app tabs
for (let i = 1; i < xulTabs.length; i++)
gBrowser.removeTab(xulTabs[i]);
// remove all but one app tabs
for (let i = 1; i < xulTabs.length; i++)
gBrowser.removeTab(xulTabs[i]);
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// unpin the last remaining tab
gBrowser.unpinTab(xulTabs[0]);
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItem);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
// unpin the last remaining tab
gBrowser.unpinTab(xulTabs[0]);
// When the tab was pinned, the last active group with an item got the focus.
// Therefore, switching the focus back to group item one.
contentWindow.UI.setActive(groupItem);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
is(appTabCount(groupItem), 0, "there are no app tab icons");
is(appTabCount(groupItem), 0, "there are no app tab icons");
is(groupItem._children.length, 1, "the normal tab shows in the group");
is(groupItem._children.length, 1, "the normal tab shows in the group");
gBrowser.removeTab(xulTabs[0]);
gBrowser.removeTab(xulTabs[0]);
// close the group
groupItem.close();
// close the group
groupItem.close();
hideTabView(function() {
ok(!TabView.isVisible(), "Tab View is hidden");
hideTabView(function() {
ok(!TabView.isVisible(), "Tab View is hidden");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
win.close();
win.close();
executeSoon(finish);
}, win);
}, win);
win.gBrowser.pinTab(xulTabs[xulTabs.length-1]);
};
executeSoon(finish);
// add enough tabs to have two columns
let returnCount = 0;
for (let i = 1; i < icons; i++) {
xulTabs.push(gBrowser.loadOneTab("about:blank"));
whenAppTabIconAdded(function() {
if (++returnCount == (icons - 1))
executeSoon(pinnedSomeTabs);
}, win);
win.gBrowser.pinTab(xulTabs[i]);
}
}, win);
win.gBrowser.pinTab(xulTabs[0]);
}
function appTabCount(groupItem) {

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

@ -10,15 +10,14 @@ function test() {
waitForExplicitFinish();
newTab = gBrowser.addTab();
gBrowser.pinTab(newTab);
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
TabView.toggle();
showTabView(function() {
whenAppTabIconAdded(onTabPinned);
gBrowser.pinTab(newTab);
})
}
function onTabViewWindowLoaded() {
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
function onTabPinned() {
let contentWindow = document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1,
"There is one group item on startup");

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

@ -29,6 +29,7 @@ function onTabViewWindowLoaded(win) {
let datatext = win.gBrowser.loadOneTab("data:text/plain,bug610242", bg);
let datahtml = win.gBrowser.loadOneTab("data:text/html,<blink>don't blink!</blink>", bg);
let mozilla = win.gBrowser.loadOneTab("about:mozilla", bg);
let robots = win.gBrowser.loadOneTab("about:robots", bg);
let html = win.gBrowser.loadOneTab("http://example.com", bg);
let png = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/moz.png", bg);
let svg = win.gBrowser.loadOneTab("http://mochi.test:8888/browser/browser/base/content/test/title_test.svg", bg);
@ -46,13 +47,11 @@ function onTabViewWindowLoaded(win) {
is(win.gBrowser.tabs.length, 1, "There is only one tab left");
is(win.gBrowser.visibleTabs.length, 1, "There is also only one visible tab");
let onTabViewHidden = function() {
win.removeEventListener("tabviewhidden", onTabViewHidden, false);
whenTabViewIsHidden(function() {
win.close();
ok(win.closed, "new window is closed");
finish();
};
win.addEventListener("tabviewhidden", onTabViewHidden, false);
}, win);
win.gBrowser.selectedTab = originalTab;
win.TabView.hide();
@ -69,16 +68,33 @@ function onTabViewWindowLoaded(win) {
afterAllTabsLoaded(function() {
afterAllTabItemsUpdated(function() {
check(datatext, "datatext", false);
check(datahtml, "datahtml", false);
check(mozilla, "about:mozilla", true);
check(html, "html", true);
check(png, "png", false);
check(svg, "svg", true);
let children = group.getChildren();
let len = children.length;
let iconUpdateCounter = 0;
// Get rid of the group and its children
// The group close will trigger a finish().
closeGroupItem(group);
children.forEach(function(tabItem) {
tabItem.addSubscriber("iconUpdated", function onIconUpdated() {
// the tab is not loaded completely so ignore it.
if (tabItem.tab.linkedBrowser.currentURI.spec == "about:blank")
return;
tabItem.removeSubscriber("iconUpdated", onIconUpdated);
if (++iconUpdateCounter == len) {
check(datatext, "datatext", false);
check(datahtml, "datahtml", false);
check(mozilla, "about:mozilla", false);
check(robots, "about:robots", true);
check(html, "html", true);
check(png, "png", false);
check(svg, "svg", true);
// Get rid of the group and its children
// The group close will trigger a finish().
closeGroupItem(group);
}
});
});
}, win);
}, win);
}

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

@ -172,6 +172,7 @@ function test() {
}
waitForExplicitFinish();
requestLongerTimeout(2);
next();
}

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

@ -11,10 +11,6 @@ function test() {
let newTabTwo = gBrowser.addTab();
let newTabThree = gBrowser.addTab();
gBrowser.pinTab(newTabOne);
gBrowser.pinTab(newTabTwo);
gBrowser.pinTab(newTabThree);
registerCleanupFunction(function() {
TabView.hide();
while (gBrowser.tabs.length > 1)
@ -27,37 +23,47 @@ function test() {
groupItem = contentWindow.GroupItems.groupItems[0];
is(xulTabForAppTabIcon(0), newTabOne,
"New tab one matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabTwo,
"New tab two matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabThree,
"New tab three matches the third app tab icon in tabview");
whenAppTabIconAdded(function() {
whenAppTabIconAdded(function() {
whenAppTabIconAdded(function() {
// move the last tab to the first position
gBrowser.moveTabTo(newTabThree, 0);
is(xulTabForAppTabIcon(0), newTabThree,
"New tab three matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabOne,
"New tab one matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabTwo,
"New tab two matches the third app tab icon in tabview");
is(xulTabForAppTabIcon(0), newTabOne,
"New tab one matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabTwo,
"New tab two matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabThree,
"New tab three matches the third app tab icon in tabview");
// move the first tab to the second position
gBrowser.moveTabTo(newTabThree, 1);
is(xulTabForAppTabIcon(0), newTabOne,
"New tab one matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabThree,
"New tab three matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabTwo,
"New tab two matches the third app tab icon in tabview");
// move the last tab to the first position
gBrowser.moveTabTo(newTabThree, 0);
is(xulTabForAppTabIcon(0), newTabThree,
"New tab three matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabOne,
"New tab one matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabTwo,
"New tab two matches the third app tab icon in tabview");
hideTabView(function() {
gBrowser.removeTab(newTabOne);
gBrowser.removeTab(newTabTwo);
gBrowser.removeTab(newTabThree);
finish();
// move the first tab to the second position
gBrowser.moveTabTo(newTabThree, 1);
is(xulTabForAppTabIcon(0), newTabOne,
"New tab one matches the first app tab icon in tabview");
is(xulTabForAppTabIcon(1), newTabThree,
"New tab three matches the second app tab icon in tabview");
is(xulTabForAppTabIcon(2), newTabTwo,
"New tab two matches the third app tab icon in tabview");
hideTabView(function() {
gBrowser.removeTab(newTabOne);
gBrowser.removeTab(newTabTwo);
gBrowser.removeTab(newTabThree);
finish();
});
});
gBrowser.pinTab(newTabThree);
});
gBrowser.pinTab(newTabTwo);
});
gBrowser.pinTab(newTabOne);
});
}

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

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const ICON_URL = "moz-anno:favicon:http://example.com/browser/browser/components/tabview/test/test_bug678374_icon16.png";
const TEST_URL = "http://example.com/browser/browser/components/tabview/test/test_bug678374.html";
function test() {
Services.prefs.setBoolPref("browser.chrome.favicons", false);
waitForExplicitFinish();
newWindowWithTabView(function(win) {
is(win.gBrowser.tabs.length, 3, "There are 3 tabs")
let newTabOne = win.gBrowser.tabs[1];
let newTabTwo = win.gBrowser.tabs[2];
let cw = win.TabView.getContentWindow();
let groupItem = cw.GroupItems.groupItems[0];
// test tab item
let newTabItemOne = newTabOne._tabViewTabItem;
newTabItemOne.addSubscriber("iconUpdated", function onIconUpdated() {
newTabItemOne.removeSubscriber("iconUpdated", onIconUpdated);
is(newTabItemOne.$favImage[0].src, ICON_URL, "The tab item is showing the right icon.");
// test pin tab
whenAppTabIconAdded(function() {
let icon = cw.iQ(".appTabIcon", groupItem.$appTabTray)[0];
is(icon.src, ICON_URL, "The app tab is showing the right icon");
finish();
}, win);
win.gBrowser.pinTab(newTabTwo);
});
}, function(win) {
registerCleanupFunction(function() {
Services.prefs.clearUserPref("browser.chrome.favicons");
win.close();
});
win.gBrowser.loadOneTab(TEST_URL);
win.gBrowser.loadOneTab(TEST_URL);
});
}

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

@ -6,19 +6,21 @@ function test() {
showTabView(function () {
let tab = gBrowser.addTab();
gBrowser.pinTab(tab);
registerCleanupFunction(function () gBrowser.removeTab(tab));
let cw = TabView.getContentWindow();
let body = cw.document.body;
let [appTabIcon] = cw.iQ(".appTabTray .appTabIcon");
whenAppTabIconAdded(function() {
let cw = TabView.getContentWindow();
let body = cw.document.body;
let [appTabIcon] = cw.iQ(".appTabTray .appTabIcon");
EventUtils.synthesizeMouseAtCenter(appTabIcon, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(body, 500, 100, {type: "mousemove"}, cw);
EventUtils.synthesizeMouse(body, 500, 100, {type: "mouseup"}, cw);
EventUtils.synthesizeMouseAtCenter(appTabIcon, {type: "mousedown"}, cw);
EventUtils.synthesizeMouse(body, 500, 100, {type: "mousemove"}, cw);
EventUtils.synthesizeMouse(body, 500, 100, {type: "mouseup"}, cw);
ok(TabView.isVisible(), "tabview is still visible");
ok(TabView.isVisible(), "tabview is still visible");
hideTabView(finish);
hideTabView(finish);
});
gBrowser.pinTab(tab);
});
}

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

@ -385,3 +385,17 @@ function togglePrivateBrowsing(callback) {
pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
}
// ----------
function whenAppTabIconAdded(callback, win) {
win = win || window;
let contentWindow = win.TabView.getContentWindow();
let groupItems = contentWindow.GroupItems.groupItems;
let groupItem = groupItems[(groupItems.length - 1)];
groupItem.addSubscriber("appTabIconAdded", function onAppTabIconAdded() {
groupItem.removeSubscriber("appTabIconAdded", onAppTabIconAdded);
callback();
});
}

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

@ -0,0 +1,7 @@
<html>
<head>
<title>Bug 678374</title>
<link rel="icon" type="image/png" id="favicon" href="test_bug678374_icon16.png" />
<body>
</body>
</html>

Двоичные данные
browser/components/tabview/test/test_bug678374_icon16.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 924 B

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

@ -51,6 +51,12 @@ let Keys = { meta: false };
// Class: UI
// Singleton top-level UI manager.
let UI = {
// Pref that controls whether to display site icons
PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
// Pref that controls whether to display fav icons
PREF_CHROME_FAVICONS: "browser.chrome.favicons",
// Variable: _frameInitialized
// True if the Tab View UI frame has been initialized.
_frameInitialized: false,
@ -141,6 +147,12 @@ let UI = {
// Used to keep track of the tab strip smooth scroll value.
_originalSmoothScroll: null,
// Used to keep track of the browser.chrome.site_icons pref value.
_prefSiteIcons: null,
// Used to keep track of the browser.chrome.favicons pref value.
_prefFavicons: null,
// ----------
// Function: toString
// Prints [UI] for debug use
@ -241,6 +253,10 @@ let UI = {
// ___ add tab action handlers
this._addTabActionHandlers();
// ___ add preference observers
Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
// ___ groups
GroupItems.init();
GroupItems.pauseArrange();
@ -292,6 +308,9 @@ let UI = {
let event = document.createEvent("Events");
event.initEvent("tabviewframeinitialized", true, false);
dispatchEvent(event);
// XXX this can be removed when bug 731868 is fixed
event = null;
} catch(e) {
Utils.log(e);
} finally {
@ -314,6 +333,9 @@ let UI = {
Storage.uninit();
StoragePolicy.uninit();
Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
this._removeTabActionHandlers();
this._currentTab = null;
this._pageBounds = null;
@ -851,6 +873,19 @@ let UI = {
AllTabs.unregister(name, this._eventListeners[name]);
},
// ----------
// Function: observe
// Observes different preference value changes.
observe: function UI_observe(subject, topic, data) {
if (data == this.PREF_CHROME_SITE_ICONS) {
this._prefSiteIcons =
Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
} else if (data == this.PREF_CHROME_FAVICONS) {
this._prefFavicons =
Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
}
},
// ----------
// Function: goToTab
// Selects the given xul:tab in the browser.
@ -1604,7 +1639,6 @@ let UI = {
// ----------
// Function: _saveAll
// Saves all data associated with TabView.
// TODO: Save info items
_saveAll: function UI__saveAll() {
this._save();
GroupItems.saveAll();
@ -1612,31 +1646,68 @@ let UI = {
},
// ----------
// Function: shouldLoadFavIcon
// Takes a xul:browser and checks whether we should display a favicon for it.
shouldLoadFavIcon: function UI_shouldLoadFavIcon(browser) {
return !(browser.contentDocument instanceof window.ImageDocument) &&
(browser.currentURI.schemeIs("about") ||
gBrowser.shouldLoadFavIcon(browser.contentDocument.documentURIObject));
// Function: _isImageDocument
// Checks whether an image is loaded into the given tab.
_isImageDocument: function UI__isImageDocument(tab, callback) {
let mm = tab.linkedBrowser.messageManager;
let message = "Panorama:isImageDocument";
mm.addMessageListener(message, function onMessage(cx) {
mm.removeMessageListener(cx.name, onMessage);
callback(cx.json.isImageDocument);
});
mm.sendAsyncMessage(message);
},
// ----------
// Function: _shouldLoadFavIcon
// Checks whether fav icon should be loaded for a given tab.
_shouldLoadFavIcon: function UI__shouldLoadFavIcon(tab) {
let uri = tab.linkedBrowser.currentURI;
if (!uri)
return false;
if (this._prefSiteIcons == null)
this._prefSiteIcons =
Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
if (!this._prefSiteIcons)
return false;
if (this._prefFavicons == null)
this._prefFavicons =
Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
return (this._prefFavicons && ("schemeIs" in uri) &&
(uri.schemeIs("http") || uri.schemeIs("https")));
},
// ----------
// Function: getFavIconUrlForTab
// Gets fav icon url for the given xul:tab.
getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab) {
let url;
getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab, callback) {
this._isImageDocument(tab, function(isImageDoc) {
if (isImageDoc) {
callback(tab.pinned ? tab.image : null);
} else {
let tabImage = tab.image;
if (tabImage) {
// if starts with http/https, fetch icon from favicon service via the moz-anno protocal
if (/^https?:/.test(tabImage))
tabImage = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec;
if (tab.image) {
// if starts with http/https, fetch icon from favicon service via the moz-anno protocal
if (/^https?:/.test(tab.image))
url = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec;
else
url = tab.image;
} else {
url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec;
}
return url;
callback(tabImage);
} else {
// determine to load the default/cached icon or not and also ensure we don't show the default icon
// for about:-style error pages
let url = null;
if (this._shouldLoadFavIcon(tab))
url = gFavIconService.getFaviconImageForPage(tab.linkedBrowser.currentURI).spec;
callback(url);
}
}
}.bind(this));
},
// ----------

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

@ -109,6 +109,7 @@ let PageThumbs = {
* @param aCallback The function to be called when finished (optional).
*/
captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
let url = aBrowser.currentURI.spec;
this.capture(aBrowser.contentWindow, function (aInputStream) {
let telemetryStoreTime = new Date();
@ -123,7 +124,7 @@ let PageThumbs = {
}
// Get a writeable cache entry.
PageThumbsCache.getWriteEntry(aBrowser.currentURI.spec, function (aEntry) {
PageThumbsCache.getWriteEntry(url, function (aEntry) {
if (!aEntry) {
finish(false);
return;

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

@ -13,6 +13,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_thumbnails_capture.js \
browser_thumbnails_bug726727.js \
head.js \
$(NULL)

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

@ -0,0 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* These tests ensure that capturing a sites's thumbnail, saving it and
* retrieving it from the cache works.
*/
function runTests() {
// Create a tab that shows an error page.
let tab = gBrowser.addTab("http://non-existant.url/");
let browser = tab.linkedBrowser;
yield browser.addEventListener("DOMContentLoaded", function onLoad() {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
executeSoon(next);
}, false);
ok(!gBrowserThumbnails._shouldCapture(browser), "we're not going to capture an error page");
}

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

@ -49,7 +49,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource:///modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/source-editor.jsm");
let EXPORTED_SYMBOLS = ["DebuggerUI"];

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

@ -197,7 +197,68 @@ function testFailGroup(data) {
laterGroup = undefined;
laterRejection = undefined;
finished();
testTrap();
}
function testTrap() {
var p = new Promise();
var message = "Expected exception";
p.chainPromise(
function() {
throw new Error(message);
}).trap(
function(aError) {
is(aError instanceof Error, true, "trap received exception");
is(aError.message, message, "trap received correct exception");
return 1;
}).chainPromise(
function(aResult) {
is(aResult, 1, "trap restored correct result");
testAlways();
});
p.resolve();
}
function testAlways() {
var shouldbeTrue1 = false;
var shouldbeTrue2 = false;
var p = new Promise();
p.chainPromise(
function() {
throw new Error();
}
).chainPromise(// Promise rejected, should not be executed
function() {
ok(false, "This should not be executed");
}
).always(
function(x) {
shouldbeTrue1 = true;
return "random value";
}
).trap(
function(arg) {
ok((arg instanceof Error), "The random value should be ignored");
return 1;// We should still have this result later
}
).trap(
function() {
ok(false, "This should not be executed 2");
}
).always(
function() {
shouldbeTrue2 = true;
}
).then(
function(aResult){
ok(shouldbeTrue1, "First always must be executed");
ok(shouldbeTrue2, "Second always must be executed");
is(aResult, 1, "Result should be unaffected by always");
testComplete();
}
);
p.resolve();
}
function fail() {
@ -207,6 +268,36 @@ function fail() {
finish();
}
/**
* We wish to launch all tests with several configurations (at the moment,
* non-debug and debug mode).
*
* If 0, we have not completed any test yet.
* If 1, we have completed the tests in non-debug mode.
* If 2, we have also completed the tests in debug mode.
*/
var configurationTestComplete = 0;
function testComplete() {
switch (configurationTestComplete) {
case 0:
info("Finished run in non-debug mode");
configurationTestComplete = 1;
Promise.Debug.setDebug(true);
window.setTimeout(testBasic, 0);
return;
case 1:
info("Finished run in debug mode");
configurationTestComplete = 2;
Promise.Debug.setDebug(false);
window.setTimeout(finished, 0);
return;
default:
ok(false, "Internal error in testComplete "+configurationTestComplete);
return;
}
}
function finished() {
gBrowser.removeCurrentTab();
info("Finishing Promise Tests");

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

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in
MOZ_PKG_FATAL_WARNINGS = 1
MOZ_NONLOCALIZED_PKG_LIST = \
xpcom \

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

@ -25,19 +25,21 @@
[@AB_CD@]
@BINPATH@/chrome/@AB_CD@@JAREXT@
@BINPATH@/chrome/@AB_CD@.manifest
@BINPATH@/@PREF_DIR@/firefox-l10n.js
@BINPATH@/searchplugins/*
@BINPATH@/defaults/profile/bookmarks.html
@BINPATH@/defaults/profile/chrome/*
@BINPATH@/defaults/profile/localstore.rdf
@BINPATH@/defaults/profile/mimeTypes.rdf
@BINPATH@/defaults/profile/chrome/*
@BINPATH@/update.locale
@BINPATH@/updater.ini
@BINPATH@/dictionaries/*
@BINPATH@/hyphenation/*
@BINPATH@/@PREF_DIR@/firefox-l10n.js
@BINPATH@/searchplugins/*
#ifdef XP_WIN32
@BINPATH@/uninstall/helper.exe
#endif
#ifdef MOZ_UPDATER
@BINPATH@/update.locale
@BINPATH@/updater.ini
#endif
[xpcom]
@BINPATH@/dependentlibs.list
@ -386,10 +388,10 @@
@BINPATH@/components/RadioInterfaceLayer.js
@BINPATH@/components/SmsDatabaseService.manifest
@BINPATH@/components/SmsDatabaseService.js
@BINPATH@/components/nsWifiWorker.js
@BINPATH@/components/nsWifiWorker.manifest
@BINPATH@/components/nsDOMWifiManager.js
@BINPATH@/components/nsDOMWifiManager.manifest
@BINPATH@/components/WifiWorker.js
@BINPATH@/components/WifiWorker.manifest
@BINPATH@/components/DOMWifiManager.js
@BINPATH@/components/DOMWifiManager.manifest
#endif
@BINPATH@/components/BrowserProfileMigrators.manifest
@BINPATH@/components/ProfileMigrator.js
@ -556,11 +558,13 @@ bin/libfreebl_32int64_3.so
; [Updater]
;
#ifdef MOZ_UPDATER
#ifdef XP_MACOSX
@BINPATH@/updater.app/
#else
@BINPATH@/updater@BIN_SUFFIX@
#endif
#endif
; [MaintenanceService]
;

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

@ -15,7 +15,6 @@
@DLL_PREFIX@mozjs@DLL_SUFFIX@
#endif
LICENSE
update.locale
browserconfig.properties
chrome/US.jar
chrome/app-chrome.manifest
@ -695,6 +694,15 @@ uninstall/UninstallDeerPark.exe
uninstall/UninstallFirefox.exe
uninstall/uninst.exe
uninstall/uninstall.exe
update.locale
#ifndef MOZ_UPDATER
#ifdef XP_MACOSX
updater.app/
#else
updater@BIN_SUFFIX@
#endif
updater.ini
#endif
xpicleanup@BIN_SUFFIX@
#ifdef MOZ_OMNIJAR
omni.jar
@ -927,10 +935,10 @@ xpicleanup@BIN_SUFFIX@
components/nsTelephonyWorker.js
components/Telephony.manifest
components/Telephony.js
components/nsWifiWorker.js
components/nsWifiWorker.manifest
components/nsDOMWifiManager.js
components/nsDOMWifiManager.manifest
components/WifiWorker.js
components/WifiWorker.manifest
components/DOMWifiManager.js
components/DOMWifiManager.manifest
#endif
components/txEXSLTRegExFunctions.js
components/Weave.js

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

@ -17,7 +17,7 @@ browser.contentHandlers.types.1.uri=http://add.my.yahoo.com/rss?url=%s
# TRANSLATION NOTE: {moz:domain} and {searchTerms} are placeholders for the site
# to be searched and the user's search query. Place them in the appropriate location
# for your locale's URL but do not translate them.
browser.search.siteSearchURL=http://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&q=site%3A{moz:domain}+{searchTerms}
browser.search.siteSearchURL=https://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&q=site%3A{moz:domain}+{searchTerms}
# increment this number when anything gets changed in the list below. This will
# cause Firefox to re-read these prefs and inject any new handlers into the

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

@ -1,6 +1,7 @@
<!ENTITY % brandDTD
SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
%syncBrandDTD;
<!-- These strings are used in the about:home page -->
@ -8,8 +9,6 @@
<!ENTITY abouthome.searchEngineButton.label "Search">
<!ENTITY abouthome.aboutMozilla "About Mozilla">
<!-- LOCALIZATION NOTE (abouthome.defaultSnippet1.v1):
text in <a/> will be linked to the Firefox features page on mozilla.com
-->
@ -19,5 +18,9 @@
-->
<!ENTITY abouthome.defaultSnippet2.v1 "It's easy to customize your Firefox exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
<!ENTITY abouthome.syncSetup.label "Set Up Sync">
<!ENTITY abouthome.pairDevice.label "Pair a Device">
<!ENTITY abouthome.bookmarksButton.label "Bookmarks">
<!ENTITY abouthome.historyButton.label "History">
<!ENTITY abouthome.settingsButton.label "Settings">
<!ENTITY abouthome.addonsButton.label "Add-ons">
<!ENTITY abouthome.appsButton.label "Marketplace">
<!ENTITY abouthome.downloadsButton.label "Downloads">

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

@ -13,22 +13,22 @@
<Description>Google Search</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,AAABAAEAEBAAAAEAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs9Pt8xetPtu9FsfFNtu%2BTzvb2%2B%2Fne4dFJeBw0egA%2FfAJAfAA8ewBBegAAAAD%2B%2FPtft98Mp%2BwWsfAVsvEbs%2FQeqvF8xO7%2F%2F%2F63yqkxdgM7gwE%2FggM%2BfQA%2BegBDeQDe7PIbotgQufcMufEPtfIPsvAbs%2FQvq%2Bfz%2Bf%2F%2B%2B%2FZKhR05hgBBhQI8hgBAgAI9ewD0%2B%2Fg3pswAtO8Cxf4Kw%2FsJvvYAqupKsNv%2B%2Fv7%2F%2FP5VkSU0iQA7jQA9hgBDgQU%2BfQH%2F%2Ff%2FQ6fM4sM4KsN8AteMCruIqqdbZ7PH8%2Fv%2Fg6Nc%2Fhg05kAA8jAM9iQI%2BhQA%2BgQDQu6b97uv%2F%2F%2F7V8Pqw3eiWz97q8%2Ff%2F%2F%2F%2F7%2FPptpkkqjQE4kwA7kAA5iwI8iAA8hQCOSSKdXjiyflbAkG7u2s%2F%2B%2F%2F39%2F%2F7r8utrqEYtjQE8lgA7kwA7kwA9jwA9igA9hACiWSekVRyeSgiYSBHx6N%2F%2B%2Fv7k7OFRmiYtlAA5lwI7lwI4lAA7kgI9jwE9iwI4iQCoVhWcTxCmb0K%2BooT8%2Fv%2F7%2F%2F%2FJ2r8fdwI1mwA3mQA3mgA8lAE8lAE4jwA9iwE%2BhwGfXifWvqz%2B%2Ff%2F58u%2Fev6Dt4tr%2B%2F%2F2ZuIUsggA7mgM6mAM3lgA5lgA6kQE%2FkwBChwHt4dv%2F%2F%2F728ei1bCi7VAC5XQ7kz7n%2F%2F%2F6bsZkgcB03lQA9lgM7kwA2iQktZToPK4r9%2F%2F%2F9%2F%2F%2FSqYK5UwDKZAS9WALIkFn%2B%2F%2F3%2F%2BP8oKccGGcIRJrERILYFEMwAAuEAAdX%2F%2Ff7%2F%2FP%2B%2BfDvGXQLIZgLEWgLOjlf7%2F%2F%2F%2F%2F%2F9QU90EAPQAAf8DAP0AAfMAAOUDAtr%2F%2F%2F%2F7%2B%2Fu2bCTIYwDPZgDBWQDSr4P%2F%2Fv%2F%2F%2FP5GRuABAPkAA%2FwBAfkDAPAAAesAAN%2F%2F%2B%2Fz%2F%2F%2F64g1C5VwDMYwK8Yg7y5tz8%2Fv%2FV1PYKDOcAAP0DAf4AAf0AAfYEAOwAAuAAAAD%2F%2FPvi28ymXyChTATRrIb8%2F%2F3v8fk6P8MAAdUCAvoAAP0CAP0AAfYAAO4AAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA</Image>
<Url type="application/x-suggestions+json" method="GET" template="http://suggestqueries.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
<Url type="text/html" method="GET" template="http://www.google.com/search">
<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?output=firefox&amp;client=firefox&amp;hl={moz:locale}&amp;q={searchTerms}"/>
<Url type="text/html" method="GET" template="https://www.google.com/search">
#expand __GOOGLE_PARAMS__
#expand __GOOGLE_CLIENT_PARAM__
</Url>
<!-- Keyword search URL is the same as the default, but with an additional parameter -->
<Url type="application/x-moz-keywordsearch" method="GET" template="http://www.google.com/search">
<Url type="application/x-moz-keywordsearch" method="GET" template="https://www.google.com/search">
#expand __GOOGLE_PARAMS__
#expand __GOOGLE_CLIENT_PARAM__
<Param name="channel" value="fflb"/>
</Url>
<!-- Context/Right-click search URL is the same as the default, but with an additional parameter -->
<Url type="application/x-moz-contextsearch" method="GET" template="http://www.google.com/search">
<Url type="application/x-moz-contextsearch" method="GET" template="https://www.google.com/search">
#expand __GOOGLE_PARAMS__
#expand __GOOGLE_CLIENT_PARAM__
<Param name="channel" value="rcs"/>
</Url>
<SearchForm>http://www.google.com/</SearchForm>
<SearchForm>https://www.google.com/</SearchForm>
</SearchPlugin>

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

@ -383,6 +383,15 @@ let BlockedLinks = {
Storage.set("blockedLinks", this.links);
},
/**
* Unblocks a given link.
* @param aLink The link to unblock.
*/
unblock: function BlockedLinks_unblock(aLink) {
if (this.isBlocked(aLink))
delete this.links[aLink.url];
},
/**
* Returns whether a given link is blocked.
* @param aLink The link to check.
@ -550,7 +559,7 @@ let Links = {
* Resets the links cache.
*/
resetCache: function Links_resetCache() {
this._links = [];
this._links = null;
},
/**
@ -584,13 +593,17 @@ let Links = {
*/
let NewTabUtils = {
/**
* Resets the NewTabUtils module, its links and its storage.
* Restores all sites that have been removed from the grid.
*/
reset: function NewTabUtils_reset() {
restore: function NewTabUtils_restore() {
Storage.clear();
Links.resetCache();
PinnedLinks.resetCache();
BlockedLinks.resetCache();
Links.populateCache(function () {
AllPages.update();
}, true);
},
allPages: AllPages,

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