Merge the trunk into HTML5 parsing repo

This commit is contained in:
Henri Sivonen 2009-05-04 11:19:16 -07:00
Родитель 20df79d12f 8d9ac8159c
Коммит 1f9455f387
4192 изменённых файлов: 122014 добавлений и 175369 удалений

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

@ -7,10 +7,8 @@
(^|/)\.DS_Store$
# User files that may appear at the root
^\.mozconfig$
^mozconfig$
^\.mozconfig\.mk$
^\.mozconfig\.out$
^\.mozconfig
^mozconfig
^configure$
^config\.cache$
^config\.log$

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

@ -40,6 +40,15 @@ topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
ifndef .PYMAKE
ifeq (,$(MAKE_VERSION))
$(error GNU Make is required)
endif
ifeq (,$(filter-out 3.78 3.79,$(MAKE_VERSION)))
$(error GNU Make 3.80 or higher is required)
endif
endif
include $(DEPTH)/config/autoconf.mk
default::
@ -183,12 +192,12 @@ ifdef MOZ_CRASHREPORTER
echo packing symbols
mkdir -p $(topsrcdir)/../$(BUILDID)
cd $(DIST)/crashreporter-symbols && \
zip -r9D ../$(SYMBOL_ARCHIVE_BASENAME).zip .
zip -r9D ../"$(SYMBOL_ARCHIVE_BASENAME).zip" .
endif # MOZ_CRASHREPORTER
uploadsymbols:
ifdef MOZ_CRASHREPORTER
$(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip
$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh "$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip"
endif
ifeq ($(OS_ARCH),WINNT)

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

@ -46,7 +46,7 @@ interface nsObjectFrame;
interface nsIContent;
interface nsITimer;
[uuid(44685af8-18be-494a-8e64-16c7d4296dd1)]
[uuid(05481634-4700-45d6-8a0c-704f3a5abc00)]
interface nsIAccessibilityService : nsIAccessibleRetrieval
{
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
@ -66,6 +66,7 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
nsIAccessible createHTMLImageAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLLabelAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLListboxAccessible(in nsIDOMNode aNode, in nsIWeakReference aPresShell);
nsIAccessible createHTMLMediaAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLObjectFrameAccessible(in nsObjectFrame aFrame);
nsIAccessible createHTMLRadioButtonAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLSelectOptionAccessible(in nsIDOMNode aNode, in nsIAccessible aAccParent, in nsIWeakReference aPresShell);

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

@ -123,7 +123,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
"columnheader",
nsIAccessibleRole::ROLE_COLUMNHEADER,
eNoValue,
eNoAction,
eSortAction,
eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
@ -417,7 +417,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
"rowheader",
nsIAccessibleRole::ROLE_ROWHEADER,
eNoValue,
eNoAction,
eSortAction,
eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},

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

@ -57,9 +57,11 @@ enum EActionRule
eActivateAction,
eClickAction,
eCheckUncheckAction,
eExpandAction,
eJumpAction,
eOpenCloseAction,
eSelectAction,
eSortAction,
eSwitchAction
};

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

@ -321,6 +321,8 @@ nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
PRBool
nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
{
NS_ASSERTION(aContent, "aContent is null in call to HasDefinedARIAToken!");
if (!aContent->HasAttr(kNameSpaceID_None, aAtom) ||
aContent->AttrValueIs(kNameSpaceID_None, aAtom,
nsAccessibilityAtoms::_empty, eCaseMatters) ||
@ -825,7 +827,6 @@ nsAccUtils::GetMultiSelectFor(nsIDOMNode *aNode)
if (0 == (state & nsIAccessibleStates::STATE_SELECTABLE))
return nsnull;
PRUint32 containerRole;
while (0 == (state & nsIAccessibleStates::STATE_MULTISELECTABLE)) {
nsIAccessible *current = accessible;
current->GetParent(getter_AddRefs(accessible));

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

@ -171,6 +171,7 @@ ACCESSIBILITY_ATOM(increment, "increment") // XUL
ACCESSIBILITY_ATOM(lang, "lang")
ACCESSIBILITY_ATOM(linkedPanel, "linkedpanel") // XUL
ACCESSIBILITY_ATOM(longDesc, "longdesc")
ACCESSIBILITY_ATOM(max, "max") // XUL
ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL
ACCESSIBILITY_ATOM(minpos, "minpos") // XUL
ACCESSIBILITY_ATOM(multiline, "multiline") // XUL
@ -217,7 +218,6 @@ ACCESSIBILITY_ATOM(aria_busy, "aria-busy")
ACCESSIBILITY_ATOM(aria_checked, "aria-checked")
ACCESSIBILITY_ATOM(aria_controls, "aria-controls")
ACCESSIBILITY_ATOM(aria_describedby, "aria-describedby")
ACCESSIBILITY_ATOM(aria_droppable, "aria-droppable")
ACCESSIBILITY_ATOM(aria_disabled, "aria-disabled")
ACCESSIBILITY_ATOM(aria_dropeffect, "aria-dropeffect")
ACCESSIBILITY_ATOM(aria_expanded, "aria-expanded")

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

@ -684,6 +684,27 @@ nsAccessibilityService::CreateHTMLListboxAccessible(nsIDOMNode* aDOMNode, nsIWea
return NS_OK;
}
NS_IMETHODIMP
nsAccessibilityService::CreateHTMLMediaAccessible(nsIFrame *aFrame,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIWeakReference> weakShell;
nsresult rv = GetInfo(aFrame, getter_AddRefs(weakShell),
getter_AddRefs(node));
NS_ENSURE_SUCCESS(rv, rv);
*aAccessible = new nsEnumRoleAccessible(node, weakShell,
nsIAccessibleRole::ROLE_GROUPING);
NS_ENSURE_TRUE(*aAccessible, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aAccessible);
return NS_OK;
}
/**
* We can have several cases here.
* 1) a text or html embedded document where the contentDocument

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

@ -319,21 +319,27 @@ nsAccessible::GetName(nsAString& aName)
NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription)
{
if (IsDefunct())
return NS_ERROR_FAILURE;
// There are 4 conditions that make an accessible have no accDescription:
// 1. it's a text node; or
// 2. It has no DHTML describedby property
// 3. it doesn't have an accName; or
// 4. its title attribute already equals to its accName nsAutoString name;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
NS_ASSERTION(content, "No content of valid accessible!");
if (!content)
return NS_ERROR_FAILURE;
if (!content->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString description;
nsresult rv = nsTextEquivUtils::
GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
description);
if (NS_FAILED(rv)) {
NS_ENSURE_SUCCESS(rv, rv);
if (description.IsEmpty()) {
PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
if (isXUL) {
// Try XUL <description control="[id]">description text</description>
@ -2335,6 +2341,17 @@ nsAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
case eSwitchAction:
aName.AssignLiteral("switch");
return NS_OK;
case eSortAction:
aName.AssignLiteral("sort");
return NS_OK;
case eExpandAction:
if (states & nsIAccessibleStates::STATE_COLLAPSED)
aName.AssignLiteral("expand");
else
aName.AssignLiteral("collapse");
return NS_OK;
}
return NS_ERROR_INVALID_ARG;
@ -3229,8 +3246,11 @@ nsAccessible::GetActionRule(PRUint32 aStates)
if (aStates & nsIAccessibleStates::STATE_UNAVAILABLE)
return eNoAction;
nsIContent* content = nsCoreUtils::GetRoleContent(mDOMNode);
if (!content)
return eNoAction;
// Check if it's simple xlink.
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (nsCoreUtils::IsXLink(content))
return eJumpAction;
@ -3240,11 +3260,17 @@ nsAccessible::GetActionRule(PRUint32 aStates)
if (isOnclick)
return eClickAction;
// Get an action based on ARIA role.
if (mRoleMapEntry)
if (mRoleMapEntry &&
mRoleMapEntry->actionRule != eNoAction)
return mRoleMapEntry->actionRule;
// Get an action based on ARIA attribute.
if (nsAccUtils::HasDefinedARIAToken(content,
nsAccessibilityAtoms::aria_expanded))
return eExpandAction;
return eNoAction;
}

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

@ -37,8 +37,11 @@
* ***** END LICENSE BLOCK ***** */
#include "nsAccessibleTreeWalker.h"
#include "nsAccessibilityAtoms.h"
#include "nsAccessNode.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIServiceManager.h"
#include "nsIContent.h"
#include "nsIDOMXULElement.h"
@ -76,7 +79,6 @@ void nsAccessibleTreeWalker::GetKids(nsIDOMNode *aParentNode)
mState.frame = nsnull; // Don't walk frames in non-HTML content, just walk the DOM.
}
PushState();
UpdateFrame(PR_TRUE);
// Walk frames? UpdateFrame() sets this when it sees anonymous frames
@ -210,6 +212,8 @@ NS_IMETHODIMP nsAccessibleTreeWalker::GetFirstChild()
}
nsCOMPtr<nsIDOMNode> parent(mState.domNode);
PushState();
GetKids(parent); // Side effects change our state (mState)
// Recursive loop: depth first search for first accessible child
@ -229,9 +233,17 @@ void nsAccessibleTreeWalker::UpdateFrame(PRBool aTryFirstChild)
if (!mState.frame) {
return;
}
if (aTryFirstChild) {
nsIContent *containerContent = mState.frame->GetContent();
// If the frame implements nsIAnonymousContentCreator interface then go down
// through the frames and obtain anonymous nodes for them.
nsIAnonymousContentCreator* creator = do_QueryFrame(mState.frame);
mState.frame = mState.frame->GetFirstChild(nsnull);
if (creator && mState.frame && mState.siblingIndex < 0) {
mState.domNode = do_QueryInterface(mState.frame->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
// temporary workaround for Bug 359210. We never want to walk frames.
// Aaron Leventhal will refix :before and :after content later without walking frames.
#if 0
@ -254,17 +266,6 @@ void nsAccessibleTreeWalker::UpdateFrame(PRBool aTryFirstChild)
mState.siblingIndex = eSiblingsWalkFrames;
}
#endif
// Special case: <input type="file">
// We should still need to walk frames inside the file control frame
// This special case may turn into a more general rule after Firefox 3,
// if HTML 5 controls use nsIAnonymousContentCreator
if (containerContent->Tag() == nsAccessibilityAtoms::input &&
containerContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
NS_LITERAL_STRING("file"), eIgnoreCase) &&
mState.frame && mState.siblingIndex < 0) {
mState.domNode = do_QueryInterface(mState.frame->GetContent());
mState.siblingIndex = eSiblingsWalkFrames;
}
}
else {
mState.frame = mState.frame->GetNextSibling();

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

@ -45,6 +45,7 @@
#include "nsCOMPtr.h"
#include "nsIDocument.h"
#include "nsIAccessible.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIAccessibilityService.h"
#include "nsIWeakReference.h"
@ -73,20 +74,61 @@ public:
PRBool mWalkAnonymousContent);
virtual ~nsAccessibleTreeWalker();
/**
* Moves current state to point to the next child accessible.
*/
NS_IMETHOD GetNextSibling();
/**
* Moves current state to point to the first child accessible.
*/
NS_IMETHOD GetFirstChild();
/**
* Current state. Used to initialize a11y tree walker and to get an accessible
* current state points to.
*/
WalkState mState;
protected:
/**
* Return true if currently navigated node/frame is accessible.
*/
PRBool GetAccessible();
/**
* Prepares current state to navigate through children of node/frame.
*/
void GetKids(nsIDOMNode *aParent);
/**
* Clears the current state.
*/
void ClearState();
/**
* Push current state on top of stack. State stack is used to navigate down to
* DOM/frame subtree during searching of accessible children.
*/
NS_IMETHOD PushState();
/**
* Pop state from stack and make it current.
*/
NS_IMETHOD PopState();
/**
* Change current state so that its frame is changed to next frame.
*
* @param aTryFirstChild [in] points whether we should move to child or
* sibling frame
*/
void UpdateFrame(PRBool aTryFirstChild);
/**
* Change current state so that its node is changed to next node.
*/
void GetNextDOMNode();
nsCOMPtr<nsIWeakReference> mWeakShell;

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

@ -51,7 +51,8 @@
#include "nsISelection2.h"
#include "nsServiceManagerUtils.h"
#include "nsIViewManager.h"
#include "nsIWidget.h"
class nsIWidget;
NS_IMPL_ISUPPORTS1(nsCaretAccessible, nsISelectionListener)

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

@ -1131,8 +1131,7 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
if (aAttribute == nsAccessibilityAtoms::role ||
aAttribute == nsAccessibilityAtoms::href ||
aAttribute == nsAccessibilityAtoms::onclick ||
aAttribute == nsAccessibilityAtoms::aria_droppable) {
aAttribute == nsAccessibilityAtoms::onclick) {
// Not worth the expense to ensure which namespace these are in
// It doesn't kill use to recreate the accessible even if the attribute was used
// in the wrong namespace or an element that doesn't support it

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

@ -521,17 +521,23 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
mCurrentARIAMenubar = nsnull;
}
nsCOMPtr<nsIContent> focusContent = do_QueryInterface(finalFocusNode);
nsIFrame *focusFrame = nsnull;
if (focusContent) {
nsCOMPtr<nsIPresShell> shell =
nsCoreUtils::GetPresShellFor(finalFocusNode);
NS_ASSERTION(shell, "No pres shell for final focus node!");
if (!shell)
return PR_FALSE;
focusFrame = shell->GetRealPrimaryFrameFor(focusContent);
}
NS_IF_RELEASE(gLastFocusedNode);
gLastFocusedNode = finalFocusNode;
NS_IF_ADDREF(gLastFocusedNode);
nsCOMPtr<nsIContent> focusContent = do_QueryInterface(gLastFocusedNode);
nsIFrame *focusFrame = nsnull;
if (focusContent) {
nsCOMPtr<nsIPresShell> shell =
nsCoreUtils::GetPresShellFor(gLastFocusedNode);
focusFrame = shell->GetRealPrimaryFrameFor(focusContent);
}
gLastFocusedFrameType = (focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ? focusFrame->GetType() : 0;
nsCOMPtr<nsIAccessibleDocument> docAccessible = do_QueryInterface(finalFocusAccessible);
@ -542,8 +548,7 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
// Suppress document focus, because real DOM focus will be fired next,
// and that's what we care about
// Make sure we never fire focus for the nsRootAccessible (mDOMNode)
return PR_FALSE;
return PR_FALSE;
}
}

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

@ -49,7 +49,6 @@
#include "nsIURI.h"
#include "nsIViewManager.h"
#include "nsIWebNavigation.h"
#include "nsIWidget.h"
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html

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

@ -45,7 +45,6 @@
#include "nsPresContext.h"
#include "nsIPresShell.h"
#include "nsIRenderingContext.h"
#include "nsIWidget.h"
#include "nsIComponentManager.h"
// --------------------------------------------------------
@ -212,9 +211,6 @@ nsresult nsTextAccessibleWrap::GetCharacterExtents(PRInt32 aStartOffset, PRInt32
nsIFrame *frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
nsIWidget *widget = frame->GetWindow();
NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
nsPoint startPoint, endPoint;
nsIFrame *startFrame = GetPointFromOffset(frame, aStartOffset, PR_TRUE, startPoint);
nsIFrame *endFrame = GetPointFromOffset(frame, aEndOffset, PR_FALSE, endPoint);

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

@ -468,16 +468,22 @@ nsXULGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
return NS_OK;
}
/**
* progressmeter
*/
NS_IMPL_ISUPPORTS_INHERITED1(nsXULProgressMeterAccessible, nsFormControlAccessible, nsIAccessibleValue)
////////////////////////////////////////////////////////////////////////////////
// nsXULProgressMeterAccessible
////////////////////////////////////////////////////////////////////////////////
nsXULProgressMeterAccessible::nsXULProgressMeterAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsFormControlAccessible(aNode, aShell)
{
NS_IMPL_ISUPPORTS_INHERITED1(nsXULProgressMeterAccessible,
nsFormControlAccessible,
nsIAccessibleValue)
nsXULProgressMeterAccessible::
nsXULProgressMeterAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
nsFormControlAccessible(aNode, aShell)
{
}
// nsAccessible
nsresult
nsXULProgressMeterAccessible::GetRoleInternal(PRUint32 *aRole)
{
@ -485,59 +491,108 @@ nsXULProgressMeterAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::GetValue(nsAString& aValue)
// nsIAccessibleValue
NS_IMETHODIMP
nsXULProgressMeterAccessible::GetValue(nsAString& aValue)
{
aValue.Truncate();
nsAccessible::GetValue(aValue);
if (!aValue.IsEmpty()) {
nsresult rv = nsFormControlAccessible::GetValue(aValue);
NS_ENSURE_SUCCESS(rv, rv);
if (!aValue.IsEmpty())
return NS_OK;
double maxValue = 0;
rv = GetMaximumValue(&maxValue);
NS_ENSURE_SUCCESS(rv, rv);
if (maxValue != 1) {
double curValue = 0;
rv = GetCurrentValue(&curValue);
NS_ENSURE_SUCCESS(rv, rv);
double percentValue = (curValue / maxValue) * 100;
nsAutoString value;
value.AppendFloat(percentValue); // AppendFloat isn't available on nsAString
value.AppendLiteral("%");
aValue = value;
return NS_OK;
}
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE;
}
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, aValue);
if (aValue.IsEmpty()) {
if (aValue.IsEmpty())
aValue.AppendLiteral("0"); // Empty value for progress meter = 0%
}
aValue.AppendLiteral("%");
return NS_OK;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::GetMaximumValue(double *aMaximumValue)
NS_IMETHODIMP
nsXULProgressMeterAccessible::GetMaximumValue(double *aMaximumValue)
{
nsresult rv = nsFormControlAccessible::GetMaximumValue(aMaximumValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
nsAutoString value;
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::max, value)) {
PRInt32 result = NS_OK;
*aMaximumValue = value.ToFloat(&result);
return result;
}
*aMaximumValue = 1; // 100% = 1;
return NS_OK;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::GetMinimumValue(double *aMinimumValue)
NS_IMETHODIMP
nsXULProgressMeterAccessible::GetMinimumValue(double *aMinimumValue)
{
nsresult rv = nsFormControlAccessible::GetMinimumValue(aMinimumValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aMinimumValue = 0;
return NS_OK;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::GetMinimumIncrement(double *aMinimumIncrement)
NS_IMETHODIMP
nsXULProgressMeterAccessible::GetMinimumIncrement(double *aMinimumIncrement)
{
nsresult rv = nsFormControlAccessible::GetMinimumIncrement(aMinimumIncrement);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
*aMinimumIncrement = 0;
return NS_OK;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::GetCurrentValue(double *aCurrentValue)
NS_IMETHODIMP
nsXULProgressMeterAccessible::GetCurrentValue(double *aCurrentValue)
{
*aCurrentValue = 0;
nsAutoString currentValue;
nsresult rv = nsFormControlAccessible::GetCurrentValue(aCurrentValue);
if (rv != NS_OK_NO_ARIA_VALUE)
return rv;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE;
}
nsAutoString currentValue;
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, currentValue);
PRInt32 error;
*aCurrentValue = currentValue.ToFloat(&error) / 100;
return NS_OK;
PRInt32 result = NS_OK;
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::max))
*aCurrentValue = currentValue.ToFloat(&result);
else
*aCurrentValue = currentValue.ToFloat(&result) / 100;
return result;
}
NS_IMETHODIMP nsXULProgressMeterAccessible::SetCurrentValue(double aValue)
NS_IMETHODIMP
nsXULProgressMeterAccessible::SetCurrentValue(double aValue)
{
return NS_ERROR_FAILURE; // Progress meters are readonly!
}

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

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
letters.gif \
moz.png \
$(topsrcdir)/content/media/video/test/bug461281.ogg \
longdesc_src.html \
attributes.js \
common.js \
@ -65,7 +66,7 @@ _TEST_FILES =\
role.js \
test_accessnode_invalidation.html \
test_actions_aria.html \
test_actions_inputs.html \
$(warning test_actions_inputs.html temporarily disabled) \
test_actions.xul \
test_aria_activedescendant.html \
test_aria_role_article.html \
@ -74,6 +75,11 @@ _TEST_FILES =\
test_bug420863.html \
$(warning test_childAtPoint.xul temporarily disabled) \
test_cssattrs.html \
test_descr.html \
test_elm_filectrl.html \
test_elm_media.html \
test_elm_prgrsmtr.xul \
test_elm_txtcntnr.html \
test_events_caretmove.html \
test_events_mutation.html \
test_events_tree.xul \

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

@ -265,6 +265,38 @@ function ensureAccessibleTree(aAccOrElmOrID)
}
}
/**
* Compare expected and actual accessibles trees.
*/
function testAccessibleTree(aAccOrElmOrID, aAccTree)
{
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
return;
for (var prop in aAccTree) {
var msg = "Wrong value of property '" + prop + "'.";
if (prop == "role")
is(roleToString(acc[prop]), roleToString(aAccTree[prop]), msg);
else if (prop != "children")
is(acc[prop], aAccTree[prop], msg);
}
if ("children" in aAccTree) {
var children = acc.children;
is(aAccTree.children.length, children.length,
"Different amount of expected children.");
if (aAccTree.children.length == children.length) {
for (var i = 0; i < children.length; i++) {
var child = children.queryElementAt(i, nsIAccessible);
testAccessibleTree(child, aAccTree.children[i]);
}
}
}
}
/**
* Convert role to human readable string.
*/
@ -292,7 +324,7 @@ function statesToString(aStates, aExtraStates)
*/
function eventTypeToString(aEventType)
{
gAccRetrieval.getStringEventType(aEventType);
return gAccRetrieval.getStringEventType(aEventType);
}
/**

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

@ -2,7 +2,6 @@
// Role constants
const ROLE_ALERT = nsIAccessibleRole.ROLE_ALERT;
const ROLE_PUSHBUTTON = nsIAccessibleRole.ROLE_PUSHBUTTON;
const ROLE_CELL = nsIAccessibleRole.ROLE_CELL;
const ROLE_CHROME_WINDOW = nsIAccessibleRole.ROLE_CHROME_WINDOW;
const ROLE_COMBOBOX = nsIAccessibleRole.ROLE_COMBOBOX;
@ -26,7 +25,10 @@ const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
const ROLE_PARAGRAPH = nsIAccessibleRole.ROLE_PARAGRAPH;
const ROLE_PASSWORD_TEXT = nsIAccessibleRole.ROLE_PASSWORD_TEXT;
const ROLE_PROGRESSBAR = nsIAccessibleRole.ROLE_PROGRESSBAR;
const ROLE_PUSHBUTTON = nsIAccessibleRole.ROLE_PUSHBUTTON;
const ROLE_SECTION = nsIAccessibleRole.ROLE_SECTION;
const ROLE_SLIDER = nsIAccessibleRole.ROLE_SLIDER;
const ROLE_TABLE = nsIAccessibleRole.ROLE_TABLE;
const ROLE_TEXT_CONTAINER = nsIAccessibleRole.ROLE_TEXT_CONTAINER;
const ROLE_TEXT_LEAF = nsIAccessibleRole.ROLE_TEXT_LEAF;

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

@ -99,6 +99,21 @@
ID: "treeitem",
actionName: "activate",
events: CLICK_EVENTS
},
{
ID: "sortable",
actionName: "sort",
events: CLICK_EVENTS
},
{
ID: "expandable",
actionName: "expand",
events: CLICK_EVENTS
},
{
ID: "collapseable",
actionName: "collapse",
events: CLICK_EVENTS
}
];
testActions(actionsArray);
@ -160,5 +175,14 @@
<div role="tree">
<div id="treeitem" role="treeitem">Treeitem</div>
</div>
<div role="grid">
<div id="sortable" role="columnheader" aria-sort="ascending">
Columnheader
</div>
</div>
<div id="expandable" aria-expanded="false">collapsed</div>
<div id="collapseable" aria-expanded="true">expanded</div>
</body>
</html>

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

@ -0,0 +1,65 @@
<html>
<head>
<title>nsIAccessible::description tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript">
function testDescr(aAccOrElmOrID, aDescr)
{
var acc = getAccessible(aAccOrElmOrID);
if (!acc)
return;
is(acc.description, aDescr,
"Wrong description for " + prettyName(aAccOrElmOrID));
}
function doTest()
{
// Description from aria-describedby attribute
testDescr("img1", "aria description");
// No description from @title attribute because it is used to generate
// name.
testDescr("img2", "");
// Description from @title attribute, name is generated from @alt
// attribute.
testDescr("img3", "description");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489944"
title="@title attribute no longer exposed on accDescription">
Mozilla Bug 489944
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<p id="description">aria description</p>
<img id="img1" aria-describedby="description" />
<img id="img2" title="title" />
<img id="img3" alt="name" title="description" />
</body>
</html>

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

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=483573
-->
<head>
<title>File Input Control tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js"></script>
<script type="application/javascript">
function doTest()
{
var accTree = {
role: ROLE_TEXT_CONTAINER,
children: [
{
role: ROLE_ENTRY
},
{
role: ROLE_PUSHBUTTON
}
]
};
testAccessibleTree("filectrl", accTree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Expose HTML5 video and audio elements' embedded controls through accessibility APIs"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=483573">Mozilla Bug 483573</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<input type="file" id="filectrl" />
</body>
</html>

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

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=483573
-->
<head>
<title>HTML5 audio/video tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js"></script>
<script type="application/javascript">
function doTest()
{
var accTree = {
role: ROLE_GROUPING,
children: [
{ // start/stop button
role: ROLE_PUSHBUTTON
},
{ // buffer bar
role: ROLE_PROGRESSBAR
},
{ // progress bar
role: ROLE_PROGRESSBAR
},
{ // slider of progress bar
role: ROLE_SLIDER
},
{ // duration label
role: ROLE_LABEL
},
{ // mute button
role: ROLE_PUSHBUTTON
}
]
};
testAccessibleTree("audio", accTree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Expose HTML5 video and audio elements' embedded controls through accessibility APIs"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=483573">Mozilla Bug 483573</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<audio id="audio" src="chrome://mochikit/content/a11y/accessible/bug461281.ogg"
autoplay="true" controls="true">
</body>
</html>

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

@ -0,0 +1,73 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="XUL progressmeter tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript">
<![CDATA[
/**
* Helper function to test nsIAccessibleValue interface.
*/
function testValue(aAccOrElmOrId, aValue, aCurrValue,
aMinValue, aMaxValue, aMinIncr)
{
var acc = getAccessible(aAccOrElmOrId, [nsIAccessibleValue]);
if (!acc)
return;
is(acc.value, aValue, "Wrong value of " + prettyName(aAccOrElmOrId));
is(acc.currentValue, aCurrValue,
"Wrong current value of " + prettyName(aAccOrElmOrId));
is(acc.minimumValue, aMinValue,
"Wrong minimum value of " + prettyName(aAccOrElmOrId));
is(acc.maximumValue, aMaxValue,
"Wrong maximum value of " + prettyName(aAccOrElmOrId));
is(acc.minimumIncrement, aMinIncr,
"Wrong minimum increment value of " + prettyName(aAccOrElmOrId));
}
function doTest()
{
testValue("pm1", "50%", .5, 0, 1, 0);
testValue("pm2", "50%", 500, 0, 1000, 0);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489551"
title="Values of sliders and progress bars in HTML 5 audio and video element's control sets are not percentages">
Mozilla Bug 489551
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<progressmeter id="pm1" value="50"/>
<progressmeter id="pm2" value="500" max="1000"/>
</hbox>
</window>

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

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML text containers tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js"></script>
<script type="application/javascript">
function doTest()
{
var accTree = {
role: ROLE_SECTION,
children: [
{ // text child
role: ROLE_TEXT_LEAF
}
]
};
testAccessibleTree("c1", accTree);
testAccessibleTree("c2", accTree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="overflowed content doesn't expose child text accessibles"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489306">Mozilla Bug 489306</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="c1" style="width: 100px; height: 100px; overflow: auto;">
1hellohello 2hellohello 3hellohello 4hellohello 5hellohello 6hellohello 7hellohello
</div>
<div id="c2">
1hellohello 2hellohello 3hellohello 4hellohello 5hellohello 6hellohello 7hellohello
</div>
</body>
</html>

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

@ -19,7 +19,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=441737
<script type="application/javascript">
function doTest()
{
// Get accessible for body tag.
var docAcc = getAccessible(document, [nsIAccessibleDocument]);
if (docAcc) {
// nsIAccessible

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

@ -243,10 +243,10 @@
<hbox>
<label value="Search History:" accesskey="S"
control="search-box"/>
<textbox id="search-box" flex="1" type="search" cocoa-size="small"
<textbox id="search-box" flex="1" type="search"
results="historyTree"/>
</hbox>
<textbox id="searchfield" emptytext="Search all add-ons"
type="search" searchbutton="true" cocoa-size="small"/>
type="search" searchbutton="true"/>
</vbox>
</window>

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

@ -410,7 +410,7 @@ endif
else
ifdef LIBXUL_SDK
libs::
cp $(LIBXUL_DIST)/bin/xulrunner-stub$(BIN_SUFFIX) $(DIST)/bin/firefox$(BIN_SUFFIX)
cp $(LIBXUL_DIST)/bin/$(XULRUNNER_STUB_NAME)$(BIN_SUFFIX) $(DIST)/bin/firefox$(BIN_SUFFIX)
endif
endif

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

@ -18,6 +18,9 @@
</targetApplication>
</versionRange>
</emItem>
<emItem id="support@daemon-tools.cc">
<versionRange minVersion=" " maxVersion="1.0.0.5"/>
</emItem>
<emItem id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
<versionRange minVersion="1.2" maxVersion="1.2">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">

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

@ -395,7 +395,7 @@ pref("privacy.item.history", true);
pref("privacy.item.formdata", true);
pref("privacy.item.passwords", false);
pref("privacy.item.downloads", true);
pref("privacy.item.cookies", false);
pref("privacy.item.cookies", true);
pref("privacy.item.cache", true);
pref("privacy.item.sessions", true);
pref("privacy.item.offlineApps", false);
@ -434,8 +434,13 @@ pref("browser.gesture.swipe.left", "Browser:BackOrBackDuplicate");
pref("browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate");
pref("browser.gesture.swipe.up", "cmd_scrollTop");
pref("browser.gesture.swipe.down", "cmd_scrollBottom");
#ifdef XP_MACOSX
pref("browser.gesture.pinch.latched", true);
pref("browser.gesture.pinch.threshold", 150);
#else
pref("browser.gesture.pinch.latched", false);
pref("browser.gesture.pinch.threshold", 25);
#endif
pref("browser.gesture.pinch.out", "cmd_fullZoomEnlarge");
pref("browser.gesture.pinch.in", "cmd_fullZoomReduce");
pref("browser.gesture.pinch.out.shift", "cmd_fullZoomReset");
@ -444,6 +449,7 @@ pref("browser.gesture.twist.latched", false);
pref("browser.gesture.twist.threshold", 25);
pref("browser.gesture.twist.right", "Browser:NextTab");
pref("browser.gesture.twist.left", "Browser:PrevTab");
pref("browser.gesture.tap", "cmd_fullZoomReset");
// 0=lines, 1=pages, 2=history , 3=text size
#ifdef XP_MACOSX
@ -659,11 +665,6 @@ pref("browser.safebrowsing.provider.0.keyURL", "https://sb-ssl.google.com/safebr
pref("browser.safebrowsing.provider.0.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
pref("browser.safebrowsing.provider.0.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client={moz:client}&appver={moz:version}&pver=2.2");
// privacy policy -- Both url and fallbackurl must exist, although they may
// point to the same file. fallbackurl must be a chrome url
pref("browser.safebrowsing.provider.0.privacy.url", "http://www.google.com/tools/firefox/firefox_privacy.html?hl=%LOCALE%");
pref("browser.safebrowsing.provider.0.privacy.fallbackurl", "chrome://browser/content/preferences/phishEULA.xhtml");
// HTML report pages
pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
@ -671,8 +672,9 @@ pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phis
pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
// FAQ URL
// FAQ URLs
pref("browser.safebrowsing.warning.infoURL", "http://%LOCALE%.www.mozilla.com/%LOCALE%/firefox/phishing-protection/");
pref("browser.geolocation.warning.infoURL", "http://%LOCALE%.www.mozilla.com/%LOCALE%/firefox/geolocation/");
// Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233)
@ -730,6 +732,9 @@ pref("browser.sessionstore.postdata", 0);
pref("browser.sessionstore.privacy_level", 1);
// how many tabs can be reopened (per window)
pref("browser.sessionstore.max_tabs_undo", 10);
// how many windows can be reopened (per session) - on non-OS X platforms this
// pref may be ignored when dealing with pop-up windows to ensure proper startup
pref("browser.sessionstore.max_windows_undo", 3);
// number of crashes that can occur before the about:sessionrestore page is displayed
// (this pref has no effect if more than 6 hours have passed since the last crash)
pref("browser.sessionstore.max_resumed_crashes", 1);
@ -741,18 +746,6 @@ pref("accessibility.blockautorefresh", false);
// when calculating frecency
pref("places.frecency.numVisits", 10);
// Number of records to update frecency for when idle.
pref("places.frecency.numCalcOnIdle", 50);
// Number of records to update frecency for when migrating from
// a pre-frecency build.
pref("places.frecency.numCalcOnMigrate", 50);
// Perform frecency recalculation after this amount of idle, repeating.
// A value of zero disables updating of frecency on idle.
// Default is 1 minute (60000ms).
pref("places.frecency.updateIdleTime", 60000);
// buckets (in days) for frecency calculation
pref("places.frecency.firstBucketCutoff", 4);
pref("places.frecency.secondBucketCutoff", 14);
@ -826,3 +819,6 @@ pref("browser.privatebrowsing.dont_prompt_on_enter", false);
// Don't try to alter this pref, it'll be reset the next time you use the
// bookmarking dialog
pref("browser.bookmarks.editDialog.firstEditField", "namePicker");
// base url for the wifi geolocation network provider
pref("geo.wifi.uri", "https://www.google.com/loc/json");

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

@ -80,7 +80,7 @@
oncommand="openHelpLink('firefox-help')"
#ifdef XP_MACOSX
label="&helpContentsMac.label;"
key="key_openHelpMacFrontend"/>
key="key_openHelpMac"/>
#else
label="&helpContents.label;"
accesskey="&helpContents.accesskey;"
@ -95,12 +95,11 @@
<menuitem id="releaseNotes"
accesskey="&helpReleaseNotes.accesskey;"
label="&helpReleaseNotes.label;"
oncommand="openReleaseNotes(event)"
oncommand="openReleaseNotes()"
onclick="checkForMiddleClick(this, event);"/>
<menuseparator id="updateSeparator"/>
#ifdef MOZ_UPDATER
<menuitem id="checkForUpdates"
accesskey="&updateCmd.accesskey;"
label="&updateCmd.label;"
class="menuitem-iconic"
oncommand="checkForUpdates();"/>
@ -115,20 +114,20 @@
<keyset id="baseMenuKeyset">
#ifdef XP_MACOSX
<key id="key_openHelpMacFrontend"
<key id="key_openHelpMac"
oncommand="openHelpLink('firefox-help');"
key="&openHelpMac.frontendCommandkey;"
modifiers="&openHelpMac.frontendModifiers;"/>
key="&helpMac.commandkey;"
modifiers="accel"/>
<!-- These are used to build the Application menu under Cocoa widgets -->
<key id="key_preferencesCmdMac"
key="&preferencesCmdMac.commandkey;"
modifiers="&preferencesCmdMac.modifiers;"/>
modifiers="accel"/>
<key id="key_hideThisAppCmdMac"
key="&hideThisAppCmdMac.commandkey;"
modifiers="&hideThisAppCmdMac.modifiers;"/>
modifiers="accel"/>
<key id="key_hideOtherAppsCmdMac"
key="&hideOtherAppsCmdMac.commandkey;"
modifiers="&hideOtherAppsCmdMac.modifiers;"/>
modifiers="accel,alt"/>
#else
<key id="key_openHelp"
oncommand="openHelpLink('firefox-help');"

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

@ -493,6 +493,12 @@
<menupopup id="historyUndoPopup"
onpopupshowing="HistoryMenu.populateUndoSubmenu();"/>
</menu>
<menu id="historyUndoWindowMenu"
label="&historyUndoWindowMenu.label;"
disabled="true">
<menupopup id="historyUndoWindowPopup"
onpopupshowing="HistoryMenu.populateUndoWindowSubmenu();"/>
</menu>
</menupopup>
</menu>

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

@ -208,7 +208,6 @@ var StarUI = {
// multiple times.
var bookmarks = PlacesUtils.getBookmarksForURI(gBrowser.currentURI);
var forms = bundle.getString("editBookmark.removeBookmarks.label");
Cu.import("resource://gre/modules/PluralForm.jsm");
var label = PluralForm.get(bookmarks.length, forms).replace("#1", bookmarks.length);
this._element("editBookmarkPanelRemoveButton").label = label;
@ -594,6 +593,12 @@ var PlacesCommandHook = {
// Functions for the history menu.
var HistoryMenu = {
get _ss() {
delete this._ss;
return this._ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
getService(Components.interfaces.nsISessionStore);
},
/**
* popupshowing handler for the history menu.
* @param aMenuPopup
@ -609,8 +614,10 @@ var HistoryMenu = {
if (!wasOpen)
resultNode.containerOpen = false;
// HistoryMenu.toggleRecentlyClosedTabs is defined in browser.js
// HistoryMenu.toggleRecentlyClosedTabs, HistoryMenu.toggleRecentlyClosedWindows
// are defined in browser.js
this.toggleRecentlyClosedTabs();
this.toggleRecentlyClosedWindows();
}
};

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

@ -128,6 +128,7 @@
oncommand="Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null);"/>
<command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
</commandset>
<commandset id="placesCommands">
@ -329,6 +330,7 @@
#endif
<key id="key_undoCloseTab" command="History:UndoCloseTab" key="&tabCmd.commandkey;" modifiers="accel,shift"/>
<key id="key_undoCloseWindow" command="History:UndoCloseWindow" key="&newNavigatorCmd.key;" modifiers="accel,shift"/>
#ifdef XP_GNOME
#define NUM_SELECT_TAB_MODIFIER alt

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

@ -13,11 +13,20 @@ toolbar[printpreview="true"] {
-moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
}
toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
display: none;
}
/* ::::: location bar ::::: */
#urlbar {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
}
#wrapper-urlbar-container #urlbar {
-moz-user-input: disabled;
cursor: -moz-grab;
}
#PopupAutoComplete {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup");
}
@ -38,7 +47,7 @@ toolbar[printpreview="true"] {
#urlbar[pageproxystate="invalid"] > #urlbar-icons > :not(#go-button) ,
#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button ,
#urlbar[empty="true"] > #urlbar-icons > #go-button {
#urlbar[isempty="true"] > #urlbar-icons > #go-button {
visibility: collapse;
}
@ -96,6 +105,12 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
display: none;
}
/* Bug 483950 - Hide domain name in status bar pending removal */
#security-button > label {
display: none;
}
/* ::::: Fullscreen pseudo-toolbar ::::: */
#fullscr-toggler {
display: none;

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

@ -45,6 +45,7 @@
# Dão Gottwald <dao@mozilla.com>
# Thomas K. Dyas <tdyas@zecador.org>
# Edward Lee <edward.lee@engineering.uiuc.edu>
# Paul OShannessy <paul@oshannessy.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
@ -126,6 +127,15 @@ __defineGetter__("gPrefService", function() {
getService(Ci.nsIPrefBranch2);
});
__defineGetter__("PluralForm", function() {
Cu.import("resource://gre/modules/PluralForm.jsm");
return this.PluralForm;
});
__defineSetter__("PluralForm", function (val) {
delete this.PluralForm;
return this.PluralForm = val;
});
let gInitialPages = [
"about:blank",
"about:privatebrowsing",
@ -688,7 +698,8 @@ let gGestureSupport = {
init: function GS_init(aAddListener) {
const gestureEvents = ["SwipeGesture",
"MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
"RotateGestureStart", "RotateGestureUpdate", "RotateGesture"];
"RotateGestureStart", "RotateGestureUpdate", "RotateGesture",
"TapGesture", "PressTapGesture"];
let addRemove = aAddListener ? window.addEventListener :
window.removeEventListener;
@ -714,14 +725,28 @@ let gGestureSupport = {
switch (aEvent.type) {
case "MozSwipeGesture":
aEvent.preventDefault();
return this.onSwipe(aEvent);
case "MozMagnifyGestureStart":
aEvent.preventDefault();
#ifdef XP_WIN
return this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in");
#else
return this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in");
#endif
case "MozRotateGestureStart":
aEvent.preventDefault();
return this._setupGesture(aEvent, "twist", def(25, 0), "right", "left");
case "MozMagnifyGestureUpdate":
case "MozRotateGestureUpdate":
aEvent.preventDefault();
return this._doUpdate(aEvent);
case "MozTapGesture":
aEvent.preventDefault();
return this._doAction(aEvent, ["tap"]);
case "MozPressTapGesture":
// Fall through to default behavior
return;
}
},
@ -1203,7 +1228,7 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
focusElement(content);
if (gURLBar)
gURLBar.setAttribute("emptytext", gURLBar.getAttribute("delayedemptytext"));
gURLBar.setAttribute("emptytext", gURLBarEmptyText.value);
gNavToolbox.customizeDone = BrowserToolboxCustomizeDone;
gNavToolbox.customizeChange = BrowserToolboxCustomizeChange;
@ -1218,6 +1243,8 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
gPrefService.addObserver(gHomeButton.prefDomain, gHomeButton, false);
gPrefService.addObserver(gURLBarEmptyText.domain, gURLBarEmptyText, false);
var homeButton = document.getElementById("home-button");
gHomeButton.updateTooltip(homeButton);
gHomeButton.updatePersonalToolbarStyle(homeButton);
@ -1386,6 +1413,7 @@ function BrowserShutdown()
gPrefService.removeObserver(gAutoHideTabbarPrefListener.domain,
gAutoHideTabbarPrefListener);
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
gPrefService.removeObserver(gURLBarEmptyText.domain, gURLBarEmptyText);
} catch (ex) {
Components.utils.reportError(ex);
}
@ -3077,6 +3105,21 @@ const BrowserSearch = {
}
function FillHistoryMenu(aParent) {
// Lazily add the hover listeners on first showing and never remove them
if (!aParent.hasStatusListener) {
// Show history item's uri in the status bar when hovering, and clear on exit
aParent.addEventListener("DOMMenuItemActive", function(aEvent) {
// Only the current page should have the checked attribute, so skip it
if (!aEvent.target.hasAttribute("checked"))
XULBrowserWindow.setOverLink(aEvent.target.getAttribute("uri"));
}, false);
aParent.addEventListener("DOMMenuItemInactive", function() {
XULBrowserWindow.setOverLink("");
}, false);
aParent.hasStatusListener = true;
}
// Remove old entries if any
var children = aParent.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
@ -3108,8 +3151,10 @@ function FillHistoryMenu(aParent) {
for (var j = end - 1; j >= start; j--) {
let item = document.createElement("menuitem");
let entry = sessionHistory.getEntryAtIndex(j, false);
let uri = entry.URI.spec;
item.setAttribute("label", entry.title || entry.URI.spec);
item.setAttribute("uri", uri);
item.setAttribute("label", entry.title || uri);
item.setAttribute("index", j);
if (j != index) {
@ -3260,7 +3305,7 @@ function BrowserCustomizeToolbar()
#else
return window.openDialog(customizeURL,
"CustomizeToolbar",
"chrome,titlebar,toolbar,resizable,dependent",
"chrome,titlebar,toolbar,location,resizable,dependent",
gNavToolbox);
#endif
}
@ -3275,7 +3320,7 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
if (aToolboxChanged) {
gURLBar = document.getElementById("urlbar");
if (gURLBar)
gURLBar.emptyText = gURLBar.getAttribute("delayedemptytext");
gURLBar.emptyText = gURLBarEmptyText.value;
gProxyFavIcon = document.getElementById("page-proxy-favicon");
gHomeButton.updateTooltip();
@ -4920,24 +4965,6 @@ var contentAreaDNDObserver = {
var dragType = aXferData.flavour.contentType;
var dragData = aXferData.data;
if (dragType == TAB_DROP_TYPE) {
// If the tab was dragged from some other tab bar, its own dragend
// handler will take care of detaching the tab
if (dragData instanceof XULElement && dragData.localName == "tab" &&
dragData.ownerDocument.defaultView == window) {
// Detach only if the mouse pointer was released a little
// bit down in the content area (to be precise, by half the height
// of a tab)
if (aEvent.screenY > gBrowser.mPanelContainer.boxObject.screenY +
dragData.boxObject.height / 2) {
gBrowser.replaceTabWithWindow(dragData);
aEvent.dataTransfer.dropEffect = "move";
return;
}
}
aEvent.dataTransfer.dropEffect = "none";
return;
}
var url = transferUtils.retrieveURLFromData(dragData, dragType);
@ -6170,11 +6197,8 @@ HistoryMenu.toggleRecentlyClosedTabs = function PHM_toggleRecentlyClosedTabs() {
// enable/disable the Recently Closed Tabs sub menu
var undoPopup = document.getElementById("historyUndoPopup");
// get closed-tabs from nsSessionStore
var ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
// no restorable tabs, so disable menu
if (ss.getClosedTabCount(window) == 0)
if (this._ss.getClosedTabCount(window) == 0)
undoPopup.parentNode.setAttribute("disabled", true);
else
undoPopup.parentNode.removeAttribute("disabled");
@ -6190,11 +6214,8 @@ HistoryMenu.populateUndoSubmenu = function PHM_populateUndoSubmenu() {
while (undoPopup.hasChildNodes())
undoPopup.removeChild(undoPopup.firstChild);
// get closed-tabs from nsSessionStore
var ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
// no restorable tabs, so make sure menu is disabled, and return
if (ss.getClosedTabCount(window) == 0) {
if (this._ss.getClosedTabCount(window) == 0) {
undoPopup.parentNode.setAttribute("disabled", true);
return;
}
@ -6203,7 +6224,7 @@ HistoryMenu.populateUndoSubmenu = function PHM_populateUndoSubmenu() {
undoPopup.parentNode.removeAttribute("disabled");
// populate menu
var undoItems = eval("(" + ss.getClosedTabData(window) + ")");
var undoItems = eval("(" + this._ss.getClosedTabData(window) + ")");
for (var i = 0; i < undoItems.length; i++) {
var m = document.createElement("menuitem");
m.setAttribute("label", undoItems[i].title);
@ -6235,6 +6256,74 @@ HistoryMenu.populateUndoSubmenu = function PHM_populateUndoSubmenu() {
}, false);
}
HistoryMenu.toggleRecentlyClosedWindows = function PHM_toggleRecentlyClosedWindows() {
// enable/disable the Recently Closed Windows sub menu
let undoPopup = document.getElementById("historyUndoWindowPopup");
// no restorable windows, so disable menu
if (this._ss.getClosedWindowCount() == 0)
undoPopup.parentNode.setAttribute("disabled", true);
else
undoPopup.parentNode.removeAttribute("disabled");
}
/**
* Populate when the history menu is opened
*/
HistoryMenu.populateUndoWindowSubmenu = function PHM_populateUndoWindowSubmenu() {
let undoPopup = document.getElementById("historyUndoWindowPopup");
let menuLabelString = gNavigatorBundle.getString("menuUndoCloseWindowLabel");
let menuLabelStringSingleTab =
gNavigatorBundle.getString("menuUndoCloseWindowSingleTabLabel");
// remove existing menu items
while (undoPopup.hasChildNodes())
undoPopup.removeChild(undoPopup.firstChild);
// no restorable windows, so make sure menu is disabled, and return
if (this._ss.getClosedWindowCount() == 0) {
undoPopup.parentNode.setAttribute("disabled", true);
return;
}
// enable menu
undoPopup.parentNode.removeAttribute("disabled");
// populate menu
let undoItems = JSON.parse(this._ss.getClosedWindowData());
for (let i = 0; i < undoItems.length; i++) {
let undoItem = undoItems[i];
let otherTabsCount = undoItem.tabs.length - 1;
let label = (otherTabsCount == 0) ? menuLabelStringSingleTab
: PluralForm.get(otherTabsCount, menuLabelString);
let menuLabel = label.replace("#1", undoItem.title)
.replace("#2", otherTabsCount);
let m = document.createElement("menuitem");
m.setAttribute("label", menuLabel);
let selectedTab = undoItem.tabs[undoItem.selected - 1];
if (selectedTab.attributes.image) {
let iconURL = selectedTab.attributes.image;
// don't initiate a connection just to fetch a favicon (see bug 467828)
if (/^https?:/.test(iconURL))
iconURL = "moz-anno:favicon:" + iconURL;
m.setAttribute("image", iconURL);
}
m.setAttribute("class", "menuitem-iconic bookmark-item");
m.setAttribute("oncommand", "undoCloseWindow(" + i + ");");
if (i == 0)
m.setAttribute("key", "key_undoCloseWindow");
undoPopup.appendChild(m);
}
// "Open All in Windows"
undoPopup.appendChild(document.createElement("menuseparator"));
let m = undoPopup.appendChild(document.createElement("menuitem"));
m.setAttribute("label", gNavigatorBundle.getString("menuRestoreAllWindows.label"));
m.setAttribute("accesskey", gNavigatorBundle.getString("menuRestoreAllWindows.accesskey"));
m.setAttribute("oncommand",
"for (var i = 0; i < " + undoItems.length + "; i++) undoCloseWindow();");
}
/**
* Re-open a closed tab and put it to the end of the tab strip.
* Used for a middle click.
@ -6279,6 +6368,22 @@ function undoCloseTab(aIndex) {
return tab;
}
/**
* Re-open a closed window.
* @param aIndex
* The index of the window (via nsSessionStore.getClosedWindowData)
* @returns a reference to the reopened window.
*/
function undoCloseWindow(aIndex) {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
let window = null;
if (ss.getClosedWindowCount() > (aIndex || 0))
window = ss.undoCloseWindow(aIndex || 0);
return window;
}
/**
* Format a URL
* eg:
@ -6719,7 +6824,6 @@ let DownloadMonitorPanel = {
init: function DMP_init() {
// Load the modules to help display strings
Cu.import("resource://gre/modules/DownloadUtils.jsm");
Cu.import("resource://gre/modules/PluralForm.jsm");
// Initialize "private" member variables
this._panel = document.getElementById("download-monitor");
@ -6935,7 +7039,14 @@ let gPrivateBrowsingUI = {
this._privateBrowsingAutoStarted = this._privateBrowsingService.autoStarted;
if (!this._privateBrowsingAutoStarted) {
if (this._privateBrowsingAutoStarted) {
// Disable the menu item in auto-start mode
document.getElementById("privateBrowsingItem")
.setAttribute("disabled", "true");
document.getElementById("Tools:PrivateBrowsing")
.setAttribute("disabled", "true");
}
else if (window.location.href == getBrowserURL()) {
// Adjust the window's title
let docElement = document.documentElement;
docElement.setAttribute("title",
@ -6944,14 +7055,6 @@ let gPrivateBrowsingUI = {
docElement.getAttribute("titlemodifier_privatebrowsing"));
docElement.setAttribute("browsingmode", "private");
}
else {
// Disable the menu item in auto-start mode
let pbMenuItem = document.getElementById("privateBrowsingItem");
if (pbMenuItem)
pbMenuItem.setAttribute("disabled", "true");
document.getElementById("Tools:PrivateBrowsing")
.setAttribute("disabled", "true");
}
},
onExitPrivateBrowsing: function PBUI_onExitPrivateBrowsing() {
@ -6969,7 +7072,7 @@ let gPrivateBrowsingUI = {
this._setPBMenuTitle("start");
if (!this._privateBrowsingAutoStarted) {
if (window.location.href == getBrowserURL()) {
// Adjust the window's title
let docElement = document.documentElement;
docElement.setAttribute("title",
@ -6978,16 +7081,20 @@ let gPrivateBrowsingUI = {
docElement.getAttribute("titlemodifier_normal"));
docElement.setAttribute("browsingmode", "normal");
}
else
this._privateBrowsingAutoStarted = false;
// Enable the menu item in after exiting the auto-start mode
document.getElementById("privateBrowsingItem")
.removeAttribute("disabled");
document.getElementById("Tools:PrivateBrowsing")
.removeAttribute("disabled");
this._privateBrowsingAutoStarted = false;
},
_setPBMenuTitle: function PBUI__setPBMenuTitle(aMode) {
let pbMenuItem = document.getElementById("privateBrowsingItem");
if (pbMenuItem) {
pbMenuItem.setAttribute("label", pbMenuItem.getAttribute(aMode + "label"));
pbMenuItem.setAttribute("accesskey", pbMenuItem.getAttribute(aMode + "accesskey"));
}
pbMenuItem.setAttribute("label", pbMenuItem.getAttribute(aMode + "label"));
pbMenuItem.setAttribute("accesskey", pbMenuItem.getAttribute(aMode + "accesskey"));
},
toggleMode: function PBUI_toggleMode() {
@ -7004,3 +7111,37 @@ let gPrivateBrowsingUI = {
return this._privateBrowsingService.privateBrowsingEnabled;
}
};
let gURLBarEmptyText = {
domain: "browser.urlbar.",
observe: function UBET_observe(aSubject, aTopic, aPrefName) {
if (aTopic == "nsPref:changed") {
switch (aPrefName) {
case "browser.urlbar.autocomplete.enabled":
case "browser.urlbar.default.behavior":
gURLBar.emptyText = this.value;
break;
}
}
},
get value UBET_get_value() {
let type = "none";
if (gPrefService.getBoolPref("browser.urlbar.autocomplete.enabled")) {
// Bottom 2 bits of default.behavior specify history/bookmark
switch (gPrefService.getIntPref("browser.urlbar.default.behavior") & 3) {
case 0:
type = "bookmarkhistory";
break;
case 1:
type = "history";
break;
case 2:
type = "bookmark";
break;
}
}
return gURLBar.getAttribute(type + "emptytext");
}
};

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

@ -65,8 +65,6 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="BrowserStartup()" onunload="BrowserShutdown()" onclose="return WindowIsClosing();"
ondragleave="gBrowser.browserWindowOnDragLeave(event);"
ondragenter="gBrowser.browserWindowOnDragEnter(event);"
title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
title_normal="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
#ifdef XP_MACOSX
@ -350,7 +348,10 @@
<toolbaritem id="urlbar-container" align="center" flex="400" persist="width"
title="&locationItem.title;" class="chromeclass-location">
<textbox id="urlbar" flex="1"
delayedemptytext="&urlbar.emptyText;"
bookmarkhistoryemptytext="&urlbar.bookmarkhistory.emptyText;"
bookmarkemptytext="&urlbar.bookmark.emptyText;"
historyemptytext="&urlbar.history.emptyText;"
noneemptytext="&urlbar.none.emptyText;"
chromedir="&locale.dir;"
type="autocomplete"
autocompletesearch="history"

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

@ -865,7 +865,7 @@ function makePreview(row)
item instanceof HTMLLinkElement)
mimeType = item.type;
if (!mimeType && item instanceof nsIImageLoadingContent) {
if (!mimeType && !isBG && item instanceof nsIImageLoadingContent) {
var imageRequest = item.getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
if (imageRequest) {
mimeType = imageRequest.mimeType;
@ -877,23 +877,28 @@ function makePreview(row)
if (!mimeType)
mimeType = getContentTypeFromHeaders(cacheEntryDescriptor);
var imageType;
if (mimeType) {
// We found the type, try to display it nicely
var imageMimeType = /^image\/(.*)/.exec(mimeType);
if (imageMimeType) {
mimeType = imageMimeType[1].toUpperCase();
imageType = imageMimeType[1].toUpperCase();
if (numFrames > 1)
mimeType = gBundle.getFormattedString("mediaAnimatedImageType",
[mimeType, numFrames]);
imageType = gBundle.getFormattedString("mediaAnimatedImageType",
[imageType, numFrames]);
else
mimeType = gBundle.getFormattedString("mediaImageType", [mimeType]);
imageType = gBundle.getFormattedString("mediaImageType", [imageType]);
}
else {
// the MIME type doesn't begin with image/, display the raw type
imageType = mimeType;
}
}
else {
// We couldn't find the type, fall back to the value in the treeview
mimeType = gImageView.data[row][COL_IMAGE_TYPE];
imageType = gImageView.data[row][COL_IMAGE_TYPE];
}
setItemValue("imagetypetext", mimeType);
setItemValue("imagetypetext", imageType);
var imageContainer = document.getElementById("theimagecontainer");
var oldImage = document.getElementById("thepreviewimage");

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

@ -114,23 +114,21 @@
<menuitem id="menu_copy" label="&copy.label;" command="cmd_copy" accesskey="&copy.accesskey;"/>
</menupopup>
<windowdragbox orient="vertical">
<stack id="topStackBar">
<radiogroup id="viewGroup" class="viewSelector chromeclass-toolbar" orient="horizontal"
chromedir="&locale.dir;">
<radio id="generalTab" label="&generalTab;" accesskey="&generalTab.accesskey;"
oncommand="showTab('general');"/>
<radio id="mediaTab" label="&mediaTab;" accesskey="&mediaTab.accesskey;"
oncommand="showTab('media'); ensureSelection(gImageView)" hidden="true"/>
<radio id="feedTab" label="&feedTab;" accesskey="&feedTab.accesskey;"
oncommand="showTab('feed');" hidden="true"/>
<radio id="permTab" label="&permTab;" accesskey="&permTab.accesskey;"
oncommand="showTab('perm');"/>
<radio id="securityTab" label="&securityTab;" accesskey="&securityTab.accesskey;"
oncommand="showTab('security');"/>
<!-- Others added by overlay -->
</radiogroup>
</stack>
<windowdragbox id="topBar" class="viewGroupWrapper">
<radiogroup id="viewGroup" class="chromeclass-toolbar" orient="horizontal"
chromedir="&locale.dir;">
<radio id="generalTab" label="&generalTab;" accesskey="&generalTab.accesskey;"
oncommand="showTab('general');"/>
<radio id="mediaTab" label="&mediaTab;" accesskey="&mediaTab.accesskey;"
oncommand="showTab('media'); ensureSelection(gImageView)" hidden="true"/>
<radio id="feedTab" label="&feedTab;" accesskey="&feedTab.accesskey;"
oncommand="showTab('feed');" hidden="true"/>
<radio id="permTab" label="&permTab;" accesskey="&permTab.accesskey;"
oncommand="showTab('perm');"/>
<radio id="securityTab" label="&securityTab;" accesskey="&securityTab.accesskey;"
oncommand="showTab('security');"/>
<!-- Others added by overlay -->
</radiogroup>
</windowdragbox>
<deck id="mainDeck" flex="1">

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

@ -90,8 +90,7 @@ function disableAddons() {
// Select the default theme
var prefB = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
if (prefB.prefHasUserValue("general.skins.selectedSkin"))
prefB.clearUserPref("general.skins.selectedSkin");
prefB.clearUserPref("general.skins.selectedSkin");
// Disable plugins
var phs = Components.classes["@mozilla.org/plugin/host;1"]

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

@ -77,7 +77,7 @@ Sanitizer.prototype = {
if (this.ignoreTimespan)
var range = null; // If we ignore timespan, clear everything
else
range = Sanitizer.getClearRange();
range = this.range || Sanitizer.getClearRange();
for (var itemName in this.items) {
var item = this.items[itemName];
@ -102,8 +102,12 @@ Sanitizer.prototype = {
},
// Time span only makes sense in certain cases. Consumers who want
// to only clear some private data can opt in by setting this to false
// to only clear some private data can opt in by setting this to false,
// and can optionally specify a specific range. If timespan is not ignored,
// and range is not set, sanitize() will use the value of the timespan
// pref to determine a range
ignoreTimespan : true,
range : null,
items: {
cache: {
@ -148,6 +152,14 @@ Sanitizer.prototype = {
cookieMgr.removeAll();
}
// clear any network geolocation provider sessions
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
try {
var branch = psvc.getBranch("geo.wifi.access_token.");
branch.deleteBranch("");
} catch (e) {}
},
get canClear()
@ -387,9 +399,11 @@ Sanitizer.TIMESPAN_TODAY = 4;
// Return a 2 element array representing the start and end times,
// in the uSec-since-epoch format that PRTime likes. If we should
// clear everything, return null
Sanitizer.getClearRange = function() {
var ts = Sanitizer.prefs.getIntPref("timeSpan");
// clear everything, return null. Use ts if it is defined; otherwise
// use the timeSpan pref.
Sanitizer.getClearRange = function (ts) {
if (ts === undefined)
ts = Sanitizer.prefs.getIntPref("timeSpan");
if (ts === Sanitizer.TIMESPAN_EVERYTHING)
return null;

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

@ -25,6 +25,7 @@
# Ben Goodger <ben@mozilla.org>
# Giorgio Maone <g.maone@informaction.com>
# Johnathan Nightingale <johnath@mozilla.com>
# Drew Willcoxon <adw@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
@ -42,6 +43,13 @@
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/sanitizeDialog.css"?>
#ifdef CRH_DIALOG_TREE_VIEW
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
#endif
<?xml-stylesheet href="chrome://browser/content/sanitizeDialog.css"?>
<!DOCTYPE prefwindow [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
@ -54,129 +62,28 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
dlgbuttons="accept,cancel"
title="&sanitizeDialog2.title;"
noneverythingtitle="&sanitizeDialog2.title;"
style="width: &dialog.width;;"
ondialogaccept="gSanitizePromptDialog.sanitize();">
<prefpane id="SanitizeDialogPane" onpaneload="gSanitizePromptDialog.init();">
<stringbundle id="bundleBrowser" src="chrome://browser/locale/browser.properties"/>
<script type="application/x-javascript" src="chrome://browser/content/sanitize.js"/>
<script type="application/x-javascript">
<![CDATA[
var gSanitizePromptDialog = {
init: function ()
{
this.checkPrefs();
var s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
var sanitizePreferences = document.getElementById("sanitizePreferences");
for (var i = 0; i < sanitizePreferences.childNodes.length; ++i) {
var preference = sanitizePreferences.childNodes[i];
var name = s.getNameFromPreference(preference.name);
if (!s.canClearItem(name))
preference.disabled = true;
}
var bundleBrowser = document.getElementById("bundleBrowser");
document.documentElement.getButton("accept").label = bundleBrowser.getString("sanitizeButtonOK");
},
checkPrefs : function ()
{
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
var cpdBranch = prefService.getBranch("privacy.cpd.");
// If we don't have defaults for the privacy.cpd branch,
// clone the privacy.item (clear at shutdown) defaults
if (cpdBranch.prefHasUserValue("history"))
return;
var itemBranch = prefService.getBranch("privacy.item.");
var itemCount = { value: 0 };
var itemArray = itemBranch.getChildList("", itemCount);
itemArray.forEach(function (name) {
cpdBranch.setBoolPref(name, itemBranch.getBoolPref(name));
});
},
sanitize: function ()
{
// Update pref values before handing off to the sanitizer (bug 453440)
this.updatePrefs();
var s = new Sanitizer();
s.ignoreTimespan = false;
s.prefDomain = "privacy.cpd.";
try {
s.sanitize();
} catch (er) {
Components.utils.reportError("Exception during sanitize: " + er);
}
return true;
},
onReadGeneric: function ()
{
var preferences = document.getElementById("sanitizePreferences");
var found = false;
for (var i = 0; i < preferences.childNodes.length; ++i) {
var preference = preferences.childNodes[i];
if (preference.value && !preference.disabled) {
found = true;
break;
}
}
try {
document.documentElement.getButton("accept").disabled = !found;
}
catch (e) { }
return undefined;
},
<stringbundle id="bundleBrowser"
src="chrome://browser/locale/browser.properties"/>
onReadDownloads: function (aEvent)
{
// Call the common function that will update the accept button if needed
this.onReadGeneric();
<script type="application/javascript"
src="chrome://browser/content/sanitize.js"/>
let historyPref = document.getElementById("privacy.cpd.history")
let downloadPref = document.getElementById("privacy.cpd.downloads");
#ifdef CRH_DIALOG_TREE_VIEW
<script type="application/javascript"
src="chrome://global/content/globalOverlay.js"/>
<script type="application/javascript"
src="chrome://browser/content/places/utils.js"/>
<script type="application/javascript"
src="chrome://browser/content/places/treeView.js"/>
#endif
// Disable the checkbox if history is selected
let downloads = document.getElementById("downloads-checkbox");
downloads.disabled = historyPref.value;
// The "Download History" checkbox is selected if either of the history or
// downloads preferences are true.
return historyPref.value || downloadPref.value;
},
updateDownloadHistory: function ()
{
// When toggling history, we automatically clear download history too,
// so we disable that control and set its value to true.
let downloads = document.getElementById("downloads-checkbox");
let history = document.getElementById("history-checkbox");
let s = new Sanitizer();
downloads.disabled = history.checked ||
!s.canClearItem("downloads");
if (history.checked)
downloads.checked = true;
},
updatePrefs : function ()
{
var tsPref = document.getElementById("privacy.sanitize.timeSpan");
Sanitizer.prefs.setIntPref("timeSpan", tsPref.value);
var sanitizePreferences = document.getElementById("sanitizePreferences");
var prefs = sanitizePreferences.rootBranch;
for (var i = 0; i < sanitizePreferences.childNodes.length; ++i) {
var p = sanitizePreferences.childNodes[i];
prefs.setBoolPref(p.name, p.value);
}
}
};
]]>
</script>
<script type="application/javascript"
src="chrome://browser/content/sanitizeDialog.js"/>
<preferences id="sanitizePreferences">
<preference id="privacy.cpd.history" name="privacy.cpd.history" type="bool"/>
@ -196,77 +103,121 @@
type="int"/>
</preferences>
<groupbox orient="vertical">
<caption label="&historySection.label;"/>
<hbox id="SanitizeDurationBox" align="center">
<label value="&clearTimeDuration.label;" control="sanitizeDurationChoice"
accesskey="&clearTimeDuration.accesskey;" id="sanitizeDurationLabel"/>
<menulist id="sanitizeDurationChoice"
preference="privacy.sanitize.timeSpan">
<menupopup>
<menuitem label="&clearTimeDuration.lastHour;" value="1"/>
<menuitem label="&clearTimeDuration.last2Hours;" value="2"/>
<menuitem label="&clearTimeDuration.last4Hours;" value="3"/>
<menuitem label="&clearTimeDuration.today;" value="4"/>
<menuseparator/>
<menuitem label="&clearTimeDuration.everything;" value="0"/>
</menupopup>
</menulist>
<label value="&clearTimeDuration.suffix;" flex="1"/>
</hbox>
<hbox>
<vbox style="width: &column.width;">
<checkbox id="history-checkbox"
label="&itemBrowsingHistory.label;"
accesskey="&itemBrowsingHistory.accesskey;"
preference="privacy.cpd.history"
oncommand="gSanitizePromptDialog.updateDownloadHistory();"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<checkbox id="downloads-checkbox"
label="&itemDownloadHistory.label;"
accesskey="&itemDownloadHistory.accesskey;"
preference="privacy.cpd.downloads"
onsyncfrompreference="return gSanitizePromptDialog.onReadDownloads();"/>
<checkbox label="&itemFormSearchHistory.label;"
accesskey="&itemFormSearchHistory.accesskey;"
preference="privacy.cpd.formdata"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
</vbox>
<vbox style="width: &column.width;">
<checkbox label="&itemCookies.label;"
accesskey="&itemCookies.accesskey;"
preference="privacy.cpd.cookies"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<checkbox label="&itemActiveLogins.label;"
accesskey="&itemActiveLogins.accesskey;"
preference="privacy.cpd.sessions"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<checkbox label="&itemCache.label;"
accesskey="&itemCache.accesskey;"
preference="privacy.cpd.cache"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
</vbox>
</hbox>
</groupbox>
<groupbox orient="horizontal">
<caption label="&dataSection.label;"/>
<vbox style="width: &column.width;">
<checkbox label="&itemPasswords.label;"
accesskey="&itemPasswords.accesskey;"
preference="privacy.cpd.passwords"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<checkbox label="&itemSitePreferences.label;"
accesskey="&itemSitePreferences.accesskey;"
preference="privacy.cpd.siteSettings"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<hbox id="SanitizeDurationBox" align="center">
<label value="&clearTimeDuration.label;"
accesskey="&clearTimeDuration.accesskey;"
control="sanitizeDurationChoice"
id="sanitizeDurationLabel"/>
<menulist id="sanitizeDurationChoice"
preference="privacy.sanitize.timeSpan"
onselect="gSanitizePromptDialog.selectByTimespan();"
flex="1">
<menupopup id="sanitizeDurationPopup">
#ifdef CRH_DIALOG_TREE_VIEW
<menuitem label="" value="-1" id="sanitizeDurationCustom"/>
#endif
<menuitem label="&clearTimeDuration.lastHour;" value="1"/>
<menuitem label="&clearTimeDuration.last2Hours;" value="2"/>
<menuitem label="&clearTimeDuration.last4Hours;" value="3"/>
<menuitem label="&clearTimeDuration.today;" value="4"/>
<menuseparator/>
<menuitem label="&clearTimeDuration.everything;" value="0"/>
</menupopup>
</menulist>
<label id="sanitizeDurationSuffixLabel"
value="&clearTimeDuration.suffix;"/>
</hbox>
#ifdef CRH_DIALOG_TREE_VIEW
<deck id="durationDeck">
<tree id="placesTree" flex="1" hidecolumnpicker="true" rows="10"
disabled="true" disableKeyNavigation="true">
<treecols>
<treecol id="date" label="&clearTimeDuration.dateColumn;" flex="1"/>
<splitter class="tree-splitter"/>
<treecol id="title" label="&clearTimeDuration.nameColumn;" flex="5"/>
</treecols>
<treechildren id="placesTreechildren"
ondragstart="gSanitizePromptDialog.grippyMoved('ondragstart', event);"
ondragover="gSanitizePromptDialog.grippyMoved('ondragover', event);"
onkeypress="gSanitizePromptDialog.grippyMoved('onkeypress', event);"
onmousedown="gSanitizePromptDialog.grippyMoved('onmousedown', event);"/>
</tree>
#endif
<vbox id="sanitizeEverythingWarningBox">
<spacer flex="1"/>
<hbox align="center">
<image id="sanitizeEverythingWarningIcon"/>
<vbox id="sanitizeEverythingWarningDescBox">
<description id="sanitizeEverythingWarning"/>
<description id="sanitizeEverythingUndoWarning">&sanitizeEverythingUndoWarning;</description>
</vbox>
</hbox>
<spacer flex="1"/>
</vbox>
<vbox style="width: &column.width;">
<checkbox label="&itemOfflineApps.label;"
accesskey="&itemOfflineApps.accesskey;"
preference="privacy.cpd.offlineApps"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
</vbox>
</groupbox>
#ifdef CRH_DIALOG_TREE_VIEW
</deck>
#endif
<separator class="thin"/>
<hbox id="detailsExpanderWrapper" align="center">
<button type="image"
id="detailsExpander"
class="expander-down"
oncommand="gSanitizePromptDialog.toggleItemList();"/>
<label id="detailsExpanderLabel"
value="&detailsProgressiveDisclosure.label;"
accesskey="&detailsProgressiveDisclosure.accesskey;"
control="detailsExpander"/>
</hbox>
<listbox id="itemList" rows="4" collapsed="true">
<listitem id="history-downloads-checkbox"
label="&itemHistoryAndDownloads.label;"
type="checkbox"
accesskey="&itemHistoryAndDownloads.accesskey;"
oncommand="gSanitizePromptDialog.onReadGeneric();"/>
<listitem label="&itemFormSearchHistory.label;"
type="checkbox"
accesskey="&itemFormSearchHistory.accesskey;"
preference="privacy.cpd.formdata"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<listitem label="&itemCookies.label;"
type="checkbox"
accesskey="&itemCookies.accesskey;"
preference="privacy.cpd.cookies"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<listitem label="&itemCache.label;"
type="checkbox"
accesskey="&itemCache.accesskey;"
preference="privacy.cpd.cache"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<listitem label="&itemActiveLogins.label;"
type="checkbox"
accesskey="&itemActiveLogins.accesskey;"
preference="privacy.cpd.sessions"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
<listitem label="&itemSitePreferences.label;"
type="checkbox"
accesskey="&itemSitePreferences.accesskey;"
preference="privacy.cpd.siteSettings"
noduration="true"
onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
</listbox>
<!-- The separate history and downloads prefs are subsumed by the combined
history-downloads checkbox, but by hiding them here we can take
advantage of the onsyncfrompreference events. -->
<checkbox id="history-checkbox"
preference="privacy.cpd.history"
onsyncfrompreference="return gSanitizePromptDialog.onReadHistoryOrDownloads();"
hidden="true"/>
<checkbox id="downloads-checkbox"
preference="privacy.cpd.downloads"
onsyncfrompreference="return gSanitizePromptDialog.onReadHistoryOrDownloads();"
hidden="true"/>
</prefpane>
</prefwindow>

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

@ -0,0 +1,19 @@
/* Places tree */
#placesTreechildren {
-moz-user-focus: normal;
}
#placesTreechildren::-moz-tree-cell(grippyRow),
#placesTreechildren::-moz-tree-cell-text(grippyRow),
#placesTreechildren::-moz-tree-image(grippyRow) {
cursor: -moz-grab;
}
/* Sanitize everything warnings */
#sanitizeEverythingWarning,
#sanitizeEverythingUndoWarning {
white-space: pre-wrap;
}

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

@ -0,0 +1,934 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Firefox Sanitizer.
*
* The Initial Developer of the Original Code is
* Ben Goodger.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Goodger <ben@mozilla.org>
* Giorgio Maone <g.maone@informaction.com>
* Johnathan Nightingale <johnath@mozilla.com>
* Drew Willcoxon <adw@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 ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
var gSanitizePromptDialog = {
get bundleBrowser()
{
if (!this._bundleBrowser)
this._bundleBrowser = document.getElementById("bundleBrowser");
return this._bundleBrowser;
},
get selectedTimespan()
{
var durList = document.getElementById("sanitizeDurationChoice");
return parseInt(durList.value);
},
get sanitizePreferences()
{
if (!this._sanitizePreferences) {
this._sanitizePreferences =
document.getElementById("sanitizePreferences");
}
return this._sanitizePreferences;
},
get warningBox()
{
return document.getElementById("sanitizeEverythingWarningBox");
},
init: function ()
{
// This is used by selectByTimespan() to determine if the window has loaded.
this._inited = true;
this.checkPrefs();
var s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
for (let i = 0; i < this.sanitizePreferences.childNodes.length; ++i) {
var preference = this.sanitizePreferences.childNodes[i];
var name = s.getNameFromPreference(preference.name);
if (!s.canClearItem(name))
preference.disabled = true;
}
document.documentElement.getButton("accept").label =
this.bundleBrowser.getString("sanitizeButtonOK");
if (this.selectedTimespan === Sanitizer.TIMESPAN_EVERYTHING) {
this.ensureWarningIsInited();
this.warningBox.hidden = false;
}
else
this.warningBox.hidden = true;
},
selectByTimespan: function ()
{
// This method is the onselect handler for the duration dropdown. As a
// result it's called a couple of times before onload calls init().
if (!this._inited)
return;
var warningBox = this.warningBox;
// If clearing everything
if (this.selectedTimespan === Sanitizer.TIMESPAN_EVERYTHING) {
this.ensureWarningIsInited();
if (warningBox.hidden) {
warningBox.hidden = false;
window.resizeBy(0, warningBox.boxObject.height);
}
window.document.title =
this.bundleBrowser.getString("sanitizeDialog2.everything.title");
return;
}
// If clearing a specific time range
if (!warningBox.hidden) {
window.resizeBy(0, -warningBox.boxObject.height);
warningBox.hidden = true;
}
window.document.title =
window.document.documentElement.getAttribute("noneverythingtitle");
},
sanitize: function ()
{
// Update pref values before handing off to the sanitizer (bug 453440)
this.updatePrefs();
var s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
s.range = Sanitizer.getClearRange(this.selectedTimespan);
s.ignoreTimespan = !s.range;
try {
s.sanitize();
} catch (er) {
Components.utils.reportError("Exception during sanitize: " + er);
}
return true;
},
/**
* If the panel that displays a warning when the duration is "Everything" is
* not set up, sets it up. Otherwise does nothing.
*/
ensureWarningIsInited: function ()
{
if (this._warningIsInited)
return;
this._warningIsInited = true;
// Get the number of items in history and the oldest item.
var histServ = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
var query = histServ.getNewQuery();
var opts = histServ.getNewQueryOptions();
opts.sortingMode = opts.SORT_BY_DATE_ASCENDING;
opts.queryType = opts.QUERY_TYPE_HISTORY;
var result = histServ.executeQuery(query, opts);
result.root.containerOpen = true;
var numItems = result.root.childCount;
var oldestTime = numItems > 0 ? result.root.getChild(0).time : null;
result.root.containerOpen = false;
var warningDesc = document.getElementById("sanitizeEverythingWarning");
warningDesc.textContent =
this.bundleBrowser.getString("sanitizeEverythingNoVisitsWarning");
},
checkPrefs : function ()
{
var prefService = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService);
var cpdBranch = prefService.getBranch("privacy.cpd.");
// If we don't have defaults for the privacy.cpd branch,
// clone the privacy.item (clear at shutdown) defaults
if (cpdBranch.prefHasUserValue("history"))
return;
var itemBranch = prefService.getBranch("privacy.item.");
var itemCount = { value: 0 };
var itemArray = itemBranch.getChildList("", itemCount);
itemArray.forEach(function (name) {
cpdBranch.setBoolPref(name, itemBranch.getBoolPref(name));
});
},
/**
* Called when the value of a preference element is synced from the actual
* pref. Enables or disables the OK button appropriately.
*/
onReadGeneric: function ()
{
// We don't update the separate history and downloads prefs until
// dialogaccept. So we need to handle the checked state of the combined
// history-downloads checkbox specially.
var combinedCb = document.getElementById("history-downloads-checkbox");
var found = combinedCb.checked;
// Find any other pref that's checked and enabled.
var i = 0;
while (!found && i < this.sanitizePreferences.childNodes.length) {
var preference = this.sanitizePreferences.childNodes[i];
// We took into account history and downloads above; don't do it again.
found = !!preference.value &&
!preference.disabled &&
preference.id !== "privacy.cpd.history" &&
preference.id !== "privacy.cpd.downloads";
i++;
}
try {
document.documentElement.getButton("accept").disabled = !found;
}
catch (e) { }
return undefined;
},
/**
* Called when the values of the history and downloads preference elements are
* synced from the actual prefs. Sets the state of the combined history-
* downloads checkbox appropriately.
*/
onReadHistoryOrDownloads: function ()
{
// Call the common function that will update the accept button
this.onReadGeneric();
var historyPref = document.getElementById("privacy.cpd.history");
var downloadsPref = document.getElementById("privacy.cpd.downloads");
var combinedCb = document.getElementById("history-downloads-checkbox");
combinedCb.disabled = historyPref.disabled && downloadsPref.disabled;
combinedCb.checked = historyPref.value || downloadsPref.value;
},
/**
* Sanitizer.prototype.sanitize() requires the prefs to be up-to-date.
* Because the type of this prefwindow is "child" -- and that's needed because
* without it the dialog has no OK and Cancel buttons -- the prefs are not
* updated on dialogaccept on platforms that don't support instant-apply
* (i.e., Windows). We must therefore manually set the prefs from their
* corresponding preference elements.
*/
updatePrefs : function ()
{
var tsPref = document.getElementById("privacy.sanitize.timeSpan");
Sanitizer.prefs.setIntPref("timeSpan", this.selectedTimespan);
// First set the values of the separate history and downloads pref
// elements based on the combined history-downloads checkbox.
var combinedCbChecked =
document.getElementById("history-downloads-checkbox").checked;
var historyPref = document.getElementById("privacy.cpd.history");
historyPref.value = !historyPref.disabled && combinedCbChecked;
var downloadsPref = document.getElementById("privacy.cpd.downloads");
downloadsPref.value = !downloadsPref.disabled && combinedCbChecked;
// Now manually set the prefs from their corresponding preference
// elements.
var prefs = this.sanitizePreferences.rootBranch;
for (let i = 0; i < this.sanitizePreferences.childNodes.length; ++i) {
var p = this.sanitizePreferences.childNodes[i];
prefs.setBoolPref(p.name, p.value);
}
},
/**
* Called by the item list expander button to toggle the list's visibility.
*/
toggleItemList: function ()
{
var itemList = document.getElementById("itemList");
var expanderButton = document.getElementById("detailsExpander");
// Showing item list
if (itemList.collapsed) {
expanderButton.className = "expander-up";
itemList.collapsed = false;
window.resizeBy(0, itemList.boxObject.height);
}
// Hiding item list
else {
expanderButton.className = "expander-down";
window.resizeBy(0, -itemList.boxObject.height);
itemList.collapsed = true;
}
}
#ifdef CRH_DIALOG_TREE_VIEW
// A duration value; used in the same context as Sanitizer.TIMESPAN_HOUR,
// Sanitizer.TIMESPAN_2HOURS, et al. This should match the value attribute
// of the sanitizeDurationCustom menuitem.
get TIMESPAN_CUSTOM()
{
return -1;
},
get placesTree()
{
if (!this._placesTree)
this._placesTree = document.getElementById("placesTree");
return this._placesTree;
},
init: function ()
{
// This is used by selectByTimespan() to determine if the window has loaded.
this._inited = true;
this.checkPrefs();
var s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
for (let i = 0; i < this.sanitizePreferences.childNodes.length; ++i) {
var preference = this.sanitizePreferences.childNodes[i];
var name = s.getNameFromPreference(preference.name);
if (!s.canClearItem(name))
preference.disabled = true;
}
document.documentElement.getButton("accept").label =
this.bundleBrowser.getString("sanitizeButtonOK");
this.selectByTimespan();
},
/**
* Sets up the hashes this.durationValsToRows, which maps duration values
* to rows in the tree, this.durationRowsToVals, which maps rows in
* the tree to duration values, and this.durationStartTimes, which maps
* duration values to their corresponding start times.
*/
initDurationDropdown: function ()
{
// First, calculate the start times for each duration.
this.durationStartTimes = {};
var durVals = [];
var durPopup = document.getElementById("sanitizeDurationPopup");
var durMenuitems = durPopup.childNodes;
for (let i = 0; i < durMenuitems.length; i++) {
let durMenuitem = durMenuitems[i];
let durVal = parseInt(durMenuitem.value);
if (durMenuitem.localName === "menuitem" &&
durVal !== Sanitizer.TIMESPAN_EVERYTHING &&
durVal !== this.TIMESPAN_CUSTOM) {
durVals.push(durVal);
let durTimes = Sanitizer.getClearRange(durVal);
this.durationStartTimes[durVal] = durTimes[0];
}
}
// Sort the duration values ascending. Because one tree index can map to
// more than one duration, this ensures that this.durationRowsToVals maps
// a row index to the largest duration possible in the code below.
durVals.sort();
// Now calculate the rows in the tree of the durations' start times. For
// each duration, we are looking for the node in the tree whose time is the
// smallest time greater than or equal to the duration's start time.
this.durationRowsToVals = {};
this.durationValsToRows = {};
var view = this.placesTree.view;
// For all rows in the tree except the grippy row...
for (let i = 0; i < view.rowCount - 1; i++) {
let unfoundDurVals = [];
let nodeTime = view.QueryInterface(Ci.nsINavHistoryResultTreeViewer).
nodeForTreeIndex(i).time;
// For all durations whose rows have not yet been found in the tree, see
// if index i is their index. An index may map to more than one duration,
// in which case the final duration (the largest) wins.
for (let j = 0; j < durVals.length; j++) {
let durVal = durVals[j];
let durStartTime = this.durationStartTimes[durVal];
if (nodeTime < durStartTime) {
this.durationValsToRows[durVal] = i - 1;
this.durationRowsToVals[i - 1] = durVal;
}
else
unfoundDurVals.push(durVal);
}
durVals = unfoundDurVals;
}
// If any durations were not found above, then every node in the tree has a
// time greater than or equal to the duration. In other words, those
// durations include the entire tree (except the grippy row).
for (let i = 0; i < durVals.length; i++) {
let durVal = durVals[i];
this.durationValsToRows[durVal] = view.rowCount - 2;
this.durationRowsToVals[view.rowCount - 2] = durVal;
}
},
/**
* If the Places tree is not set up, sets it up. Otherwise does nothing.
*/
ensurePlacesTreeIsInited: function ()
{
if (this._placesTreeIsInited)
return;
this._placesTreeIsInited = true;
// Either "Last Four Hours" or "Today" will have the most history. If
// it's been more than 4 hours since today began, "Today" will. Otherwise
// "Last Four Hours" will.
var times = Sanitizer.getClearRange(Sanitizer.TIMESPAN_TODAY);
// If it's been less than 4 hours since today began, use the past 4 hours.
if (times[1] - times[0] < 14400000000) { // 4*60*60*1000000
times = Sanitizer.getClearRange(Sanitizer.TIMESPAN_4HOURS);
}
var histServ = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
var query = histServ.getNewQuery();
query.beginTimeReference = query.TIME_RELATIVE_EPOCH;
query.beginTime = times[0];
query.endTimeReference = query.TIME_RELATIVE_EPOCH;
query.endTime = times[1];
var opts = histServ.getNewQueryOptions();
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
opts.queryType = opts.QUERY_TYPE_HISTORY;
var result = histServ.executeQuery(query, opts);
var view = gContiguousSelectionTreeHelper.setTree(this.placesTree,
new PlacesTreeView());
result.viewer = view;
this.initDurationDropdown();
},
/**
* Called on select of the duration dropdown and when grippyMoved() sets a
* duration based on the location of the grippy row. Selects all the nodes in
* the tree that are contained in the selected duration. If clearing
* everything, the warning panel is shown instead.
*/
selectByTimespan: function ()
{
// This method is the onselect handler for the duration dropdown. As a
// result it's called a couple of times before onload calls init().
if (!this._inited)
return;
var durDeck = document.getElementById("durationDeck");
var durList = document.getElementById("sanitizeDurationChoice");
var durVal = parseInt(durList.value);
var durCustom = document.getElementById("sanitizeDurationCustom");
// If grippy row is not at a duration boundary, show the custom menuitem;
// otherwise, hide it. Since the user cannot specify a custom duration by
// using the dropdown, this conditional is true only when this method is
// called onselect from grippyMoved(), so no selection need be made.
if (durVal === this.TIMESPAN_CUSTOM) {
durCustom.hidden = false;
return;
}
durCustom.hidden = true;
// If clearing everything, show the warning and change the dialog's title.
if (durVal === Sanitizer.TIMESPAN_EVERYTHING) {
this.ensureWarningIsInited();
durDeck.selectedIndex = 1;
window.document.title =
this.bundleBrowser.getString("sanitizeDialog2.everything.title");
document.documentElement.getButton("accept").disabled = false;
return;
}
// Otherwise -- if clearing a specific time range -- select that time range
// in the tree.
this.ensurePlacesTreeIsInited();
durDeck.selectedIndex = 0;
window.document.title =
window.document.documentElement.getAttribute("noneverythingtitle");
var durRow = this.durationValsToRows[durVal];
gContiguousSelectionTreeHelper.rangedSelect(durRow);
gContiguousSelectionTreeHelper.scrollToGrippy();
// If duration is empty (there are no selected rows), disable the dialog's
// OK button.
document.documentElement.getButton("accept").disabled = durRow < 0;
},
sanitize: function ()
{
// Update pref values before handing off to the sanitizer (bug 453440)
this.updatePrefs();
var s = new Sanitizer();
s.prefDomain = "privacy.cpd.";
var durList = document.getElementById("sanitizeDurationChoice");
var durValue = parseInt(durList.value);
s.ignoreTimespan = durValue === Sanitizer.TIMESPAN_EVERYTHING;
// Set the sanitizer's time range if we're not clearing everything.
if (!s.ignoreTimespan) {
// If user selected a custom timespan, use that.
if (durValue === this.TIMESPAN_CUSTOM) {
var view = this.placesTree.view;
var now = Date.now() * 1000;
// We disable the dialog's OK button if there's no selection, but we'll
// handle that case just in... case.
if (view.selection.getRangeCount() === 0)
s.range = [now, now];
else {
var startIndexRef = {};
// Tree sorted by visit date DEscending, so start time time comes last.
view.selection.getRangeAt(0, {}, startIndexRef);
view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
var startNode = view.nodeForTreeIndex(startIndexRef.value);
s.range = [startNode.time, now];
}
}
// Otherwise use the predetermined range.
else
s.range = [this.durationStartTimes[durValue], Date.now() * 1000];
}
try {
s.sanitize();
} catch (er) {
Components.utils.reportError("Exception during sanitize: " + er);
}
return true;
},
/**
* In order to mark the custom Places tree view and its nsINavHistoryResult
* for garbage collection, we need to break the reference cycle between the
* two.
*/
unload: function ()
{
var view = this.placesTree.view;
view.QueryInterface(Ci.nsINavHistoryResultViewer).result.viewer = null;
this.placesTree.view = null;
},
/**
* Called when the user moves the grippy by dragging it, clicking in the tree,
* or on keypress. Updates the duration dropdown so that it displays the
* appropriate specific or custom duration.
*
* @param aEventName
* The name of the event whose handler called this method, e.g.,
* "ondragstart", "onkeypress", etc.
* @param aEvent
* The event captured in the event handler.
*/
grippyMoved: function (aEventName, aEvent)
{
gContiguousSelectionTreeHelper[aEventName](aEvent);
var lastSelRow = gContiguousSelectionTreeHelper.getGrippyRow() - 1;
var durList = document.getElementById("sanitizeDurationChoice");
var durValue = parseInt(durList.value);
// Multiple durations can map to the same row. Don't update the dropdown
// if the current duration is valid for lastSelRow.
if ((durValue !== this.TIMESPAN_CUSTOM ||
lastSelRow in this.durationRowsToVals) &&
(durValue === this.TIMESPAN_CUSTOM ||
this.durationValsToRows[durValue] !== lastSelRow)) {
// Setting durList.value causes its onselect handler to fire, which calls
// selectByTimespan().
if (lastSelRow in this.durationRowsToVals)
durList.value = this.durationRowsToVals[lastSelRow];
else
durList.value = this.TIMESPAN_CUSTOM;
}
// If there are no selected rows, disable the dialog's OK button.
document.documentElement.getButton("accept").disabled = lastSelRow < 0;
}
#endif
};
#ifdef CRH_DIALOG_TREE_VIEW
/**
* A helper for handling contiguous selection in the tree.
*/
var gContiguousSelectionTreeHelper = {
/**
* Gets the tree associated with this helper.
*/
get tree()
{
return this._tree;
},
/**
* Sets the tree that this module handles. The tree is assigned a new view
* that is equipped to handle contiguous selection. You can pass in an
* object that will be used as the prototype of the new view. Otherwise
* the tree's current view is used as the prototype.
*
* @param aTreeElement
* The tree element
* @param aProtoTreeView
* If defined, this will be used as the prototype of the tree's new
* view
* @return The new view
*/
setTree: function CSTH_setTree(aTreeElement, aProtoTreeView)
{
this._tree = aTreeElement;
var newView = this._makeTreeView(aProtoTreeView || aTreeElement.view);
aTreeElement.view = newView;
return newView;
},
/**
* The index of the row that the grippy occupies. Note that the index of the
* last selected row is getGrippyRow() - 1. If getGrippyRow() is 0, then
* no selection exists.
*
* @return The row index of the grippy
*/
getGrippyRow: function CSTH_getGrippyRow()
{
var sel = this.tree.view.selection;
var rangeCount = sel.getRangeCount();
if (rangeCount === 0)
return 0;
if (rangeCount !== 1) {
throw "contiguous selection tree helper: getGrippyRow called with " +
"multiple selection ranges";
}
var max = {};
sel.getRangeAt(0, {}, max);
return max.value + 1;
},
/**
* Helper function for the dragover event. Your dragover listener should
* call this. It updates the selection in the tree under the mouse.
*
* @param aEvent
* The observed dragover event
*/
ondragover: function CSTH_ondragover(aEvent)
{
// Without this when dragging on Windows the mouse cursor is a "no" sign.
// This makes it a drop symbol.
var ds = Cc["@mozilla.org/widget/dragservice;1"].
getService(Ci.nsIDragService).
getCurrentSession();
ds.canDrop = true;
ds.dragAction = 0;
var tbo = this.tree.treeBoxObject;
aEvent.QueryInterface(Ci.nsIDOMMouseEvent);
var hoverRow = tbo.getRowAt(aEvent.clientX, aEvent.clientY);
if (hoverRow < 0)
return;
this.rangedSelect(hoverRow - 1);
},
/**
* Helper function for the dragstart event. Your dragstart listener should
* call this. It starts a drag session.
*
* @param aEvent
* The observed dragstart event
*/
ondragstart: function CSTH_ondragstart(aEvent)
{
var tbo = this.tree.treeBoxObject;
var clickedRow = tbo.getRowAt(aEvent.clientX, aEvent.clientY);
if (clickedRow !== this.getGrippyRow())
return;
// This part is a hack. What we really want is a grab and slide, not
// drag and drop. Start a move drag session with dummy data and a
// dummy region. Set the region's coordinates to (Infinity, Infinity)
// so it's drawn offscreen and its size to (1, 1).
var arr = Cc["@mozilla.org/supports-array;1"].
createInstance(Ci.nsISupportsArray);
var trans = Cc["@mozilla.org/widget/transferable;1"].
createInstance(Ci.nsITransferable);
trans.setTransferData('dummy-flavor', null, 0);
arr.AppendElement(trans);
var reg = Cc["@mozilla.org/gfx/region;1"].
createInstance(Ci.nsIScriptableRegion);
reg.setToRect(Infinity, Infinity, 1, 1);
var ds = Cc["@mozilla.org/widget/dragservice;1"].
getService(Ci.nsIDragService);
ds.invokeDragSession(aEvent.target, arr, reg, ds.DRAGDROP_ACTION_MOVE);
},
/**
* Helper function for the keypress event. Your keypress listener should
* call this. Users can use Up, Down, Page Up/Down, Home, and End to move
* the bottom of the selection window.
*
* @param aEvent
* The observed keypress event
*/
onkeypress: function CSTH_onkeypress(aEvent)
{
var grippyRow = this.getGrippyRow();
var tbo = this.tree.treeBoxObject;
var rangeEnd;
switch (aEvent.keyCode) {
case aEvent.DOM_VK_HOME:
rangeEnd = 0;
break;
case aEvent.DOM_VK_PAGE_UP:
rangeEnd = grippyRow - tbo.getPageLength();
break;
case aEvent.DOM_VK_UP:
rangeEnd = grippyRow - 2;
break;
case aEvent.DOM_VK_DOWN:
rangeEnd = grippyRow;
break;
case aEvent.DOM_VK_PAGE_DOWN:
rangeEnd = grippyRow + tbo.getPageLength();
break;
case aEvent.DOM_VK_END:
rangeEnd = this.tree.view.rowCount - 2;
break;
default:
return;
break;
}
aEvent.stopPropagation();
// First, clip rangeEnd. this.rangedSelect() doesn't clip the range if we
// select past the ends of the tree.
if (rangeEnd < 0)
rangeEnd = -1;
else if (this.tree.view.rowCount - 2 < rangeEnd)
rangeEnd = this.tree.view.rowCount - 2;
// Next, (de)select.
this.rangedSelect(rangeEnd);
// Finally, scroll the tree. We always want one row above and below the
// grippy row to be visible if possible.
if (rangeEnd < grippyRow) // moved up
tbo.ensureRowIsVisible(rangeEnd < 0 ? 0 : rangeEnd);
else { // moved down
if (rangeEnd + 2 < this.tree.view.rowCount)
tbo.ensureRowIsVisible(rangeEnd + 2);
else if (rangeEnd + 1 < this.tree.view.rowCount)
tbo.ensureRowIsVisible(rangeEnd + 1);
}
},
/**
* Helper function for the mousedown event. Your mousedown listener should
* call this. Users can click on individual rows to make the selection
* jump to them immediately.
*
* @param aEvent
* The observed mousedown event
*/
onmousedown: function CSTH_onmousedown(aEvent)
{
var tbo = this.tree.treeBoxObject;
var clickedRow = tbo.getRowAt(aEvent.clientX, aEvent.clientY);
if (clickedRow < 0 || clickedRow >= this.tree.view.rowCount)
return;
if (clickedRow < this.getGrippyRow())
this.rangedSelect(clickedRow);
else if (clickedRow > this.getGrippyRow())
this.rangedSelect(clickedRow - 1);
},
/**
* Selects range [0, aEndRow] in the tree. The grippy row will then be at
* index aEndRow + 1. aEndRow may be -1, in which case the selection is
* cleared and the grippy row will be at index 0.
*
* @param aEndRow
* The range [0, aEndRow] will be selected.
*/
rangedSelect: function CSTH_rangedSelect(aEndRow)
{
var tbo = this.tree.treeBoxObject;
if (aEndRow < 0)
this.tree.view.selection.clearSelection();
else
this.tree.view.selection.rangedSelect(0, aEndRow, false);
tbo.invalidateRange(tbo.getFirstVisibleRow(), tbo.getLastVisibleRow());
},
/**
* Scrolls the tree so that the grippy row is in the center of the view.
*/
scrollToGrippy: function CSTH_scrollToGrippy()
{
var rowCount = this.tree.view.rowCount;
var tbo = this.tree.treeBoxObject;
var pageLen = tbo.getPageLength() ||
parseInt(this.tree.getAttribute("rows")) ||
10;
// All rows fit on a single page.
if (rowCount <= pageLen)
return;
var scrollToRow = this.getGrippyRow() - Math.ceil(pageLen / 2.0);
// Grippy row is in first half of first page.
if (scrollToRow < 0)
scrollToRow = 0;
// Grippy row is in last half of last page.
else if (rowCount < scrollToRow + pageLen)
scrollToRow = rowCount - pageLen;
tbo.scrollToRow(scrollToRow);
},
/**
* Creates a new tree view suitable for contiguous selection. If
* aProtoTreeView is specified, it's used as the new view's prototype.
* Otherwise the tree's current view is used as the prototype.
*
* @param aProtoTreeView
* Used as the new view's prototype if specified
*/
_makeTreeView: function CSTH__makeTreeView(aProtoTreeView)
{
var atomServ = Cc["@mozilla.org/atom-service;1"].
getService(Ci.nsIAtomService);
var view = aProtoTreeView;
var that = this;
//XXXadw: When Alex gets the grippy icon done, this may or may not change,
// depending on how we style it.
view.isSeparator = function CSTH_View_isSeparator(aRow)
{
return aRow === that.getGrippyRow();
};
// rowCount includes the grippy row.
view.__defineGetter__("_rowCount", view.__lookupGetter__("rowCount"));
view.__defineGetter__("rowCount",
function CSTH_View_rowCount()
{
return this._rowCount + 1;
});
// This has to do with visual feedback in the view itself, e.g., drawing
// a small line underneath the dropzone. Not what we want.
view.canDrop = function CSTH_View_canDrop() { return false; };
// No clicking headers to sort the tree or sort feedback on columns.
view.cycleHeader = function CSTH_View_cycleHeader() {};
view.sortingChanged = function CSTH_View_sortingChanged() {};
// Override a bunch of methods to account for the grippy row.
view._getCellProperties = view.getCellProperties;
view.getCellProperties =
function CSTH_View_getCellProperties(aRow, aCol, aProps)
{
var grippyRow = that.getGrippyRow();
if (aRow === grippyRow)
aProps.AppendElement(atomServ.getAtom("grippyRow"));
else if (aRow < grippyRow)
this._getCellProperties(aRow, aCol, aProps);
else
this._getCellProperties(aRow - 1, aCol, aProps);
};
view._getRowProperties = view.getRowProperties;
view.getRowProperties =
function CSTH_View_getRowProperties(aRow, aProps)
{
var grippyRow = that.getGrippyRow();
if (aRow === grippyRow)
aProps.AppendElement(atomServ.getAtom("grippyRow"));
else if (aRow < grippyRow)
this._getRowProperties(aRow, aProps);
else
this._getRowProperties(aRow - 1, aProps);
};
view._getCellText = view.getCellText;
view.getCellText =
function CSTH_View_getCellText(aRow, aCol)
{
var grippyRow = that.getGrippyRow();
if (aRow === grippyRow)
return "";
aRow = aRow < grippyRow ? aRow : aRow - 1;
return this._getCellText(aRow, aCol);
};
view._getImageSrc = view.getImageSrc;
view.getImageSrc =
function CSTH_View_getImageSrc(aRow, aCol)
{
var grippyRow = that.getGrippyRow();
if (aRow === grippyRow)
return "";
aRow = aRow < grippyRow ? aRow : aRow - 1;
return this._getImageSrc(aRow, aCol);
};
view.isContainer = function CSTH_View_isContainer(aRow) { return false; };
view.getParentIndex = function CSTH_View_getParentIndex(aRow) { return -1; };
view.getLevel = function CSTH_View_getLevel(aRow) { return 0; };
view.hasNextSibling = function CSTH_View_hasNextSibling(aRow, aAfterIndex)
{
return aRow < this.rowCount - 1;
};
return view;
}
};
#endif

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

@ -809,6 +809,9 @@
if (this.mCurrentBrowser == newBrowser && !aForceUpdate)
return;
if (this.mCurrentTab != this.selectedTab)
this.mCurrentTab.owner = null;
if (this.mCurrentBrowser) {
// Only save the focused element if it is in our content window
// or in an ancestor window.
@ -1302,21 +1305,9 @@
this._browsers = null;
// If this new tab is owned by another, assert that relationship
if (aOwner !== undefined && aOwner !== null) {
if (aOwner)
t.owner = aOwner;
var self = this;
function attrChanged(event) {
if (event.attrName == "selectedIndex" &&
event.prevValue != event.newValue)
self.resetOwner(parseInt(event.prevValue));
}
if (!this.mTabChangedListenerAdded) {
this.mTabBox.addEventListener("DOMAttrModified", attrChanged, false);
this.mTabChangedListenerAdded = true;
}
}
var b = document.createElementNS(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"browser");
@ -1488,20 +1479,6 @@
</body>
</method>
<method name="resetOwner">
<parameter name="oldIndex"/>
<body>
<![CDATA[
// Reset the owner property, since we're leaving the modally opened
// tab for another.
if (oldIndex < this.mTabContainer.childNodes.length) {
var tab = this.mTabContainer.childNodes[oldIndex];
tab.owner = null;
}
]]>
</body>
</method>
<field name="_removingTabs">
[]
</field>
@ -1510,7 +1487,7 @@
<parameter name="aTab"/>
<body>
<![CDATA[
this._endRemoveTab(this._beginRemoveTab(aTab, true));
this._endRemoveTab(this._beginRemoveTab(aTab, true, null, true));
]]>
</body>
</method>
@ -1526,6 +1503,7 @@
<parameter name="aTab"/>
<parameter name="aFireBeforeUnload"/>
<parameter name="aCloseWindowWithLastTab"/>
<parameter name="aCloseWindowFastpath"/>
<body>
<![CDATA[
if (this._removingTabs.indexOf(aTab) > -1 || this._windowIsClosing)
@ -1541,14 +1519,22 @@
var closeWindow = false;
var l = this.mTabs.length - this._removingTabs.length;
var newTab;
var newTab = false;
if (l == 1) {
closeWindow = aCloseWindowWithLastTab != null ?
aCloseWindowWithLastTab :
this.mPrefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
newTab = this.addTab("about:blank");
newTab.collapsed = true;
// Closing the tab and replacing it with a blank one is notably slower
// than closing the window right away. If the caller opts in, take
// the fast path.
if (closeWindow &&
aCloseWindowFastpath &&
this._removingTabs.length == 0 &&
(this._windowIsClosing = window.closeWindow(true)))
return null;
newTab = true;
l++;
}
if (l == 2) {
@ -1601,6 +1587,8 @@
// update the UI early for responsiveness
aTab.collapsed = true;
if (aNewTab)
this.addTab("about:blank");
this.tabContainer._fillTrailingGap();
this._blurTab(aTab);
@ -1618,11 +1606,8 @@
};
setTimeout(_delayedUpdate, 0, this.tabContainer);
if (aNewTab) {
aNewTab.collapsed = false;
if (gURLBar)
gURLBar.focus();
}
if (aNewTab && gURLBar)
gURLBar.focus();
}
// We're going to remove the tab and the browser now.
@ -1724,6 +1709,7 @@
<parameter name="aOtherTab"/>
<body>
<![CDATA[
// That's gBrowser for the other window, not the tab's browser!
var remoteBrowser =
aOtherTab.ownerDocument.defaultView.getBrowser();
@ -1741,8 +1727,19 @@
filter.removeProgressListener(tabListener);
var tabListenerBlank = tabListener.mBlank;
// Workarounds for bug 458697
// Icon might have been set on DOMLinkAdded, don't override that.
if (!ourBrowser.mIconURL && aOtherTab.linkedBrowser.mIconURL)
this.setIcon(aOurTab, aOtherTab.linkedBrowser.mIconURL);
var isBusy = aOtherTab.hasAttribute("busy");
if (isBusy) {
aOurTab.setAttribute("busy", "true");
if (aOurTab == this.selectedTab)
this.mIsBusy = true;
}
// Swap the docshells
ourBrowser.swapDocShells(remoteBrowser.getBrowserForTab(aOtherTab));
ourBrowser.swapDocShells(aOtherTab.linkedBrowser);
// Finish tearing down the tab that's going away.
remoteBrowser._endRemoveTab(endRemoveArgs);
@ -1757,7 +1754,10 @@
ourBrowser.webProgress.addProgressListener(filter,
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
this.setTabTitle(aOurTab);
if (isBusy)
this.setTabTitleLoading(aOurTab);
else
this.setTabTitle(aOurTab);
this.updateIcon(aOurTab);
// If the tab was already selected (this happpens in the scenario
@ -2251,25 +2251,20 @@
<body>
<![CDATA[
// Note: while this case is correctly handled here, this event
// isn't dispatched when the tab is moved within the tabstript,
// isn't dispatched when the tab is moved within the tabstrip,
// see bug 460801.
// * mozUserCancelled = the user pressed ESC to cancel the drag
// * Within our browser window, the detach-target is the content
// area. That case is handled by contentAreaDNDObserver.
// * The dragLeftWindow solution is suboptimal, a better solution
// is on bug 466379.
var dt = aEvent.dataTransfer;
if (dt.mozUserCancelled || !this._dragLeftWindow)
if (dt.mozUserCancelled || dt.dropEffect != "none")
return;
// The dropEffect == "none" scenarios:
// 1. No-op (no postion change) - "catched" by !dragLeftWindow
// 2. On the browser chrome (on element which don't handle
// text/plain or the tab type) - ditto.
// 2. Drop outside the browser window - the case that is handled
// here.
if (dt.dropEffect == "none") {
// Deatch happens only if the tab was dropped below the tabbar.
// That is applied even if it was dropped outside the browser
// window.
var bo = this.mTabContainer.mTabstrip.boxObject;
var tabbarEndScreenY = bo.screenY + bo.height;
if (aEvent.screenY > tabbarEndScreenY) {
var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
this.replaceTabWithWindow(draggedTab);
}
@ -2278,28 +2273,6 @@
</body>
</method>
<method name="browserWindowOnDragEnter">
<parameter name="aEvent"/>
<body>
<![CDATA[
this._dragLeftWindow = false;
]]>
</body>
</method>
<method name="browserWindowOnDragLeave">
<parameter name="aEvent"/>
<body>
<![CDATA[
// If the clientX or clientY values are positive, the mouse is
// still dragged within our window. How would that happen? Either
// by the dragleave event that is dispatched right before the drop,
// or by a bubbled dragleave event
this._dragLeftWindow = aEvent.clientX < 0 || aEvent.clientY < 0;
]]>
</body>
</method>
<!-- Moves a tab to a new browser window, unless it's already the only tab
in the current window, in which case this will do nothing. -->
<method name="replaceTabWithWindow">
@ -2312,11 +2285,11 @@
// tell a new window to take the "dropped" tab
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
ww.openWindow(window,
getBrowserURL(),
null,
"chrome,dialog=no,all",
aTab);
return ww.openWindow(window,
getBrowserURL(),
null,
"chrome,dialog=no,all",
aTab);
]]>
</body>
</method>
@ -3272,8 +3245,8 @@
return;
}
this.mTabstrip._smoothScrollByPixels(this.mTabstrip._isLTRScrollbox ?
selStart - tsboStart : selEnd - tsboEnd);
this.mTabstrip._smoothScrollByPixels(this.mTabstrip._isRTLScrollbox ?
selEnd - tsboEnd : selStart - tsboStart);
}
// start the flash timer

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

@ -63,10 +63,16 @@ _TEST_FILES = test_feed_discovery.html \
# browser_bug321000.js is bug 474081
# browser_bug423833.js is bug 428712
# browser_sanitize-download-history.js is bug 432425
#
# browser_sanitizeDialog_treeView.js is disabled until the tree view is added
# back to the clear recent history dialog (santize.xul), if it ever is (bug
# 480169)
_BROWSER_FILES = browser_sanitize-timespans.js \
browser_bug405137.js \
browser_bug409481.js \
browser_bug413915.js \
browser_bug419612.js \
browser_bug420160.js \
browser_bug424101.js \
browser_bug427559.js \
@ -74,6 +80,8 @@ _BROWSER_FILES = browser_sanitize-timespans.js \
browser_bug441778.js \
browser_bug455852.js \
browser_bug462673.js \
browser_bug481560.js \
browser_bug477014.js \
browser_discovery.js \
discovery.html \
moz.png \
@ -104,6 +112,9 @@ _BROWSER_FILES = browser_sanitize-timespans.js \
browser_bug479408.js \
browser_bug479408_sample.html \
browser_scope.js \
browser_overflowScroll.js \
browser_sanitizeDialog.js \
browser_tabs_owner.js \
$(NULL)
ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))

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

@ -0,0 +1,33 @@
function test() {
waitForExplicitFinish();
let testPage = "http://example.org/browser/browser/base/content/test/dummy_page.html";
let prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
let tab1 = gBrowser.selectedTab = gBrowser.addTab();
tab1.linkedBrowser.addEventListener("load", (function(event) {
event.currentTarget.removeEventListener("load", arguments.callee, true);
let tab2 = gBrowser.addTab();
tab2.linkedBrowser.addEventListener("load", (function(event) {
event.currentTarget.removeEventListener("load", arguments.callee, true);
let oldPref = prefService.getBoolPref("browser.zoom.updateBackgroundTabs");
FullZoom.enlarge();
let tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser);
gBrowser.selectedTab = tab2;
let tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser);
is(tab2Zoom, tab1Zoom, "Zoom should affect background tabs");
prefService.setBoolPref("browser.zoom.updateBackgroundTabs", false);
FullZoom.reset();
gBrowser.selectedTab = tab1;
tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser);
tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser);
isnot(tab1Zoom, tab2Zoom, "Zoom should not affect background tabs");
prefService.setBoolPref("browser.zoom.updateBackgroundTabs", oldPref);
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
finish();
}), true);
tab2.linkedBrowser.loadURI(testPage);
}), true);
content.location = testPage;
}

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

@ -11,6 +11,5 @@ function test() {
is(gBrowser.mTabs.length, 1, "a new tab has been opened");
is(document.activeElement, gURLBar.inputField, "location bar is focused for the new tab");
if (gPrefService.prefHasUserValue("browser.tabs.closeWindowWithLastTab"))
gPrefService.clearUserPref("browser.tabs.closeWindowWithLastTab");
gPrefService.clearUserPref("browser.tabs.closeWindowWithLastTab");
}

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

@ -0,0 +1,88 @@
/* ***** 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 bug 477014 test.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Asaf Romano <mano@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// That's a gecko!
const iconURLSpec = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
var testPage="data:text/plain,test bug 477014";
function test() {
waitForExplicitFinish();
var newWindow;
var tabToDetach;
function onPageShow(event) {
// we get here if the test is executed before the pageshow
// event for the window's first tab
if (!tabToDetach ||
tabToDetach.linkedBrowser.contentDocument != event.target) {
return;
}
if (!newWindow) {
var pageShowFunc = arguments.callee;
gBrowser.removeEventListener("pageshow", pageShowFunc, false);
// prepare the tab (set icon and busy state)
// we have to set these only after onState* notification, otherwise
// they're overriden
setTimeout(function() {
gBrowser.setIcon(tabToDetach, iconURLSpec);
tabToDetach.setAttribute("busy", "true");
// detach and set the listener on the new window
newWindow = gBrowser.replaceTabWithWindow(tabToDetach);
// wait for gBrowser to come along
function onLoad(event) {
newWindow.gBrowser
.addEventListener("pageshow", pageShowFunc, false);
newWindow.removeEventListener("load", arguments.callee, false);
}
newWindow.addEventListener("load", onLoad, false);
}, 0);
return;
}
is(newWindow.gBrowser.selectedTab.hasAttribute("busy"), true);
is(newWindow.gBrowser.selectedTab.linkedBrowser.mIconURL,iconURLSpec);
newWindow.close();
finish();
}
gBrowser.addEventListener("pageshow", onPageShow, false);
tabToDetach = gBrowser.addTab(testPage);
}

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

@ -0,0 +1,19 @@
function test() {
waitForExplicitFinish();
var win = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
win.addEventListener("load", function () {
win.removeEventListener("load", arguments.callee, false);
win.gBrowser.selectedTab.addEventListener("TabClose", function () {
ok(false, "shouldn't have gotten the TabClose event for the last tab");
}, false);
EventUtils.synthesizeKey("w", { accelKey: true }, win);
ok(win.closed, "accel+w closed the window immediately");
finish();
}, false);
}

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

@ -153,10 +153,14 @@ function test_TestEventListeners()
e("MozMagnifyGesture", 0, 30.0, 0);
// rotate gesture events
e("MozRotateGestureStart", SimpleGestureEvent.DIRECTION_RIGHT, 33.0, 0);
e("MozRotateGestureUpdate", SimpleGestureEvent.DIRECTION_LEFT, -13.0, 0);
e("MozRotateGestureUpdate", SimpleGestureEvent.DIRECTION_RIGHT, 13.0, 0);
e("MozRotateGesture", SimpleGestureEvent.DIRECTION_RIGHT, 33.0, 0);
e("MozRotateGestureStart", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0);
e("MozRotateGestureUpdate", SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE, -13.0, 0);
e("MozRotateGestureUpdate", SimpleGestureEvent.ROTATION_CLOCKWISE, 13.0, 0);
e("MozRotateGesture", SimpleGestureEvent.ROTATION_CLOCKWISE, 33.0, 0);
// Tap and presstap gesture events
e("MozTapGesture", 0, 0.0, 0);
e("MozPressTapGesture", 0, 0.0, 0);
// event.shiftKey
let modifier = Components.interfaces.nsIDOMNSEvent.SHIFT_MASK;
@ -249,12 +253,16 @@ function test_EnsureConstantsAreDisjoint()
let left = SimpleGestureEvent.DIRECTION_LEFT;
let right = SimpleGestureEvent.DIRECTION_RIGHT;
let clockwise = SimpleGestureEvent.ROTATION_CLOCKWISE;
let cclockwise = SimpleGestureEvent.ROTATION_COUNTERCLOCKWISE;
ok(up ^ down, "DIRECTION_UP and DIRECTION_DOWN are not bitwise disjoint");
ok(up ^ left, "DIRECTION_UP and DIRECTION_LEFT are not bitwise disjoint");
ok(up ^ right, "DIRECTION_UP and DIRECTION_RIGHT are not bitwise disjoint");
ok(down ^ left, "DIRECTION_DOWN and DIRECTION_LEFT are not bitwise disjoint");
ok(down ^ right, "DIRECTION_DOWN and DIRECTION_RIGHT are not bitwise disjoint");
ok(left ^ right, "DIRECTION_LEFT and DIRECTION_RIGHT are not bitwise disjoint");
ok(clockwise ^ cclockwise, "ROTATION_CLOCKWISE and ROTATION_COUNTERCLOCKWISE are not bitwise disjoint");
}
// Helper for test of latched event processing. Emits the actual

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

@ -0,0 +1,69 @@
var tabContainer = gBrowser.tabContainer;
var tabstrip = tabContainer.mTabstrip;
var scrollbox = tabstrip._scrollbox;
var originalSmoothScroll = tabstrip.smoothScroll;
function rect(ele) ele.getBoundingClientRect();
function width(ele) rect(ele).width;
function left(ele) rect(ele).left;
function right(ele) rect(ele).right;
function isLeft(ele, msg) is(left(ele), left(scrollbox), msg);
function isRight(ele, msg) is(right(ele), right(scrollbox), msg);
function elementFromPoint(x) tabstrip._elementFromPoint(x);
function nextLeftElement() elementFromPoint(left(scrollbox) - 1);
function nextRightElement() elementFromPoint(right(scrollbox) + 1);
function test() {
waitForExplicitFinish();
tabstrip.smoothScroll = false;
var tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth");
var tabCountForOverflow = Math.ceil(width(tabstrip) / tabMinWidth * 3);
while (tabContainer.childNodes.length < tabCountForOverflow)
gBrowser.addTab();
tabstrip.addEventListener("overflow", runOverflowTests, false);
}
function runOverflowTests(aEvent) {
if (aEvent.detail != 1)
return;
tabstrip.removeEventListener("overflow", runOverflowTests, false);
var upButton = tabstrip._scrollButtonUp;
var downButton = tabstrip._scrollButtonDown;
var element;
gBrowser.selectedTab = tabContainer.firstChild;
isLeft(tabContainer.firstChild, "Selecting the first tab scrolls it into view");
element = nextRightElement();
EventUtils.synthesizeMouse(downButton, 0, 0, {});
isRight(element, "Scrolled one tab to the right with a single click");
gBrowser.selectedTab = tabContainer.lastChild;
isRight(tabContainer.lastChild, "Selecting the last tab scrolls it into view");
element = nextLeftElement();
EventUtils.synthesizeMouse(upButton, 0, 0, {});
isLeft(element, "Scrolled one tab to the left with a single click");
element = elementFromPoint(left(scrollbox) - width(scrollbox));
EventUtils.synthesizeMouse(upButton, 0, 0, {clickCount: 2});
isLeft(element, "Scrolled one page of tabs with a double click");
EventUtils.synthesizeMouse(upButton, 0, 0, {clickCount: 3});
isLeft(tabContainer.firstChild, "Scrolled to the start with a triple click");
element = nextRightElement();
EventUtils.synthesizeMouseScroll(scrollbox, 0, 0, {delta: 1});
isRight(element, "Scrolled one tab to the right with the mouse wheel");
while (tabContainer.childNodes.length > 1)
gBrowser.removeTab(tabContainer.lastChild);
tabstrip.smoothScroll = originalSmoothScroll;
finish();
}

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

@ -12,6 +12,7 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.moz
function test() {
var hoursSinceMidnight = new Date().getHours();
var minutesSinceMidnight = new Date().getMinutes();
setupHistory();
setupFormHistory();
@ -35,46 +36,131 @@ function test() {
itemPrefs.setBoolPref("passwords", false);
itemPrefs.setBoolPref("sessions", false);
itemPrefs.setBoolPref("siteSettings", false);
// Clear 10 minutes ago
s.range = [now_uSec - 10*60*1000000, now_uSec];
s.sanitize();
s.range = null;
ok(!bhist.isVisited(uri("http://10minutes.com")), "10minutes.com should now be deleted");
ok(bhist.isVisited(uri("http://1hour.com")), "Pretend visit to 1hour.com should still exist");
ok(bhist.isVisited(uri("http://1hour10minutes.com/")), "Pretend visit to 1hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should still exist");
ok(bhist.isVisited(uri("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(minutesSinceMidnight > 10)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("10minutes"), "10minutes form entry should be deleted");
ok(formhist.nameExists("1hour"), "1hour form entry should still exist");
ok(formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should still exist");
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(minutesSinceMidnight > 10)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555555), "10 minute download should now be deleted");
ok(downloadExists(5555551), "<1 hour download should still be present");
ok(downloadExists(5555556), "1 hour 10 minute download should still be present");
ok(downloadExists(5555550), "Year old download should still be present");
ok(downloadExists(5555552), "<2 hour old download should still be present");
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
ok(downloadExists(5555553), "<4 hour old download should still be present");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
if(minutesSinceMidnight > 10)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 1 hour
Sanitizer.prefs.setIntPref("timeSpan", 1);
s.sanitize();
ok(!bhist.isVisited(uri("http://1hour.com")), "1hour.com should now be deleted");
ok(bhist.isVisited(uri("http://1hour10minutes.com/")), "Pretend visit to 1hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should still exist");
ok(bhist.isVisited(uri("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(hoursSinceMidnight > 1)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("1hour"), "1hour form entry should be deleted");
ok(formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should still exist");
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(hoursSinceMidnight > 1)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555551), "<1 hour download should now be deleted");
ok(downloadExists(5555556), "1 hour 10 minute download should still be present");
ok(downloadExists(5555550), "Year old download should still be present");
ok(downloadExists(5555552), "<2 hour old download should still be present");
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
ok(downloadExists(5555553), "<4 hour old download should still be present");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
if(hoursSinceMidnight > 1)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 1 hour 10 minutes
s.range = [now_uSec - 70*60*1000000, now_uSec];
s.sanitize();
s.range = null;
ok(!bhist.isVisited(uri("http://1hour10minutes.com")), "Pretend visit to 1hour10minutes.com should now be deleted");
ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should still exist");
ok(bhist.isVisited(uri("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(minutesSinceMidnight > 70)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should be deleted");
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(minutesSinceMidnight > 70)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555556), "1 hour 10 minute old download should now be deleted");
ok(downloadExists(5555550), "Year old download should still be present");
ok(downloadExists(5555552), "<2 hour old download should still be present");
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
ok(downloadExists(5555553), "<4 hour old download should still be present");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
if(minutesSinceMidnight > 70)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 2 hours
Sanitizer.prefs.setIntPref("timeSpan", 2);
s.sanitize();
ok(!bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should now be deleted");
ok(bhist.isVisited(uri("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should still exist");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(hoursSinceMidnight > 2)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("2hour"), "2hour form entry should be deleted");
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(hoursSinceMidnight > 2)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
@ -82,29 +168,80 @@ function test() {
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555552), "<2 hour old download should now be deleted");
ok(downloadExists(5555550), "Year old download should still be present");
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
ok(downloadExists(5555553), "<4 hour old download should still be present");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
if(hoursSinceMidnight > 2)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 2 hours 10 minutes
s.range = [now_uSec - 130*60*1000000, now_uSec];
s.sanitize();
s.range = null;
ok(!bhist.isVisited(uri("http://2hour10minutes.com")), "Pretend visit to 2hour10minutes.com should now be deleted");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(minutesSinceMidnight > 130)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should be deleted");
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(minutesSinceMidnight > 130)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555557), "2 hour 10 minute old download should now be deleted");
ok(downloadExists(5555553), "<4 hour old download should still be present");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
ok(downloadExists(5555550), "Year old download should still be present");
if(minutesSinceMidnight > 130)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 4 hours
Sanitizer.prefs.setIntPref("timeSpan", 3);
s.sanitize();
ok(!bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should now be deleted");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should still exist");
if(hoursSinceMidnight > 4)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("4hour"), "4hour form entry should be deleted");
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
if(hoursSinceMidnight > 4)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555553), "<4 hour old download should now be deleted");
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
ok(downloadExists(5555550), "Year old download should still be present");
if(hoursSinceMidnight > 4)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear 4 hours 10 minutes
s.range = [now_uSec - 250*60*1000000, now_uSec];
s.sanitize();
s.range = null;
ok(!bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should now be deleted");
if(minutesSinceMidnight > 250)
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
ok(!formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should be deleted");
if(minutesSinceMidnight > 250)
ok(formhist.nameExists("today"), "today form entry should still exist");
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
ok(!downloadExists(5555558), "4 hour 10 minute download should now be deleted");
ok(downloadExists(5555550), "Year old download should still be present");
if(minutesSinceMidnight > 250)
ok(downloadExists(5555554), "'Today' download should still be present");
// Clear Today
Sanitizer.prefs.setIntPref("timeSpan", 4);
s.sanitize();
@ -131,9 +268,13 @@ function test() {
}
function setupHistory() {
bhist.addPageWithDetails(uri("http://10minutes.com/"), "10 minutes ago", now_uSec - 10*60*1000000);
bhist.addPageWithDetails(uri("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45*60*1000000);
bhist.addPageWithDetails(uri("http://1hour10minutes.com/"), "1 hour 10 minutes ago", now_uSec - 70*60*1000000);
bhist.addPageWithDetails(uri("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90*60*1000000);
bhist.addPageWithDetails(uri("http://2hour10minutes.com/"), "2 hours 10 minutes ago", now_uSec - 130*60*1000000);
bhist.addPageWithDetails(uri("http://4hour.com/"), "Less than 4 hours ago", now_uSec - 180*60*1000000);
bhist.addPageWithDetails(uri("http://4hour10minutes.com/"), "4 hours 10 minutesago", now_uSec - 250*60*1000000);
let today = new Date();
today.setHours(0);
@ -146,9 +287,13 @@ function setupHistory() {
bhist.addPageWithDetails(uri("http://before-today.com/"), "Before Today", lastYear.valueOf() * 1000);
// Confirm everything worked
ok(bhist.isVisited(uri("http://10minutes.com/")), "Pretend visit to 10minutes.com should exist");
ok(bhist.isVisited(uri("http://1hour.com")), "Pretend visit to 1hour.com should exist");
ok(bhist.isVisited(uri("http://1hour10minutes.com/")), "Pretend visit to 1hour10minutes.com should exist");
ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should exist");
ok(bhist.isVisited(uri("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should exist");
ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should exist");
ok(bhist.isVisited(uri("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should exist");
ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should exist");
ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should exist");
}
@ -158,23 +303,39 @@ function setupFormHistory() {
formhist.removeAllEntries();
// Add the entries we'll be testing.
formhist.addEntry("10minutes", "10m");
formhist.addEntry("1hour", "1h");
formhist.addEntry("1hour10minutes", "1h10m");
formhist.addEntry("2hour", "2h");
formhist.addEntry("2hour10minutes", "2h10m");
formhist.addEntry("4hour", "4h");
formhist.addEntry("4hour10minutes", "4h10m");
formhist.addEntry("today", "1d");
formhist.addEntry("b4today", "1y");
// Artifically age the entries to the proper vintage.
let db = formhist.DBConnection;
let timestamp = now_uSec - 45*60*1000000;
let timestamp = now_uSec - 10*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '10minutes'");
timestamp = now_uSec - 45*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '1hour'");
timestamp = now_uSec - 70*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '1hour10minutes'");
timestamp = now_uSec - 90*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '2hour'");
timestamp = now_uSec - 130*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '2hour10minutes'");
timestamp = now_uSec - 180*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '4hour'");
timestamp = now_uSec - 250*60*1000000;
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '4hour10minutes'");
let today = new Date();
today.setHours(0);
@ -191,23 +352,27 @@ function setupFormHistory() {
timestamp + " WHERE fieldname = 'b4today'");
// Sanity check.
ok(formhist.nameExists("10minutes"), "Checking for 10minutes form history entry creation");
ok(formhist.nameExists("1hour"), "Checking for 1hour form history entry creation");
ok(formhist.nameExists("1hour10minutes"), "Checking for 1hour10minutes form history entry creation");
ok(formhist.nameExists("2hour"), "Checking for 2hour form history entry creation");
ok(formhist.nameExists("2hour10minutes"), "Checking for 2hour10minutes form history entry creation");
ok(formhist.nameExists("4hour"), "Checking for 4hour form history entry creation");
ok(formhist.nameExists("4hour10minutes"), "Checking for 4hour10minutes form history entry creation");
ok(formhist.nameExists("today"), "Checking for today form history entry creation");
ok(formhist.nameExists("b4today"), "Checking for b4today form history entry creation");
}
function setupDownloads() {
// Add within-1-hour download to DB
// Add 10-minutes download to DB
let data = {
id: "5555551",
name: "fakefile-1-hour",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-1-hour",
startTime: now_uSec - 45*60*1000000, // 45 minutes ago, in uSec
endTime: now_uSec - 44*60*1000000, // 1 minute later
id: "5555555",
name: "fakefile-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-10-minutes",
startTime: now_uSec - 10*60*1000000, // 10 minutes ago, in uSec
endTime: now_uSec - 11*60*1000000, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
@ -227,6 +392,48 @@ function setupDownloads() {
stmt.reset();
}
// Add within-1-hour download to DB
data = {
id: "5555551",
name: "fakefile-1-hour",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
target: "fakefile-1-hour",
startTime: now_uSec - 45*60*1000000, // 45 minutes ago, in uSec
endTime: now_uSec - 44*60*1000000, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
try {
for (let prop in data)
stmt.params[prop] = data[prop];
stmt.execute();
}
finally {
stmt.reset();
}
// Add 1-hour-10-minutes download to DB
data = {
id: "5555556",
name: "fakefile-1-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-1-hour-10-minutes",
startTime: now_uSec - 70*60*1000000, // 70 minutes ago, in uSec
endTime: now_uSec - 71*60*1000000, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
try {
for (let prop in data)
stmt.params[prop] = data[prop];
stmt.execute();
}
finally {
stmt.reset();
}
// Add within-2-hour download
data = {
id: "5555552",
@ -248,6 +455,27 @@ function setupDownloads() {
stmt.reset();
}
// Add 2-hour-10-minutes download
data = {
id: "5555557",
name: "fakefile-2-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-2-hour-10-minutes",
startTime: now_uSec - 130*60*1000000, // 130 minutes ago, in uSec
endTime: now_uSec - 131*60*1000000, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
try {
for (let prop in data)
stmt.params[prop] = data[prop];
stmt.execute();
}
finally {
stmt.reset();
}
// Add within-4-hour download
data = {
id: "5555553",
@ -269,6 +497,27 @@ function setupDownloads() {
stmt.reset();
}
// Add 4-hour-10-minutes download
data = {
id: "5555558",
name: "fakefile-4-hour-10-minutes",
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: "fakefile-4-hour-10-minutes",
startTime: now_uSec - 250*60*1000000, // 250 minutes ago, in uSec
endTime: now_uSec - 251*60*1000000, // 1 minute later
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
try {
for (let prop in data)
stmt.params[prop] = data[prop];
stmt.execute();
}
finally {
stmt.reset();
}
// Add "today" download
let today = new Date();
today.setHours(0);
@ -320,9 +569,13 @@ function setupDownloads() {
// Confirm everything worked
ok(downloadExists(5555550), "Pretend download for everything case should exist");
ok(downloadExists(5555555), "Pretend download for 10-minutes case should exist");
ok(downloadExists(5555551), "Pretend download for 1-hour case should exist");
ok(downloadExists(5555556), "Pretend download for 1-hour-10-minutes case should exist");
ok(downloadExists(5555552), "Pretend download for 2-hour case should exist");
ok(downloadExists(5555557), "Pretend download for 2-hour-10-minutes case should exist");
ok(downloadExists(5555553), "Pretend download for 4-hour case should exist");
ok(downloadExists(5555558), "Pretend download for 4-hour-10-minutes case should exist");
ok(downloadExists(5555554), "Pretend download for Today case should exist");
}

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

@ -0,0 +1,721 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 sanitize dialog test code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Drew Willcoxon <adw@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Tests the sanitize dialog (a.k.a. the clear recent history dialog).
* See bug 480169.
*
* The purpose of this test is not to fully flex the sanitize timespan code;
* browser/base/content/test/browser_sanitize-timespans.js does that. This
* test checks the UI of the dialog and makes sure it's correctly connected to
* the sanitize timespan code.
*
* Some of this code, especially the history creation parts, was taken from
* browser/base/content/test/browser_sanitize-timespans.js.
*/
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
loadSubScript("chrome://mochikit/content/MochiKit/packed.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
loadSubScript("chrome://browser/content/sanitize.js");
const winWatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory);
const iosvc = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
const formhist = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
// Add tests here. Each is a function that's called by doNextTest().
var gAllTests = [
/**
* Cancels the dialog, makes sure history not cleared.
*/
function () {
// Add history (within the past hour)
let uris = [];
for (let i = 0; i < 30; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
let wh = new WindowHelper();
wh.onload = function () {
this.selectDuration(Sanitizer.TIMESPAN_HOUR);
this.checkPrefCheckbox("history-downloads-checkbox", false);
this.checkDetails();
this.toggleDetails();
this.checkDetails();
this.cancelDialog();
ensureHistoryClearedState(uris, false);
blankSlate();
ensureHistoryClearedState(uris, true);
};
wh.open();
},
/**
* Ensures that the combined history-downloads checkbox clears both history
* visits and downloads when checked; the dialog respects simple timespan.
*/
function () {
// Add history and downloads (within the past hour).
let uris = [];
for (let i = 0; i < 30; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
let downloadIDs = [];
for (let i = 0; i < 5; i++) {
downloadIDs.push(addDownloadWithMinutesAgo(i));
}
// Add history and downloads (over an hour ago).
let olderURIs = [];
for (let i = 0; i < 5; i++) {
olderURIs.push(addHistoryWithMinutesAgo(61 + i));
}
let olderDownloadIDs = [];
for (let i = 0; i < 5; i++) {
olderDownloadIDs.push(addDownloadWithMinutesAgo(61 + i));
}
let totalHistoryVisits = uris.length + olderURIs.length;
let wh = new WindowHelper();
wh.onload = function () {
this.selectDuration(Sanitizer.TIMESPAN_HOUR);
this.checkPrefCheckbox("history-downloads-checkbox", true);
this.acceptDialog();
intPrefIs("sanitize.timeSpan", Sanitizer.TIMESPAN_HOUR,
"timeSpan pref should be hour after accepting dialog with " +
"hour selected");
boolPrefIs("cpd.history", true,
"history pref should be true after accepting dialog with " +
"combined history-downloads checkbox checked");
boolPrefIs("cpd.downloads", true,
"downloads pref should be true after accepting dialog with " +
"combined history-downloads checkbox checked");
// History visits and downloads within one hour should be cleared.
ensureHistoryClearedState(uris, true);
ensureDownloadsClearedState(downloadIDs, true);
// Visits and downloads > 1 hour should still exist.
ensureHistoryClearedState(olderURIs, false);
ensureDownloadsClearedState(olderDownloadIDs, false);
// OK, done, cleanup after ourselves.
blankSlate();
ensureHistoryClearedState(olderURIs, true);
ensureDownloadsClearedState(olderDownloadIDs, true);
};
wh.open();
},
/**
* Ensures that the combined history-downloads checkbox removes neither
* history visits nor downloads when not checked.
*/
function () {
// Add history, downloads, form entries (within the past hour).
let uris = [];
for (let i = 0; i < 5; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
let downloadIDs = [];
for (let i = 0; i < 5; i++) {
downloadIDs.push(addDownloadWithMinutesAgo(i));
}
let formEntries = [];
for (let i = 0; i < 5; i++) {
formEntries.push(addFormEntryWithMinutesAgo(i));
}
let wh = new WindowHelper();
wh.onload = function () {
is(this.isWarningPanelVisible(), false,
"Warning panel should be hidden after previously accepting dialog " +
"with a predefined timespan");
this.selectDuration(Sanitizer.TIMESPAN_HOUR);
// Remove only form entries, leave history and downloads.
this.checkPrefCheckbox("history-downloads-checkbox", false);
this.checkPrefCheckbox("formdata", true);
this.acceptDialog();
intPrefIs("sanitize.timeSpan", Sanitizer.TIMESPAN_HOUR,
"timeSpan pref should be hour after accepting dialog with " +
"hour selected");
boolPrefIs("cpd.history", false,
"history pref should be false after accepting dialog with " +
"combined history-downloads checkbox unchecked");
boolPrefIs("cpd.downloads", false,
"downloads pref should be false after accepting dialog with " +
"combined history-downloads checkbox unchecked");
// Of the three only form entries should be cleared.
ensureHistoryClearedState(uris, false);
ensureDownloadsClearedState(downloadIDs, false);
ensureFormEntriesClearedState(formEntries, true);
// OK, done, cleanup after ourselves.
blankSlate();
ensureHistoryClearedState(uris, true);
ensureDownloadsClearedState(downloadIDs, true);
};
wh.open();
},
/**
* Ensures that the "Everything" duration option works.
*/
function () {
// Add history.
let uris = [];
uris.push(addHistoryWithMinutesAgo(10)); // within past hour
uris.push(addHistoryWithMinutesAgo(70)); // within past two hours
uris.push(addHistoryWithMinutesAgo(130)); // within past four hours
uris.push(addHistoryWithMinutesAgo(250)); // outside past four hours
let wh = new WindowHelper();
wh.onload = function () {
is(this.isWarningPanelVisible(), false,
"Warning panel should be hidden after previously accepting dialog " +
"with a predefined timespan");
this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
this.checkPrefCheckbox("history-downloads-checkbox", true);
this.checkDetails();
this.toggleDetails();
this.checkDetails();
this.acceptDialog();
intPrefIs("sanitize.timeSpan", Sanitizer.TIMESPAN_EVERYTHING,
"timeSpan pref should be everything after accepting dialog " +
"with everything selected");
ensureHistoryClearedState(uris, true);
};
wh.open();
},
/**
* Ensures that the "Everything" warning is visible on dialog open after
* the previous test.
*/
function () {
// Add history.
let uris = [];
uris.push(addHistoryWithMinutesAgo(10)); // within past hour
uris.push(addHistoryWithMinutesAgo(70)); // within past two hours
uris.push(addHistoryWithMinutesAgo(130)); // within past four hours
uris.push(addHistoryWithMinutesAgo(250)); // outside past four hours
let wh = new WindowHelper();
wh.onload = function () {
is(this.isWarningPanelVisible(), true,
"Warning panel should be visible after previously accepting dialog " +
"with clearing everything");
this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
this.checkPrefCheckbox("history-downloads-checkbox", true);
this.acceptDialog();
intPrefIs("sanitize.timeSpan", Sanitizer.TIMESPAN_EVERYTHING,
"timeSpan pref should be everything after accepting dialog " +
"with everything selected");
ensureHistoryClearedState(uris, true);
};
wh.open();
}
];
// Used as the download database ID for a new download. Incremented for each
// new download. See addDownloadWithMinutesAgo().
var gDownloadId = 5555551;
// Index in gAllTests of the test currently being run. Incremented for each
// test run. See doNextTest().
var gCurrTest = 0;
var now_uSec = Date.now() * 1000;
///////////////////////////////////////////////////////////////////////////////
/**
* This wraps the dialog and provides some convenience methods for interacting
* with it.
*
* @param aWin
* The dialog's nsIDOMWindow
*/
function WindowHelper(aWin) {
this.win = aWin;
}
WindowHelper.prototype = {
/**
* "Presses" the dialog's OK button.
*/
acceptDialog: function () {
is(this.win.document.documentElement.getButton("accept").disabled, false,
"Dialog's OK button should not be disabled");
this.win.document.documentElement.acceptDialog();
},
/**
* "Presses" the dialog's Cancel button.
*/
cancelDialog: function () {
this.win.document.documentElement.cancelDialog();
},
/**
* Ensures that the details progressive disclosure button and the item list
* hidden by it match up. Also makes sure the height of the dialog is
* sufficient for the item list and warning panel.
*/
checkDetails: function () {
let button = this.getDetailsButton();
let list = this.getItemList();
let hidden = list.hidden || list.collapsed;
let dir = hidden ? "down" : "up";
is(button.className, "expander-" + dir,
"Details button should be " + dir + " because item list is " +
(hidden ? "" : "not ") + "hidden");
let height = 0;
if (!hidden)
height += list.boxObject.height;
if (this.isWarningPanelVisible())
height += this.getWarningPanel().boxObject.height;
ok(height < this.win.innerHeight,
"Window should be tall enough to fit warning panel and item list");
},
/**
* (Un)checks a history scope checkbox (browser & download history,
* form history, etc.).
*
* @param aPrefName
* Either the ID of the checkbox or the final portion of its
* privacy.cpd.* preference name
* @param aCheckState
* True if the checkbox should be checked, false otherwise
*/
checkPrefCheckbox: function (aPrefName, aCheckState) {
let checkBoxes = this.win.document.getElementsByTagName("listitem");
for (let i = 0; i < checkBoxes.length; i++) {
let cb = checkBoxes[i];
if (cb.id === aPrefName ||
(cb.hasAttribute("preference") &&
cb.getAttribute("preference") === "privacy.cpd." + aPrefName)) {
cb.checked = aCheckState;
break;
}
}
},
/**
* @return The details progressive disclosure button
*/
getDetailsButton: function () {
return this.win.document.getElementById("detailsExpander");
},
/**
* @return The dialog's duration dropdown
*/
getDurationDropdown: function () {
return this.win.document.getElementById("sanitizeDurationChoice");
},
/**
* @return The item list hidden by the details progressive disclosure button
*/
getItemList: function () {
return this.win.document.getElementById("itemList");
},
/**
* @return The clear-everything warning box
*/
getWarningPanel: function () {
return this.win.document.getElementById("sanitizeEverythingWarningBox");
},
/**
* @return True if the "Everything" warning panel is visible (as opposed to
* the tree)
*/
isWarningPanelVisible: function () {
return !this.getWarningPanel().hidden;
},
/**
* Opens the clear recent history dialog. Before calling this, set
* this.onload to a function to execute onload. It should close the dialog
* when done so that the tests may continue. Set this.onunload to a function
* to execute onunload. this.onunload is optional.
*/
open: function () {
let wh = this;
let windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic !== "domwindowopened")
return;
winWatch.unregisterNotification(this);
var loaded = false;
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function onload(event) {
win.removeEventListener("load", onload, false);
if (win.name !== "SanitizeDialog")
return;
wh.win = win;
loaded = true;
executeSoon(function () {
// Some exceptions that reach here don't reach the test harness, but
// ok()/is() do...
try {
wh.onload();
}
catch (exc) {
win.close();
ok(false, "Unexpected exception: " + exc + "\n" + exc.stack);
finish();
}
});
}, false);
win.addEventListener("unload", function onunload(event) {
if (win.name !== "SanitizeDialog") {
win.removeEventListener("unload", onunload, false);
return;
}
// Why is unload fired before load?
if (!loaded)
return;
win.removeEventListener("unload", onunload, false);
wh.win = win;
executeSoon(function () {
// Some exceptions that reach here don't reach the test harness, but
// ok()/is() do...
try {
if (wh.onunload)
wh.onunload();
doNextTest();
}
catch (exc) {
win.close();
ok(false, "Unexpected exception: " + exc + "\n" + exc.stack);
finish();
}
});
}, false);
}
};
winWatch.registerNotification(windowObserver);
winWatch.openWindow(null,
"chrome://browser/content/sanitize.xul",
"SanitizeDialog",
"chrome,titlebar,dialog,centerscreen,modal",
null);
},
/**
* Selects a duration in the duration dropdown.
*
* @param aDurVal
* One of the Sanitizer.TIMESPAN_* values
*/
selectDuration: function (aDurVal) {
this.getDurationDropdown().value = aDurVal;
if (aDurVal === Sanitizer.TIMESPAN_EVERYTHING) {
is(this.isWarningPanelVisible(), true,
"Warning panel should be visible for TIMESPAN_EVERYTHING");
}
else {
is(this.isWarningPanelVisible(), false,
"Warning panel should not be visible for non-TIMESPAN_EVERYTHING");
}
},
/**
* Toggles the details progressive disclosure button.
*/
toggleDetails: function () {
this.getDetailsButton().click();
}
};
/**
* Adds a download to history.
*
* @param aMinutesAgo
* The download will be downloaded this many minutes ago
*/
function addDownloadWithMinutesAgo(aMinutesAgo) {
let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
let data = {
id: gDownloadId,
name: name,
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: name,
startTime: now_uSec - (aMinutesAgo * 60 * 1000000),
endTime: now_uSec - ((aMinutesAgo + 1) *60 * 1000000),
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
let db = dm.DBConnection;
let stmt = db.createStatement(
"INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
"state, currBytes, maxBytes, preferredAction, autoResume) " +
"VALUES (:id, :name, :source, :target, :startTime, :endTime, :state, " +
":currBytes, :maxBytes, :preferredAction, :autoResume)");
try {
for (let prop in data) {
stmt.params[prop] = data[prop];
}
stmt.execute();
}
finally {
stmt.reset();
}
is(downloadExists(gDownloadId), true,
"Sanity check: download " + gDownloadId +
" should exist after creating it");
return gDownloadId++;
}
/**
* Adds a form entry to history.
*
* @param aMinutesAgo
* The entry will be added this many minutes ago
*/
function addFormEntryWithMinutesAgo(aMinutesAgo) {
let name = aMinutesAgo + "-minutes-ago";
formhist.addEntry(name, "dummy");
// Artifically age the entry to the proper vintage.
let db = formhist.DBConnection;
let timestamp = now_uSec - (aMinutesAgo * 60 * 1000000);
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '" + name + "'");
is(formhist.nameExists(name), true,
"Sanity check: form entry " + name + " should exist after creating it");
return name;
}
/**
* Adds a history visit to history.
*
* @param aMinutesAgo
* The visit will be visited this many minutes ago
*/
function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = uri("http://" + aMinutesAgo + "-minutes-ago.com/");
bhist.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(bhist.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec +
" should exist after creating it");
return pURI;
}
/**
* Removes all history visits, downloads, and form entries.
*/
function blankSlate() {
bhist.removeAllPages();
dm.cleanUp();
formhist.removeAllEntries();
}
/**
* Ensures that the given pref is the expected value.
*
* @param aPrefName
* The pref's sub-branch under the privacy branch
* @param aExpectedVal
* The pref's expected value
* @param aMsg
* Passed to is()
*/
function boolPrefIs(aPrefName, aExpectedVal, aMsg) {
let prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService).
getBranch("privacy.");
is(prefs.getBoolPref(aPrefName), aExpectedVal, aMsg);
}
/**
* Checks to see if the download with the specified ID exists.
*
* @param aID
* The ID of the download to check
* @return True if the download exists, false otherwise
*/
function downloadExists(aID)
{
let db = dm.DBConnection;
let stmt = db.createStatement(
"SELECT * " +
"FROM moz_downloads " +
"WHERE id = :id"
);
stmt.params.id = aID;
let rows = stmt.step();
stmt.finalize();
return !!rows;
}
/**
* Runs the next test in the gAllTests array. If all tests have been run,
* finishes the entire suite.
*/
function doNextTest() {
if (gAllTests.length <= gCurrTest) {
blankSlate();
finish();
}
else {
let ct = gCurrTest;
gCurrTest++;
gAllTests[ct]();
}
}
/**
* Ensures that the specified downloads are either cleared or not.
*
* @param aDownloadIDs
* Array of download database IDs
* @param aShouldBeCleared
* True if each download should be cleared, false otherwise
*/
function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aDownloadIDs.forEach(function (id) {
is(downloadExists(id), !aShouldBeCleared,
"download " + id + " should " + niceStr + " exist");
});
}
/**
* Ensures that the specified form entries are either cleared or not.
*
* @param aFormEntries
* Array of form entry names
* @param aShouldBeCleared
* True if each form entry should be cleared, false otherwise
*/
function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aFormEntries.forEach(function (entry) {
is(formhist.nameExists(entry), !aShouldBeCleared,
"form entry " + entry + " should " + niceStr + " exist");
});
}
/**
* Ensures that the specified URIs are either cleared or not.
*
* @param aURIs
* Array of page URIs
* @param aShouldBeCleared
* True if each visit to the URI should be cleared, false otherwise
*/
function ensureHistoryClearedState(aURIs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aURIs.forEach(function (aURI) {
is(bhist.isVisited(aURI), !aShouldBeCleared,
"history visit " + aURI.spec + " should " + niceStr + " exist");
});
}
/**
* Ensures that the given pref is the expected value.
*
* @param aPrefName
* The pref's sub-branch under the privacy branch
* @param aExpectedVal
* The pref's expected value
* @param aMsg
* Passed to is()
*/
function intPrefIs(aPrefName, aExpectedVal, aMsg) {
let prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService).
getBranch("privacy.");
is(prefs.getIntPref(aPrefName), aExpectedVal, aMsg);
}
/**
* @return A new nsIURI from aSpec.
*/
function uri(aSpec) {
return iosvc.newURI(aSpec, null, null);
}
///////////////////////////////////////////////////////////////////////////////
function test() {
blankSlate();
waitForExplicitFinish();
// Kick off all the tests in the gAllTests array.
doNextTest();
}

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

@ -0,0 +1,674 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 sanitize dialog test code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Drew Willcoxon <adw@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Tests the sanitize dialog (a.k.a. the clear recent history dialog).
* See bug 480169.
*
* The purpose of this test is not to fully flex the sanitize timespan code;
* browser/base/content/test/browser_sanitize-timespans.js does that. This
* test checks the UI of the dialog and makes sure it's correctly connected to
* the sanitize timespan code.
*
* Some of this code, especially the history creation parts, was taken from
* browser/base/content/test/browser_sanitize-timespans.js.
*/
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
loadSubScript("chrome://mochikit/content/MochiKit/packed.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
loadSubScript("chrome://browser/content/sanitize.js");
const winWatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
getService(Ci.nsIBrowserHistory);
const iosvc = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
const formhist = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
// Add tests here. Each is a function that's called by doNextTest().
var gAllTests = [
/**
* Moves the grippy around, makes sure it works OK.
*/
function () {
// Add history (within the past hour) to get some rows in the tree.
let uris = [];
for (let i = 0; i < 30; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
// Open the dialog and do our tests.
openWindow(function (aWin) {
let wh = new WindowHelper(aWin);
wh.selectDuration(Sanitizer.TIMESPAN_HOUR);
wh.checkGrippy("Grippy should be at last row after selecting HOUR " +
"duration",
wh.getRowCount() - 1);
// Move the grippy around.
let row = wh.getGrippyRow();
while (row !== 0) {
row--;
wh.moveGrippyBy(-1);
wh.checkGrippy("Grippy should be moved up one row", row);
}
wh.moveGrippyBy(-1);
wh.checkGrippy("Grippy should remain at first row after trying to move " +
"it up",
0);
while (row !== wh.getRowCount() - 1) {
row++;
wh.moveGrippyBy(1);
wh.checkGrippy("Grippy should be moved down one row", row);
}
wh.moveGrippyBy(1);
wh.checkGrippy("Grippy should remain at last row after trying to move " +
"it down",
wh.getRowCount() - 1);
// Cancel the dialog, make sure history visits are not cleared.
wh.checkPrefCheckbox("history-downloads-checkbox", false);
wh.cancelDialog();
ensureHistoryClearedState(uris, false);
// OK, done, cleanup after ourselves.
blankSlate();
ensureHistoryClearedState(uris, true);
});
},
/**
* Ensures that the combined history-downloads checkbox clears both history
* visits and downloads when checked; the dialog respects simple timespan.
*/
function () {
// Add history and downloads (within the past hour).
let uris = [];
for (let i = 0; i < 30; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
let downloadIDs = [];
for (let i = 0; i < 5; i++) {
downloadIDs.push(addDownloadWithMinutesAgo(i));
}
// Add history and downloads (over an hour ago).
let olderURIs = [];
for (let i = 0; i < 5; i++) {
olderURIs.push(addHistoryWithMinutesAgo(61 + i));
}
let olderDownloadIDs = [];
for (let i = 0; i < 5; i++) {
olderDownloadIDs.push(addDownloadWithMinutesAgo(61 + i));
}
let totalHistoryVisits = uris.length + olderURIs.length;
// Open the dialog and do our tests.
openWindow(function (aWin) {
let wh = new WindowHelper(aWin);
wh.selectDuration(Sanitizer.TIMESPAN_HOUR);
wh.checkGrippy("Grippy should be at proper row after selecting HOUR " +
"duration",
uris.length);
// Accept the dialog, make sure history visits and downloads within one
// hour are cleared.
wh.checkPrefCheckbox("history-downloads-checkbox", true);
wh.acceptDialog();
ensureHistoryClearedState(uris, true);
ensureDownloadsClearedState(downloadIDs, true);
// Make sure visits and downloads > 1 hour still exist.
ensureHistoryClearedState(olderURIs, false);
ensureDownloadsClearedState(olderDownloadIDs, false);
// OK, done, cleanup after ourselves.
blankSlate();
ensureHistoryClearedState(olderURIs, true);
ensureDownloadsClearedState(olderDownloadIDs, true);
});
},
/**
* Ensures that the combined history-downloads checkbox removes neither
* history visits nor downloads when not checked.
*/
function () {
// Add history, downloads, form entries (within the past hour).
let uris = [];
for (let i = 0; i < 5; i++) {
uris.push(addHistoryWithMinutesAgo(i));
}
let downloadIDs = [];
for (let i = 0; i < 5; i++) {
downloadIDs.push(addDownloadWithMinutesAgo(i));
}
let formEntries = [];
for (let i = 0; i < 5; i++) {
formEntries.push(addFormEntryWithMinutesAgo(i));
}
// Open the dialog and do our tests.
openWindow(function (aWin) {
let wh = new WindowHelper(aWin);
wh.selectDuration(Sanitizer.TIMESPAN_HOUR);
wh.checkGrippy("Grippy should be at last row after selecting HOUR " +
"duration",
wh.getRowCount() - 1);
// Remove only form entries, leave history and downloads.
wh.checkPrefCheckbox("history-downloads-checkbox", false);
wh.checkPrefCheckbox("formdata", true);
wh.acceptDialog();
// Of the three only form entries should be cleared.
ensureHistoryClearedState(uris, false);
ensureDownloadsClearedState(downloadIDs, false);
ensureFormEntriesClearedState(formEntries, true);
// OK, done, cleanup after ourselves.
blankSlate();
ensureHistoryClearedState(uris, true);
ensureDownloadsClearedState(downloadIDs, true);
});
},
/**
* Ensures that the "Everything" duration option works.
*/
function () {
// Add history.
let uris = [];
uris.push(addHistoryWithMinutesAgo(10)); // within past hour
uris.push(addHistoryWithMinutesAgo(70)); // within past two hours
uris.push(addHistoryWithMinutesAgo(130)); // within past four hours
uris.push(addHistoryWithMinutesAgo(250)); // outside past four hours
// Open the dialog and do our tests.
openWindow(function (aWin) {
let wh = new WindowHelper(aWin);
wh.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
wh.checkPrefCheckbox("history-downloads-checkbox", true);
wh.acceptDialog();
ensureHistoryClearedState(uris, true);
});
}
];
// Used as the download database ID for a new download. Incremented for each
// new download. See addDownloadWithMinutesAgo().
var gDownloadId = 5555551;
// Index in gAllTests of the test currently being run. Incremented for each
// test run. See doNextTest().
var gCurrTest = 0;
var now_uSec = Date.now() * 1000;
///////////////////////////////////////////////////////////////////////////////
/**
* This wraps the dialog and provides some convenience methods for interacting
* with it.
*
* A warning: Before you call any function that uses the tree (or any function
* that calls a function that uses the tree), you must set a non-everything
* duration by calling selectDuration(). The dialog does not initialize the
* tree if it does not yet need to be shown.
*
* @param aWin
* The dialog's nsIDOMWindow
*/
function WindowHelper(aWin) {
this.win = aWin;
}
WindowHelper.prototype = {
/**
* "Presses" the dialog's OK button.
*/
acceptDialog: function () {
is(this.win.document.documentElement.getButton("accept").disabled, false,
"Dialog's OK button should not be disabled");
this.win.document.documentElement.acceptDialog();
},
/**
* "Presses" the dialog's Cancel button.
*/
cancelDialog: function () {
this.win.document.documentElement.cancelDialog();
},
/**
* Ensures that the grippy row is in the right place, tree selection is OK,
* and that the grippy's visible.
*
* @param aMsg
* Passed to is() when checking grippy location
* @param aExpectedRow
* The row that the grippy should be at
*/
checkGrippy: function (aMsg, aExpectedRow) {
is(this.getGrippyRow(), aExpectedRow, aMsg);
this.checkTreeSelection();
this.ensureGrippyIsVisible();
},
/**
* (Un)checks a history scope checkbox (browser & download history,
* form history, etc.).
*
* @param aPrefName
* Either the ID of the checkbox or the final portion of its
* privacy.cpd.* preference name
* @param aCheckState
* True if the checkbox should be checked, false otherwise
*/
checkPrefCheckbox: function (aPrefName, aCheckState) {
let checkBoxes = this.win.document.getElementsByTagName("listitem");
for (let i = 0; i < checkBoxes.length; i++) {
let cb = checkBoxes[i];
if (cb.id === aPrefName ||
(cb.hasAttribute("preference") &&
cb.getAttribute("preference") === "privacy.cpd." + aPrefName)) {
cb.checked = aCheckState;
break;
}
}
},
/**
* Ensures that the tree selection is appropriate to the grippy row. (A
* single, contiguous selection should exist from the first row all the way
* to the grippy.)
*/
checkTreeSelection: function () {
let grippyRow = this.getGrippyRow();
let sel = this.getTree().view.selection;
if (grippyRow === 0) {
is(sel.getRangeCount(), 0,
"Grippy row is 0, so no tree selection should exist");
}
else {
is(sel.getRangeCount(), 1,
"Grippy row > 0, so only one tree selection range should exist");
let min = {};
let max = {};
sel.getRangeAt(0, min, max);
is(min.value, 0, "Tree selection should start at first row");
is(max.value, grippyRow - 1,
"Tree selection should end at row before grippy");
}
},
/**
* The grippy should always be visible when it's moved directly. This method
* ensures that.
*/
ensureGrippyIsVisible: function () {
let tbo = this.getTree().treeBoxObject;
let firstVis = tbo.getFirstVisibleRow();
let lastVis = tbo.getLastVisibleRow();
let grippyRow = this.getGrippyRow();
ok(firstVis <= grippyRow && grippyRow <= lastVis,
"Grippy row should be visible; this inequality should be true: " +
firstVis + " <= " + grippyRow + " <= " + lastVis);
},
/**
* @return The dialog's duration dropdown
*/
getDurationDropdown: function () {
return this.win.document.getElementById("sanitizeDurationChoice");
},
/**
* @return The grippy row index
*/
getGrippyRow: function () {
return this.win.gContiguousSelectionTreeHelper.getGrippyRow();
},
/**
* @return The tree's row count (includes the grippy row)
*/
getRowCount: function () {
return this.getTree().view.rowCount;
},
/**
* @return The tree
*/
getTree: function () {
return this.win.gContiguousSelectionTreeHelper.tree;
},
/**
* @return True if the "Everything" warning panel is visible (as opposed to
* the tree)
*/
isWarningPanelVisible: function () {
return this.win.document.getElementById("durationDeck").selectedIndex == 1;
},
/**
* @return True if the tree is visible (as opposed to the warning panel)
*/
isTreeVisible: function () {
return this.win.document.getElementById("durationDeck").selectedIndex == 0;
},
/**
* Moves the grippy one row at a time in the direction and magnitude specified.
* If aDelta < 0, moves the grippy up; if aDelta > 0, moves it down.
*
* @param aDelta
* The amount and direction to move
*/
moveGrippyBy: function (aDelta) {
if (aDelta === 0)
return;
let key = aDelta < 0 ? "UP" : "DOWN";
let abs = Math.abs(aDelta);
let treechildren = this.getTree().treeBoxObject.treeBody;
for (let i = 0; i < abs; i++) {
EventUtils.sendKey(key, treechildren);
}
},
/**
* Selects a duration in the duration dropdown.
*
* @param aDurVal
* One of the Sanitizer.TIMESPAN_* values
*/
selectDuration: function (aDurVal) {
this.getDurationDropdown().value = aDurVal;
if (aDurVal === Sanitizer.TIMESPAN_EVERYTHING) {
is(this.isTreeVisible(), false,
"Tree should not be visible for TIMESPAN_EVERYTHING");
is(this.isWarningPanelVisible(), true,
"Warning panel should be visible for TIMESPAN_EVERYTHING");
}
else {
is(this.isTreeVisible(), true,
"Tree should be visible for non-TIMESPAN_EVERYTHING");
is(this.isWarningPanelVisible(), false,
"Warning panel should not be visible for non-TIMESPAN_EVERYTHING");
}
}
};
/**
* Adds a download to history.
*
* @param aMinutesAgo
* The download will be downloaded this many minutes ago
*/
function addDownloadWithMinutesAgo(aMinutesAgo) {
let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
let data = {
id: gDownloadId,
name: name,
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
target: name,
startTime: now_uSec - (aMinutesAgo * 60 * 1000000),
endTime: now_uSec - ((aMinutesAgo + 1) *60 * 1000000),
state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
};
let db = dm.DBConnection;
let stmt = db.createStatement(
"INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
"state, currBytes, maxBytes, preferredAction, autoResume) " +
"VALUES (:id, :name, :source, :target, :startTime, :endTime, :state, " +
":currBytes, :maxBytes, :preferredAction, :autoResume)");
try {
for (let prop in data) {
stmt.params[prop] = data[prop];
}
stmt.execute();
}
finally {
stmt.reset();
}
is(downloadExists(gDownloadId), true,
"Sanity check: download " + gDownloadId +
" should exist after creating it");
return gDownloadId++;
}
/**
* Adds a form entry to history.
*
* @param aMinutesAgo
* The entry will be added this many minutes ago
*/
function addFormEntryWithMinutesAgo(aMinutesAgo) {
let name = aMinutesAgo + "-minutes-ago";
formhist.addEntry(name, "dummy");
// Artifically age the entry to the proper vintage.
let db = formhist.DBConnection;
let timestamp = now_uSec - (aMinutesAgo * 60 * 1000000);
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
timestamp + " WHERE fieldname = '" + name + "'");
is(formhist.nameExists(name), true,
"Sanity check: form entry " + name + " should exist after creating it");
return name;
}
/**
* Adds a history visit to history.
*
* @param aMinutesAgo
* The visit will be visited this many minutes ago
*/
function addHistoryWithMinutesAgo(aMinutesAgo) {
let pURI = uri("http://" + aMinutesAgo + "-minutes-ago.com/");
bhist.addPageWithDetails(pURI,
aMinutesAgo + " minutes ago",
now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
is(bhist.isVisited(pURI), true,
"Sanity check: history visit " + pURI.spec +
" should exist after creating it");
return pURI;
}
/**
* Removes all history visits, downloads, and form entries.
*/
function blankSlate() {
bhist.removeAllPages();
dm.cleanUp();
formhist.removeAllEntries();
}
/**
* Checks to see if the download with the specified ID exists.
*
* @param aID
* The ID of the download to check
* @return True if the download exists, false otherwise
*/
function downloadExists(aID)
{
let db = dm.DBConnection;
let stmt = db.createStatement(
"SELECT * " +
"FROM moz_downloads " +
"WHERE id = :id"
);
stmt.params.id = aID;
let rows = stmt.step();
stmt.finalize();
return !!rows;
}
/**
* Runs the next test in the gAllTests array. If all tests have been run,
* finishes the entire suite.
*/
function doNextTest() {
if (gAllTests.length <= gCurrTest) {
blankSlate();
finish();
}
else {
let ct = gCurrTest;
gCurrTest++;
gAllTests[ct]();
}
}
/**
* Ensures that the specified downloads are either cleared or not.
*
* @param aDownloadIDs
* Array of download database IDs
* @param aShouldBeCleared
* True if each download should be cleared, false otherwise
*/
function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aDownloadIDs.forEach(function (id) {
is(downloadExists(id), !aShouldBeCleared,
"download " + id + " should " + niceStr + " exist");
});
}
/**
* Ensures that the specified form entries are either cleared or not.
*
* @param aFormEntries
* Array of form entry names
* @param aShouldBeCleared
* True if each form entry should be cleared, false otherwise
*/
function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aFormEntries.forEach(function (entry) {
is(formhist.nameExists(entry), !aShouldBeCleared,
"form entry " + entry + " should " + niceStr + " exist");
});
}
/**
* Ensures that the specified URIs are either cleared or not.
*
* @param aURIs
* Array of page URIs
* @param aShouldBeCleared
* True if each visit to the URI should be cleared, false otherwise
*/
function ensureHistoryClearedState(aURIs, aShouldBeCleared) {
let niceStr = aShouldBeCleared ? "no longer" : "still";
aURIs.forEach(function (aURI) {
is(bhist.isVisited(aURI), !aShouldBeCleared,
"history visit " + aURI.spec + " should " + niceStr + " exist");
});
}
/**
* Opens the sanitize dialog and runs a callback once it's finished loading.
*
* @param aOnloadCallback
* A function that will be called once the dialog has loaded
*/
function openWindow(aOnloadCallback) {
let windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
winWatch.unregisterNotification(this);
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function onload(event) {
win.removeEventListener("load", onload, false);
executeSoon(function () {
// Some exceptions that reach here don't reach the test harness, but
// ok()/is() do...
try {
aOnloadCallback(win);
doNextTest();
}
catch (exc) {
win.close();
ok(false, "Unexpected exception: " + exc + "\n" + exc.stack);
finish();
}
});
}, false);
}
}
};
winWatch.registerNotification(windowObserver);
winWatch.openWindow(null,
"chrome://browser/content/sanitize.xul",
"Sanitize",
"chrome,titlebar,dialog,centerscreen,modal",
null);
}
/**
* @return A new nsIURI from aSpec.
*/
function uri(aSpec) {
return iosvc.newURI(aSpec, null, null);
}
///////////////////////////////////////////////////////////////////////////////
function test() {
blankSlate();
waitForExplicitFinish();
// Kick off all the tests in the gAllTests array.
doNextTest();
}

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

@ -0,0 +1,32 @@
function test() {
gBrowser.addTab();
gBrowser.addTab();
gBrowser.addTab();
var tabs = gBrowser.tabContainer.childNodes;
var owner;
is(tabs.length, 4, "4 tabs are open");
owner = gBrowser.selectedTab = tabs[2];
BrowserOpenTab();
is(gBrowser.selectedTab, tabs[4], "newly opened tab is selected");
gBrowser.removeCurrentTab();
is(gBrowser.selectedTab, owner, "owner is selected");
owner = gBrowser.selectedTab;
BrowserOpenTab();
gBrowser.selectedTab = tabs[1];
gBrowser.selectedTab = tabs[4];
gBrowser.removeCurrentTab();
isnot(gBrowser.selectedTab, owner, "selecting a different tab clears the owner relation");
owner = gBrowser.selectedTab;
BrowserOpenTab();
gBrowser.moveTabTo(gBrowser.selectedTab, 0);
gBrowser.removeCurrentTab();
is(gBrowser.selectedTab, owner, "owner relatitionship persists when tab is moved");
while (tabs.length > 1)
gBrowser.removeCurrentTab();
}

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

@ -436,18 +436,14 @@ function openAdvancedPreferences(tabID)
/**
* Opens the release notes page for this version of the application.
* @param event
* The DOM Event that caused this function to be called, used to
* determine where the release notes page should be displayed based
* on modifiers (e.g. Ctrl = new tab)
*/
function openReleaseNotes(event)
function openReleaseNotes()
{
var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Components.interfaces.nsIURLFormatter);
var relnotesURL = formatter.formatURLPref("app.releaseNotesURL");
openUILink(relnotesURL, event, false, true);
openUILinkIn(relnotesURL, "tab");
}
#ifdef MOZ_UPDATER
@ -525,6 +521,7 @@ function buildHelpMenu()
}
}
checkForUpdates.label = getStringWithUpdateName("updatesItem_" + key);
checkForUpdates.accessKey = strings.getString("updatesItem_" + key + ".accesskey");
if (um.activeUpdate && updates.isDownloading)
checkForUpdates.setAttribute("loading", "true");
else

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

@ -40,6 +40,8 @@ browser.jar:
* content/browser/safeMode.xul (content/safeMode.xul)
* content/browser/sanitize.js (content/sanitize.js)
* content/browser/sanitize.xul (content/sanitize.xul)
* content/browser/sanitizeDialog.js (content/sanitizeDialog.js)
content/browser/sanitizeDialog.css (content/sanitizeDialog.css)
* content/browser/tabbrowser.css (content/tabbrowser.css)
* content/browser/tabbrowser.xml (content/tabbrowser.xml)
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)

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

@ -8,13 +8,12 @@ function test() {
newBrowser = gBrowser.getBrowserForTab(newTab);
// Navigate to a site with a broken cert
window.addEventListener("DOMContentLoaded", testBrokenCert, true);
newBrowser.contentWindow.location = 'https://nocert.example.com/';
// XXX - This timer and the next should be replaced with an event
// handler when bug 425001 is fixed.
window.setTimeout(testBrokenCert, 2000);
}
function testBrokenCert() {
window.removeEventListener("DOMContentLoaded", testBrokenCert, true);
// Confirm that we are displaying the contributed error page, not the default
ok(/^about:certerror/.test(gBrowser.contentWindow.document.documentURI), "Broken page should go to about:certerror, not about:neterror");
@ -28,12 +27,13 @@ function testBrokenCert() {
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
.setBoolPref("browser.xul.error_pages.expert_bad_cert", true);
window.addEventListener("DOMContentLoaded", testExpertPref, true);
newBrowser.reload();
window.setTimeout(testExpertPref, 2000);
}
function testExpertPref() {
window.removeEventListener("DOMContentLoaded", testExpertPref, true);
var expertDiv = gBrowser.contentWindow.document.getElementById("expertContent");
var technicalDiv = gBrowser.contentWindow.document.getElementById("technicalContent");
ok(!expertDiv.hasAttribute("collapsed"), "Expert content should not be collapsed with the expert mode pref set");

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

@ -161,17 +161,7 @@ FeedConverter.prototype = {
* Records if the feed was sniffed
*/
_sniffed: false,
/**
* See nsIStreamConverter.idl
*/
canConvert: function FC_canConvert(sourceType, destinationType) {
// We only support one conversion.
return destinationType == TYPE_ANY && ((sourceType == TYPE_MAYBE_FEED) ||
(sourceType == TYPE_MAYBE_VIDEO) ||
(sourceType == TYPE_MAYBE_AUDIO));
},
/**
* See nsIStreamConverter.idl
*/
@ -362,7 +352,7 @@ FeedConverter.prototype = {
/**
* See nsIRequestObserver.idl
*/
onStopRequest: function FC_onStopReqeust(request, context, status) {
onStopRequest: function FC_onStopRequest(request, context, status) {
if (this._processor)
this._processor.onStopRequest(request, context, status);
},

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

@ -1423,6 +1423,7 @@ FeedWriter.prototype = {
onEndUpdateBatch: function() { },
onVisit: function() { },
onTitleChanged: function() { },
onBeforeDeleteURI: function() { },
onDeleteURI: function() { },
onClearHistory: function() { },
onPageExpired: function() { },

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

@ -453,10 +453,7 @@ var MigrationWizard = {
var prefBranch = prefSvc.getBranch(null);
if (this._newHomePage == "DEFAULT") {
try {
prefBranch.clearUserPref("browser.startup.homepage");
}
catch (e) { }
prefBranch.clearUserPref("browser.startup.homepage");
}
else {
var str = Components.classes["@mozilla.org/supports-string;1"]

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

@ -495,9 +495,10 @@ nsIEProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
homeURLKey, nsIWindowsRegKey::ACCESS_READ)))
return NS_OK;
// read registry data
// Read in the main home page
NS_NAMED_LITERAL_STRING(homeURLValName, "Start Page");
nsAutoString homeURLVal;
nsAutoString homeURLVal;
if (NS_SUCCEEDED(regKey->ReadStringValue(homeURLValName, homeURLVal))) {
// Do we need this round-about way to get |homePageURL|?
// Perhaps, we do to have the form of URL under our control
@ -506,11 +507,40 @@ nsIEProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
nsCAutoString homePageURL;
nsCOMPtr<nsIURI> homePageURI;
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(homePageURI), homeURLVal)))
if (NS_SUCCEEDED(homePageURI->GetSpec(homePageURL))
&& !homePageURL.IsEmpty())
aResult.Assign(homePageURL);
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(homePageURI), homeURLVal))) {
if (NS_SUCCEEDED(homePageURI->GetSpec(homePageURL)) && !homePageURL.IsEmpty()) {
aResult.Assign(homePageURL);
}
}
}
// With IE7, The "Start Page" key still exists. Secondary home pages
// are located in a string stored in "Secondary Start Pages" which
// contains multiple Unicode URI seperated by nulls. (REG_MULTI_SZ)
NS_NAMED_LITERAL_STRING(ssRegKeyName, "Secondary Start Pages");
nsAutoString secondaryList;
if (NS_SUCCEEDED(regKey->ReadStringValue(ssRegKeyName, secondaryList)) &&
!secondaryList.IsEmpty()) {
nsTArray<nsCString> parsedList;
if (!ParseString(NS_ConvertUTF16toUTF8(secondaryList), '\0', parsedList))
return NS_OK;
// Split the result up into individual uri
for (PRUint32 index = 0; index < parsedList.Length(); ++index) {
nsCOMPtr<nsIURI> uri;
nsCAutoString homePage;
// Append "|uri" to result. This is how we currently handle
// storing multiple home pages.
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), parsedList[index]))) {
if (NS_SUCCEEDED(uri->GetSpec(homePage)) && !homePage.IsEmpty()) {
aResult.AppendLiteral("|");
aResult.Append(homePage);
}
}
}
}
return NS_OK;
}
@ -796,12 +826,6 @@ nsIEProfileMigrator::RunBatched(nsISupports* aUserData)
typedef HRESULT (WINAPI *PStoreCreateInstancePtr)(IPStore**, DWORD, DWORD, DWORD);
struct SignonData {
PRUnichar* user;
PRUnichar* pass;
char* realm;
};
// IE PStore Type GUIDs
// {e161255a-37c3-11d2-bcaa-00c04fd929db} Autocomplete Password & Form Data
// Subtype has same GUID
@ -865,7 +889,7 @@ nsIEProfileMigrator::CopyPasswords(PRBool aReplace)
{
HRESULT hr;
nsresult rv;
nsVoidArray signonsFound;
nsTArray<SignonData> signonsFound;
HMODULE pstoreDLL = ::LoadLibraryW(L"pstorec.dll");
if (!pstoreDLL) {
@ -972,7 +996,7 @@ nsIEProfileMigrator::MigrateSiteAuthSignons(IPStore* aPStore)
}
nsresult
nsIEProfileMigrator::GetSignonsListFromPStore(IPStore* aPStore, nsVoidArray* aSignonsFound)
nsIEProfileMigrator::GetSignonsListFromPStore(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound)
{
HRESULT hr;
@ -1008,13 +1032,12 @@ nsIEProfileMigrator::GetSignonsListFromPStore(IPStore* aPStore, nsVoidArray* aSi
// method, and we own that buffer. We don't free it here, since we're going to be using
// it after the password harvesting stage to locate the username field. Only after the second
// phase is complete do we free the buffer.
SignonData* d = new SignonData;
SignonData* d = aSignonsFound->AppendElement();
if (!d)
return NS_ERROR_OUT_OF_MEMORY;
d->user = (PRUnichar*)username;
d->pass = (PRUnichar*)pass;
d->realm = realm; // freed in ResolveAndMigrateSignons
aSignonsFound->AppendElement(d);
}
}
}
@ -1055,7 +1078,7 @@ nsIEProfileMigrator::KeyIsURI(const nsAString& aKey, char** aRealm)
}
nsresult
nsIEProfileMigrator::ResolveAndMigrateSignons(IPStore* aPStore, nsVoidArray* aSignonsFound)
nsIEProfileMigrator::ResolveAndMigrateSignons(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound)
{
HRESULT hr;
@ -1090,19 +1113,19 @@ nsIEProfileMigrator::ResolveAndMigrateSignons(IPStore* aPStore, nsVoidArray* aSi
// Now that we've done resolving signons, we need to walk the signons list, freeing the data buffers
// for each SignonData entry, since these buffers were allocated by the system back in |GetSignonListFromPStore|
// but never freed.
PRInt32 signonCount = aSignonsFound->Count();
for (PRInt32 i = 0; i < signonCount; ++i) {
SignonData* sd = (SignonData*)aSignonsFound->ElementAt(i);
::CoTaskMemFree(sd->user); // |sd->user| is a pointer to the start of a buffer that also contains sd->pass
NS_Free(sd->realm);
delete sd;
PRUint32 signonCount = aSignonsFound->Length();
for (PRUint32 i = 0; i < signonCount; ++i) {
SignonData &sd = aSignonsFound->ElementAt(i);
::CoTaskMemFree(sd.user); // |sd->user| is a pointer to the start of a buffer that also contains sd->pass
NS_Free(sd.realm);
}
aSignonsFound->Clear();
}
return NS_OK;
}
void
nsIEProfileMigrator::EnumerateUsernames(const nsAString& aKey, PRUnichar* aData, unsigned long aCount, nsVoidArray* aSignonsFound)
nsIEProfileMigrator::EnumerateUsernames(const nsAString& aKey, PRUnichar* aData, unsigned long aCount, nsTArray<SignonData>* aSignonsFound)
{
nsCOMPtr<nsILoginManagerIEMigrationHelper> pwmgr(
do_GetService("@mozilla.org/login-manager/storage/legacy;1"));
@ -1110,19 +1133,19 @@ nsIEProfileMigrator::EnumerateUsernames(const nsAString& aKey, PRUnichar* aData,
return;
PRUnichar* cursor = aData;
PRInt32 offset = 0;
PRInt32 signonCount = aSignonsFound->Count();
PRUint32 offset = 0;
PRUint32 signonCount = aSignonsFound->Length();
while (offset < aCount) {
nsAutoString curr; curr = cursor;
// Compare the value at the current cursor position with the collected list of signons
for (PRInt32 i = 0; i < signonCount; ++i) {
SignonData* sd = (SignonData*)aSignonsFound->ElementAt(i);
if (curr.Equals(sd->user)) {
for (PRUint32 i = 0; i < signonCount; ++i) {
SignonData &sd = aSignonsFound->ElementAt(i);
if (curr.Equals(sd.user)) {
// Bingo! Found a username in the saved data for this item. Now, add a Signon.
nsDependentString usernameStr(sd->user), passStr(sd->pass);
nsAutoString realm(NS_ConvertUTF8toUTF16(sd->realm));
nsDependentString usernameStr(sd.user), passStr(sd.pass);
nsAutoString realm(NS_ConvertUTF8toUTF16(sd.realm));
nsresult rv;

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

@ -45,7 +45,7 @@
#include <windows.h>
#include "nsIBrowserProfileMigrator.h"
#include "nsIObserverService.h"
#include "nsVoidArray.h"
#include "nsTArray.h"
#include "nsINavHistoryService.h"
class nsIFile;
@ -54,6 +54,12 @@ class nsIRDFResource;
class nsINavBookmarksService;
class nsIPrefBranch;
struct SignonData {
PRUnichar* user;
PRUnichar* pass;
char* realm;
};
#import PSTOREC_DLL raw_interfaces_only
using namespace PSTORECLib;
@ -79,9 +85,9 @@ protected:
nsresult CopyPasswords(PRBool aReplace);
nsresult MigrateSiteAuthSignons(IPStore* aPStore);
nsresult GetSignonsListFromPStore(IPStore* aPStore, nsVoidArray* aSignonsFound);
nsresult ResolveAndMigrateSignons(IPStore* aPStore, nsVoidArray* aSignonsFound);
void EnumerateUsernames(const nsAString& aKey, PRUnichar* aData, unsigned long aCount, nsVoidArray* aSignonsFound);
nsresult GetSignonsListFromPStore(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound);
nsresult ResolveAndMigrateSignons(IPStore* aPStore, nsTArray<SignonData>* aSignonsFound);
void EnumerateUsernames(const nsAString& aKey, PRUnichar* aData, unsigned long aCount, nsTArray<SignonData>* aSignonsFound);
void GetUserNameAndPass(unsigned char* data, unsigned long len, unsigned char** username, unsigned char** pass);
nsresult CopyFormData(PRBool aReplace);

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

@ -695,7 +695,7 @@ nsOperaCookieMigrator::Migrate()
mStream->ReadBytes(length, &buf);
buf = (char*)nsMemory::Realloc(buf, length+1);
buf[length] = '\0';
mDomainStack.AppendElement((void*)buf);
mDomainStack.AppendElement(buf);
}
break;
case END_DOMAIN_SEGMENT:
@ -704,9 +704,9 @@ nsOperaCookieMigrator::Migrate()
AddCookieOverride(permissionManager);
// Pop the domain stack
PRUint32 count = mDomainStack.Count();
PRUint32 count = mDomainStack.Length();
if (count > 0) {
char* segment = (char*)mDomainStack.ElementAt(count - 1);
char* segment = mDomainStack.ElementAt(count - 1);
if (segment)
nsMemory::Free(segment);
mDomainStack.RemoveElementAt(count - 1);
@ -724,7 +724,7 @@ nsOperaCookieMigrator::Migrate()
mStream->ReadBytes(length, &buf);
buf = (char*)nsMemory::Realloc(buf, length+1);
buf[length] = '\0';
mPathStack.AppendElement((void*)buf);
mPathStack.AppendElement(buf);
}
break;
case END_PATH_SEGMENT:
@ -737,9 +737,9 @@ nsOperaCookieMigrator::Migrate()
// i.e. telling us that we are done processing cookies for "/"
// Pop the path stack
PRUint32 count = mPathStack.Count();
PRUint32 count = mPathStack.Length();
if (count > 0) {
char* segment = (char*)mPathStack.ElementAt(count - 1);
char* segment = mPathStack.ElementAt(count - 1);
if (segment)
nsMemory::Free(segment);
mPathStack.RemoveElementAt(count - 1);
@ -849,17 +849,17 @@ nsOperaCookieMigrator::Migrate()
// Make sure the path and domain stacks are clear.
char* segment = nsnull;
PRUint32 i;
PRUint32 count = mPathStack.Count();
PRUint32 count = mPathStack.Length();
for (i = 0; i < count; ++i) {
segment = (char*)mPathStack.ElementAt(i);
segment = mPathStack.ElementAt(i);
if (segment) {
nsMemory::Free(segment);
segment = nsnull;
}
}
count = mDomainStack.Count();
count = mDomainStack.Length();
for (i = 0; i < count; ++i) {
segment = (char*)mDomainStack.ElementAt(i);
segment = mDomainStack.ElementAt(i);
if (segment) {
nsMemory::Free(segment);
segment = nsnull;
@ -923,10 +923,10 @@ nsOperaCookieMigrator::AddCookie(nsICookieManager2* aManager)
void
nsOperaCookieMigrator::SynthesizePath(char** aResult)
{
PRUint32 count = mPathStack.Count();
PRUint32 count = mPathStack.Length();
nsCAutoString synthesizedPath("/");
for (PRUint32 i = 0; i < count; ++i) {
synthesizedPath.Append((char*)mPathStack.ElementAt(i));
synthesizedPath.Append(mPathStack.ElementAt(i));
if (i != count-1)
synthesizedPath.Append("/");
}
@ -939,13 +939,13 @@ nsOperaCookieMigrator::SynthesizePath(char** aResult)
void
nsOperaCookieMigrator::SynthesizeDomain(char** aResult)
{
PRUint32 count = mDomainStack.Count();
PRUint32 count = mDomainStack.Length();
if (count == 0)
return;
nsCAutoString synthesizedDomain;
for (PRInt32 i = (PRInt32)count - 1; i >= 0; --i) {
synthesizedDomain.Append((char*)mDomainStack.ElementAt((PRUint32)i));
synthesizedDomain.Append(mDomainStack.ElementAt((PRUint32)i));
if (i != 0)
synthesizedDomain.Append(".");
}

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

@ -44,7 +44,7 @@
#include "nsIObserverService.h"
#include "nsISupportsArray.h"
#include "nsStringAPI.h"
#include "nsVoidArray.h"
#include "nsTArray.h"
#include "nsINavHistoryService.h"
class nsICookieManager2;
@ -180,8 +180,8 @@ protected:
private:
nsCOMPtr<nsIBinaryInputStream> mStream;
nsVoidArray mDomainStack;
nsVoidArray mPathStack;
nsTArray<char*> mDomainStack;
nsTArray<char*> mPathStack;
struct Cookie {
nsCString id;

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

@ -48,7 +48,6 @@
class nsIFile;
class nsIPrefBranch;
class nsIPrefService;
class nsVoidArray;
class nsPhoenixProfileMigrator : public nsNetscapeProfileMigratorBase,
public nsIBrowserProfileMigrator

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

@ -49,7 +49,6 @@
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsSeamonkeyProfileMigrator.h"
#include "nsVoidArray.h"
#include "nsIProfileMigrator.h"
///////////////////////////////////////////////////////////////////////////////
@ -479,10 +478,8 @@ nsSeamonkeyProfileMigrator::TransformPreferences(const nsAString& aSourcePrefFil
for (transform = gTransforms; transform < end; ++transform)
transform->prefGetterFunc(transform, branch);
nsVoidArray* fontPrefs = new nsVoidArray();
if (!fontPrefs)
return NS_ERROR_OUT_OF_MEMORY;
ReadFontsBranch(psvc, fontPrefs);
nsTArray<FontPref> fontPrefs;
ReadFontsBranch(psvc, &fontPrefs);
// Now that we have all the pref data in memory, load the target pref file,
// and write it back out
@ -490,9 +487,7 @@ nsSeamonkeyProfileMigrator::TransformPreferences(const nsAString& aSourcePrefFil
for (transform = gTransforms; transform < end; ++transform)
transform->prefSetterFunc(transform, branch);
WriteFontsBranch(psvc, fontPrefs);
delete fontPrefs;
fontPrefs = nsnull;
WriteFontsBranch(psvc, &fontPrefs);
nsCOMPtr<nsIFile> targetPrefsFile;
mTargetProfile->Clone(getter_AddRefs(targetPrefsFile));
@ -505,20 +500,9 @@ nsSeamonkeyProfileMigrator::TransformPreferences(const nsAString& aSourcePrefFil
return NS_OK;
}
struct FontPref {
char* prefName;
PRInt32 type;
union {
char* stringValue;
PRInt32 intValue;
PRBool boolValue;
PRUnichar* wstringValue;
};
};
void
nsSeamonkeyProfileMigrator::ReadFontsBranch(nsIPrefService* aPrefService,
nsVoidArray* aPrefs)
nsTArray<FontPref>* aPrefs)
{
// Enumerate the branch
nsCOMPtr<nsIPrefBranch> branch;
@ -534,7 +518,7 @@ nsSeamonkeyProfileMigrator::ReadFontsBranch(nsIPrefService* aPrefService,
char* currPref = prefs[i];
PRInt32 type;
branch->GetPrefType(currPref, &type);
FontPref* pref = new FontPref;
FontPref* pref = aPrefs->AppendElement();
pref->prefName = currPref;
pref->type = type;
switch (type) {
@ -559,14 +543,14 @@ nsSeamonkeyProfileMigrator::ReadFontsBranch(nsIPrefService* aPrefService,
break;
}
if (NS_SUCCEEDED(rv))
aPrefs->AppendElement((void*)pref);
if (NS_FAILED(rv))
aPrefs->RemoveElementAt(aPrefs->Length()-1);
}
}
void
nsSeamonkeyProfileMigrator::WriteFontsBranch(nsIPrefService* aPrefService,
nsVoidArray* aPrefs)
nsTArray<FontPref>* aPrefs)
{
nsresult rv;
@ -574,35 +558,32 @@ nsSeamonkeyProfileMigrator::WriteFontsBranch(nsIPrefService* aPrefService,
nsCOMPtr<nsIPrefBranch> branch;
aPrefService->GetBranch("font.", getter_AddRefs(branch));
PRUint32 count = aPrefs->Count();
PRUint32 count = aPrefs->Length();
for (PRUint32 i = 0; i < count; ++i) {
FontPref* pref = (FontPref*)aPrefs->ElementAt(i);
switch (pref->type) {
FontPref &pref = aPrefs->ElementAt(i);
switch (pref.type) {
case nsIPrefBranch::PREF_STRING:
rv = branch->SetCharPref(pref->prefName, pref->stringValue);
NS_Free(pref->stringValue);
pref->stringValue = nsnull;
rv = branch->SetCharPref(pref.prefName, pref.stringValue);
NS_Free(pref.stringValue);
pref.stringValue = nsnull;
break;
case nsIPrefBranch::PREF_BOOL:
rv = branch->SetBoolPref(pref->prefName, pref->boolValue);
rv = branch->SetBoolPref(pref.prefName, pref.boolValue);
break;
case nsIPrefBranch::PREF_INT:
rv = branch->SetIntPref(pref->prefName, pref->intValue);
rv = branch->SetIntPref(pref.prefName, pref.intValue);
break;
case nsIPrefBranch::PREF_INVALID:
nsCOMPtr<nsIPrefLocalizedString> pls(do_CreateInstance("@mozilla.org/pref-localizedstring;1"));
pls->SetData(pref->wstringValue);
rv = branch->SetComplexValue(pref->prefName,
pls->SetData(pref.wstringValue);
rv = branch->SetComplexValue(pref.prefName,
NS_GET_IID(nsIPrefLocalizedString),
pls);
NS_Free(pref->wstringValue);
pref->wstringValue = nsnull;
NS_Free(pref.wstringValue);
pref.wstringValue = nsnull;
break;
}
NS_Free(pref->prefName);
pref->prefName = nsnull;
delete pref;
pref = nsnull;
NS_Free(pref.prefName);
}
aPrefs->Clear();
}

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

@ -44,11 +44,22 @@
#include "nsISupportsArray.h"
#include "nsNetscapeProfileMigratorBase.h"
#include "nsStringAPI.h"
#include "nsTArray.h"
class nsIFile;
class nsIPrefBranch;
class nsIPrefService;
class nsVoidArray;
struct FontPref {
char* prefName;
PRInt32 type;
union {
char* stringValue;
PRInt32 intValue;
PRBool boolValue;
PRUnichar* wstringValue;
};
};
class nsSeamonkeyProfileMigrator : public nsNetscapeProfileMigratorBase,
public nsIBrowserProfileMigrator
@ -72,8 +83,10 @@ protected:
nsresult CopyPreferences(PRBool aReplace);
nsresult TransformPreferences(const nsAString& aSourcePrefFileName,
const nsAString& aTargetPrefFileName);
void ReadFontsBranch(nsIPrefService* aPrefService, nsVoidArray* aPrefs);
void WriteFontsBranch(nsIPrefService* aPrefService, nsVoidArray* aPrefs);
void ReadFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs);
void WriteFontsBranch(nsIPrefService* aPrefService,
nsTArray<FontPref>* aPrefs);
nsresult CopyUserContentSheet();

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

@ -45,6 +45,8 @@ const Cc = Components.classes;
const Cr = Components.results;
const Cu = Components.utils;
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/distribution.js");
@ -1037,6 +1039,22 @@ GeolocationPrompt.prototype = {
prompt: function(request) {
var prefService = Cc["@mozilla.org/content-pref/service;1"].getService(Ci.nsIContentPrefService);
if (prefService.hasPref(request.requestingURI, "geo.request.remember")) {
if (prefService.getPref(request.requestingURI, "geo.request.remember"))
request.allow();
else
request.cancel();
return;
}
function setPagePermission(uri, allow) {
var prefService = Cc["@mozilla.org/content-pref/service;1"].getService(Ci.nsIContentPrefService);
prefService.setPref(uri, "geo.request.remember", allow);
}
function getChromeWindow(aWindow) {
var chromeWin = aWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
@ -1050,7 +1068,8 @@ GeolocationPrompt.prototype = {
}
var requestingWindow = request.requestingWindow.top;
var tabbrowser = getChromeWindow(requestingWindow).wrappedJSObject.gBrowser;
var chromeWindowObject = getChromeWindow(requestingWindow).wrappedJSObject;
var tabbrowser = chromeWindowObject.gBrowser;
var browser = tabbrowser.getBrowserForDocument(requestingWindow.document);
var notificationBox = tabbrowser.getNotificationBox(browser);
@ -1060,23 +1079,57 @@ GeolocationPrompt.prototype = {
var browserBundle = bundleService.createBundle("chrome://browser/locale/browser.properties");
var buttons = [{
label: browserBundle.GetStringFromName("geolocation.tellThem"),
accessKey: browserBundle.GetStringFromName("geolocation.tellThemKey"),
callback: function() request.allow() ,
},
{
label: browserBundle.GetStringFromName("geolocation.dontTellThem"),
accessKey: browserBundle.GetStringFromName("geolocation.dontTellThemKey"),
callback: function() request.cancel() ,
}];
label: browserBundle.GetStringFromName("geolocation.tellThem"),
accessKey: browserBundle.GetStringFromName("geolocation.tellThemKey"),
callback: function(notification) {
if (notification.getElementsByClassName("rememberChoice")[0].checked)
setPagePermission(request.requestingURI, true);
request.allow();
},
},
{
label: browserBundle.GetStringFromName("geolocation.dontTellThem"),
accessKey: browserBundle.GetStringFromName("geolocation.dontTellThemKey"),
callback: function(notification) {
if (notification.getElementsByClassName("rememberChoice")[0].checked)
setPagePermission(request.requestingURI, false);
request.cancel();
},
}];
var message = browserBundle.formatStringFromName("geolocation.siteWantsToKnow",
[request.requestingURI.spec], 1);
notificationBox.appendNotification(message,
"geolocation",
"chrome://browser/skin/Info.png",
notificationBox.PRIORITY_INFO_HIGH,
buttons);
[request.requestingURI.host], 1);
var newBar = notificationBox.appendNotification(message,
"geolocation",
"chrome://browser/skin/Geo.png",
notificationBox.PRIORITY_INFO_HIGH,
buttons);
// For whatever reason, if we do this immediately
// (eg, without the setTimeout), the "link"
// element does not show up in the notification
// bar.
function geolocation_hacks_to_notification () {
var checkbox = newBar.ownerDocument.createElementNS(XULNS, "checkbox");
checkbox.className = "rememberChoice";
checkbox.setAttribute("label", browserBundle.GetStringFromName("geolocation.remember"));
newBar.appendChild(checkbox);
var link = newBar.ownerDocument.createElementNS(XULNS, "label");
link.className = "text-link";
link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore"));
var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
var description = newBar.ownerDocument.getAnonymousElementByAttribute(newBar, "anonid", "messageText");
description.appendChild(link);
};
chromeWindowObject.setTimeout(geolocation_hacks_to_notification, 0);
}
},
};

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

@ -54,7 +54,7 @@
<dialog id="bookmarkproperties"
buttons="accept, cancel"
defaultButton=""
defaultButton="none"
ondialogaccept="BookmarkPropertiesPanel.onDialogAccept();"
ondialogcancel="BookmarkPropertiesPanel.onDialogCancel();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"

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

@ -63,7 +63,7 @@
<hbox align="center">
<label value="&search.label;" accesskey="&search.accesskey;" control="search-box"/>
<textbox id="search-box" flex="1" type="search" cocoa-size="small"
<textbox id="search-box" flex="1" type="search" class="compact"
aria-controls="bookmarks-view"
oncommand="searchBookmarks(this.value);"/>
</hbox>

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

@ -127,10 +127,18 @@ PlacesController.prototype = {
case "cmd_redo":
return PlacesUIUtils.ptm.numberOfRedoItems > 0;
case "cmd_cut":
var nodes = this._view.getSelectionNodes();
// If selection includes history nodes there's no reason to allow cut.
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].itemId == -1)
return false;
}
// Otherwise fallback to cmd_delete check.
case "cmd_delete":
return this._hasRemovableSelection(false);
case "placesCmd_deleteDataHost":
return this._hasRemovableSelection(false);
return this._hasRemovableSelection(false) &&
!PlacesUIUtils.privateBrowsing.privateBrowsingEnabled;
case "placesCmd_moveBookmarks":
return this._hasRemovableSelection(true);
case "cmd_copy":
@ -230,10 +238,8 @@ PlacesController.prototype = {
this.remove("Remove Selection");
break;
case "placesCmd_deleteDataHost":
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let uri = PlacesUtils._uri(this._view.selectedNode.uri);
pb.removeDataFromDomain(uri.host);
PlacesUIUtils.privateBrowsing.removeDataFromDomain(uri.host);
break;
case "cmd_selectAll":
this.selectAll();
@ -581,6 +587,8 @@ PlacesController.prototype = {
* attribute are set.
* 7) These attributes should not be set on separators for which the
* visibility state is "auto-detected."
* 8) The "hideifprivatebrowsing" attribute may be set on a menu-item to
* true if it should be hidden inside the private browsing mode
* @param aPopup
* The menupopup to build children into.
* @return true if at least one item is visible, false otherwise.
@ -597,8 +605,11 @@ PlacesController.prototype = {
var item = aPopup.childNodes[i];
if (item.localName != "menuseparator") {
// We allow pasting into tag containers, so special case that.
item.hidden = (item.getAttribute("hideifnoinsertionpoint") == "true" &&
noIp && !(ip && ip.isTag && item.id == "placesContext_paste")) ||
var hideIfNoIP = item.getAttribute("hideifnoinsertionpoint") == "true" &&
noIp && !(ip && ip.isTag && item.id == "placesContext_paste");
var hideIfPB = item.getAttribute("hideifprivatebrowsing") == "true" &&
PlacesUIUtils.privateBrowsing.privateBrowsingEnabled;
item.hidden = hideIfNoIP || hideIfPB ||
!this._shouldShowMenuItem(item, metadata);
if (!item.hidden) {
@ -897,18 +908,18 @@ PlacesController.prototype = {
if (this._shouldSkipNode(node, removedFolders))
continue;
if (PlacesUtils.nodeIsFolder(node))
removedFolders.push(node);
else if (PlacesUtils.nodeIsTagQuery(node.parent)) {
if (PlacesUtils.nodeIsTagQuery(node.parent)) {
// This is a uri node inside a tag container. It needs a special
// untag transaction.
var tagItemId = PlacesUtils.getConcreteItemId(node.parent);
var uri = PlacesUtils._uri(node.uri);
transactions.push(PlacesUIUtils.ptm.untagURI(uri, [tagItemId]));
continue;
}
else if (PlacesUtils.nodeIsTagQuery(node) && node.parent &&
PlacesUtils.nodeIsQuery(node.parent) &&
asQuery(node.parent).queryOptions.resultType ==
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY) {
// This is a tag container.
// Untag all URIs tagged with this tag only if the tag container is
// child of the "Tags" query in the library, in all other places we
// must only remove the query node.
@ -916,19 +927,35 @@ PlacesController.prototype = {
var URIs = PlacesUtils.tagging.getURIsForTag(tag);
for (var j = 0; j < URIs.length; j++)
transactions.push(PlacesUIUtils.ptm.untagURI(URIs[j], [tag]));
continue;
}
else if (PlacesUtils.nodeIsQuery(node.parent) &&
else if (PlacesUtils.nodeIsURI(node) &&
PlacesUtils.nodeIsQuery(node.parent) &&
asQuery(node.parent).queryOptions.queryType ==
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY &&
node.uri) {
// remove page from history, history deletes are not undoable
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
// This is a uri node inside an history query.
var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
bhist.removePage(PlacesUtils._uri(node.uri));
continue;
// History deletes are not undoable, so we don't have a transaction.
}
else if (node.itemId == -1 &&
PlacesUtils.nodeIsQuery(node) &&
asQuery(node).queryOptions.queryType ==
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
// This is a dynamically generated history query, like queries
// grouped by site, time or both. Dynamically generated queries don't
// have an itemId even if they are descendants of a bookmark.
this._removeHistoryContainer(node);
// History deletes are not undoable, so we don't have a transaction.
}
else {
// This is a common bookmark item.
if (PlacesUtils.nodeIsFolder(node)) {
// If this is a folder we add it to our array of folders, used
// to skip nodes that are children of an already removed folder.
removedFolders.push(node);
}
transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
}
transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
}
},
@ -965,24 +992,17 @@ PlacesController.prototype = {
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];
if (PlacesUtils.nodeIsHost(node))
bhist.removePagesFromHost(node.title, true);
else if (PlacesUtils.nodeIsURI(node)) {
if (PlacesUtils.nodeIsURI(node)) {
var uri = PlacesUtils._uri(node.uri);
// avoid trying to delete the same url twice
if (URIs.indexOf(uri) < 0) {
URIs.push(uri);
}
}
else if (PlacesUtils.nodeIsDay(node)) {
var query = node.getQueries({})[0];
var beginTime = query.beginTime;
var endTime = query.endTime;
NS_ASSERT(query && beginTime && endTime,
"A valid date container query should exist!");
// We want to exclude beginTime from the removal
bhist.removePagesByTimeframe(beginTime+1, endTime);
}
else if (PlacesUtils.nodeIsQuery(node) &&
asQuery(node).queryOptions.queryType ==
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
this._removeHistoryContainer(node);
}
// if we have to delete a lot of urls RemovePage will be slow, it's better
@ -1005,6 +1025,32 @@ PlacesController.prototype = {
}
},
/**
* Removes history visits for an history container node.
* @param [in] aContainerNode
* The container node to remove.
*/
_removeHistoryContainer: function PC_removeHistoryContainer(aContainerNode) {
var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
if (PlacesUtils.nodeIsHost(aContainerNode)) {
// Site container.
bhist.removePagesFromHost(aContainerNode.title, true);
}
else if (PlacesUtils.nodeIsDay(aContainerNode)) {
// Day container.
var query = aContainerNode.getQueries({})[0];
var beginTime = query.beginTime;
var endTime = query.endTime;
NS_ASSERT(query && beginTime && endTime,
"A valid date container query should exist!");
// We want to exclude beginTime from the removal because
// removePagesByTimeframe includes both extremes, while date containers
// exclude the lower extreme. So, if we would not exclude it, we would
// end up removing more history than requested.
bhist.removePagesByTimeframe(beginTime+1, endTime);
}
},
/**
* Removes the selection
* @param aTxnName
@ -1095,7 +1141,8 @@ PlacesController.prototype = {
createInstance(Ci.nsITransferable);
var foundFolder = false, foundLink = false;
var copiedFolders = [];
var placeString = mozURLString = htmlString = unicodeString = "";
var placeString, mozURLString, htmlString, unicodeString;
placeString = mozURLString = htmlString = unicodeString = "";
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];

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

@ -228,7 +228,6 @@ var gEditItemOverlay = {
// tags selector
this._rebuildTagsSelectorList();
this._initialized = true;
}
// name picker
@ -243,6 +242,8 @@ var gEditItemOverlay = {
window.addEventListener("unload", this, false);
this._observersAdded = true;
}
this._initialized = true;
},
_getCommonTags: function(aArrIndex) {
@ -583,10 +584,10 @@ var gEditItemOverlay = {
tagsToAdd.push(tags[i]);
}
if (tagsToAdd.length > 0)
txns.push(PlacesUIUtils.ptm.tagURI(this._uri, tagsToAdd));
if (tagsToRemove.length > 0)
txns.push(PlacesUIUtils.ptm.untagURI(this._uri, tagsToRemove));
if (tagsToAdd.length > 0)
txns.push(PlacesUIUtils.ptm.tagURI(this._uri, tagsToAdd));
if (txns.length > 0) {
var aggregate = PlacesUIUtils.ptm.aggregateTransactions("Update tags",
@ -720,7 +721,7 @@ var gEditItemOverlay = {
ptm.doTransaction(aggregate);
},
onDescriptionFieldBlur: function EIO_onDescriptionFieldInput() {
onDescriptionFieldBlur: function EIO_onDescriptionFieldBlur() {
var description = this._element("descriptionField").value;
if (description != PlacesUIUtils.getItemDescription(this._itemId)) {
var txn = PlacesUIUtils.ptm
@ -809,7 +810,7 @@ var gEditItemOverlay = {
// breaks the view.
const FOLDER_TREE_PLACE_URI =
"place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
window.top.PlacesUIUtils.allBookmarksFolderId;
PlacesUIUtils.allBookmarksFolderId;
this._folderTree.place = FOLDER_TREE_PLACE_URI;
this._element("chooseFolderSeparator").hidden =
@ -841,7 +842,8 @@ var gEditItemOverlay = {
var menupopup = this._folderMenuList.menupopup;
for (var i=0; i < menupopup.childNodes.length; i++) {
if (menupopup.childNodes[i].folderId == aFolderId)
if (menupopup.childNodes[i].folderId &&
menupopup.childNodes[i].folderId == aFolderId)
return menupopup.childNodes[i];
}

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

@ -86,7 +86,7 @@
<hbox align="center">
<label value="&find.label;" accesskey="&find.accesskey;"
control="search-box"/>
<textbox id="search-box" flex="1" type="search" cocoa-size="small"
<textbox id="search-box" flex="1" type="search" class="compact"
aria-controls="historyTree"
oncommand="searchHistory(this.value);"/>
<button id="viewButton" style="min-width:0px !important;" type="menu"

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

@ -7,6 +7,15 @@ hbox[type="places"] {
overflow: hidden;
}
.bookmarks-toolbar-customize,
toolbarpaletteitem .bookmarks-toolbar-items {
display: none;
}
toolbarpaletteitem .bookmarks-toolbar-customize {
display: -moz-box;
}
menupopup[type="places"] {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-menupopup");
}

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

@ -481,6 +481,7 @@ var PlacesOrganizer = {
Ci.nsIFilePicker.modeOpen);
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
fp.appendFilters(Ci.nsIFilePicker.filterAll);
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
@ -688,6 +689,16 @@ var PlacesOrganizer = {
gEditItemOverlay.initPanel(itemId, { hiddenRows: ["folderPicker"],
forceReadOnly: readOnly });
// Dynamically generated queries, like history date containers, have
// itemId !=0 and do not exist in history. For them the panel is
// read-only, but empty, since it can't get a valid title for the object.
// In such a case we force the title using the selectedNode one, for UI
// polishness.
if (aSelectedNode.itemId == -1 &&
(PlacesUtils.nodeIsDay(aSelectedNode) ||
PlacesUtils.nodeIsHost(aSelectedNode)))
gEditItemOverlay._element("namePicker").value = aSelectedNode.title;
this._detectAndSetDetailsPaneMinimalState(aSelectedNode);
}
else if (!aSelectedNode && aNodeList[0]) {
@ -891,10 +902,6 @@ var PlacesSearchBox = {
//scopeBtn.label = PlacesOrganizer._places.selectedNode.title;
break;
case "bookmarks":
// Make sure we're getting uri results.
// We do not yet support searching into grouped queries or into
// tag containers, so we must fall to the default case.
currentOptions.resultType = currentOptions.RESULT_TYPE_URI;
content.applyFilter(filterString, this.folders);
break;
case "history":
@ -902,6 +909,8 @@ var PlacesSearchBox = {
var query = PlacesUtils.history.getNewQuery();
query.searchTerms = filterString;
var options = currentOptions.clone();
// Make sure we're getting uri results.
options.resultType = currentOptions.RESULT_TYPE_URI;
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
content.load([query], options);
}

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

@ -191,14 +191,12 @@
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
command="OrganizerCommand:Back"
tooltiptext="&backButton.tooltip;"
accesskey="&backCmd.accesskey;"
chromedir="&locale.dir;"
disabled="true"/>
<toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
command="OrganizerCommand:Forward"
tooltiptext="&forwardButton.tooltip;"
accesskey="&forwardCmd.accesskey;"
chromedir="&locale.dir;"
disabled="true"/>
@ -297,7 +295,7 @@
<!--
<menuitem id="viewDetails"
type="radio"
#ifdef MACOSX
#ifdef XP_MACOSX
label="&view.detailsMacOSX.label;"
#else
label="&view.details.label;"

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

@ -195,6 +195,8 @@
accesskey="&cmd.deleteDomainData.accesskey;"
closemenu="single"
selection="link"
selectiontype="single"
hideifprivatebrowsing="true"
forcehideselection="bookmark"/>
<menuseparator id="placesContext_deleteSeparator"/>
<menuitem id="placesContext_reload"

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

@ -64,7 +64,7 @@
<xul:hbox class="toolbar-drop-indicator"/>
</xul:hbox>
<xul:hbox flex="1">
<xul:hbox class="bookmarks-toolbar-items places-toolbar-items" flex="1">
<xul:hbox class="bookmarks-toolbar-items" flex="1">
<children/>
</xul:hbox>
<xul:toolbarbutton class="bookmark-item bookmarks-toolbar-customize"

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

@ -95,6 +95,14 @@
var queryNode = asQuery(this.getResultNode());
var options = queryNode.queryOptions.clone();
// Make sure we're getting uri results.
// We do not yet support searching into grouped queries or into
// tag containers, so we must fall to the default case.
if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
options.resultType == options.RESULTS_AS_TAG_QUERY ||
options.resultType == options.RESULTS_AS_TAG_CONTENTS)
options.resultType = options.RESULT_TYPE_URI;
var query = PlacesUtils.history.getNewQuery();
query.searchTerms = filterString;

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

@ -62,7 +62,7 @@ const LMANNO_FEEDURI = "livemark/feedURI";
const LMANNO_SITEURI = "livemark/siteURI";
const ORGANIZER_FOLDER_ANNO = "PlacesOrganizer/OrganizerFolder";
const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery";
const ORGANIZER_LEFTPANE_VERSION = 5;
const ORGANIZER_LEFTPANE_VERSION = 6;
const EXCLUDE_FROM_BACKUP_ANNO = "places/excludeFromBackup";
#ifdef XP_MACOSX
@ -129,6 +129,12 @@ var PlacesUIUtils = {
Ci.nsIPrefLocalizedString).data;
},
get privateBrowsing() {
delete this.privateBrowsing;
return this.privateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
},
/**
* Makes a URI from a spec, and do fixup
* @param aSpec
@ -1142,142 +1148,154 @@ var PlacesUIUtils = {
return this.leftPaneQueries;
},
// get the folder id for the organizer left-pane folder
// Get the folder id for the organizer left-pane folder.
get leftPaneFolderId() {
var leftPaneRoot = -1;
var allBookmarksId;
var items = PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
// Shortcuts to services.
var bs = PlacesUtils.bookmarks;
var as = PlacesUtils.annotations;
// Get all items marked as being the left pane folder. We should only have
// one of them.
var items = as.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
if (items.length > 1) {
// Something went wrong, we cannot have more than one left pane folder,
// remove all left pane folders and generate a correct new one.
items.forEach(function(aItem) {
PlacesUtils.bookmarks.removeItem(aItem);
});
// remove all left pane folders and continue. We will create a new one.
items.forEach(bs.removeItem);
}
else if (items.length == 1 && items[0] != -1) {
leftPaneRoot = items[0];
// check organizer left pane version
var version = PlacesUtils.annotations
.getItemAnnotation(leftPaneRoot, ORGANIZER_FOLDER_ANNO);
// Check organizer left pane version.
var version = as.getItemAnnotation(leftPaneRoot, ORGANIZER_FOLDER_ANNO);
if (version != ORGANIZER_LEFTPANE_VERSION) {
// If version is not valid we must rebuild the left pane.
PlacesUtils.bookmarks.removeItem(leftPaneRoot);
bs.removeItem(leftPaneRoot);
leftPaneRoot = -1;
}
}
var queriesTitles = {
"PlacesRoot": "",
"History": this.getString("OrganizerQueryHistory"),
// TODO: Bug 489681, Tags needs its own string in places.properties
"Tags": bs.getItemTitle(PlacesUtils.tagsFolderId),
"AllBookmarks": this.getString("OrganizerQueryAllBookmarks"),
"Downloads": this.getString("OrganizerQueryDownloads"),
"BookmarksToolbar": null,
"BookmarksMenu": null,
"UnfiledBookmarks": null
};
if (leftPaneRoot != -1) {
// Build the leftPaneQueries Map
// A valid left pane folder has been found.
// Build the leftPaneQueries Map. This is used to quickly access them
// associating a mnemonic name to the real item ids.
delete this.leftPaneQueries;
this.leftPaneQueries = {};
var items = PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_QUERY_ANNO, {});
for (var i=0; i < items.length; i++) {
var queryName = PlacesUtils.annotations
.getItemAnnotation(items[i], ORGANIZER_QUERY_ANNO);
var items = as.getItemsWithAnnotation(ORGANIZER_QUERY_ANNO, {});
// While looping through queries we will also check for titles validity.
for (var i = 0; i < items.length; i++) {
var queryName = as.getItemAnnotation(items[i], ORGANIZER_QUERY_ANNO);
Components.utils.reportError(items[i] + " " + queryName);
this.leftPaneQueries[queryName] = items[i];
// Titles could have been corrupted or the user could have changed his
// locale. Check title is correctly set and eventually fix it.
if (bs.getItemTitle(items[i]) != queriesTitles[queryName])
bs.setItemTitle(items[i], queriesTitles[queryName]);
}
delete this.leftPaneFolderId;
return this.leftPaneFolderId = leftPaneRoot;
}
var self = this;
const EXPIRE_NEVER = PlacesUtils.annotations.EXPIRE_NEVER;
var callback = {
runBatched: function(aUserData) {
// Helper to create an organizer special query.
create_query: function CB_create_query(aQueryName, aParentId, aQueryUrl) {
let itemId = bs.insertBookmark(aParentId,
PlacesUtils._uri(aQueryUrl),
bs.DEFAULT_INDEX,
queriesTitles[aQueryName]);
// Mark as special organizer query.
as.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO, aQueryName,
0, as.EXPIRE_NEVER);
// We should never backup this, since it changes between profiles.
as.setItemAnnotation(itemId, EXCLUDE_FROM_BACKUP_ANNO, 1,
0, as.EXPIRE_NEVER);
// Add to the queries map.
self.leftPaneQueries[aQueryName] = itemId;
return itemId;
},
// Helper to create an organizer special folder.
create_folder: function CB_create_folder(aFolderName, aParentId, aIsRoot) {
// Left Pane Root Folder.
let folderId = bs.createFolder(aParentId,
queriesTitles[aFolderName],
bs.DEFAULT_INDEX);
// We should never backup this, since it changes between profiles.
as.setItemAnnotation(folderId, EXCLUDE_FROM_BACKUP_ANNO, 1,
0, as.EXPIRE_NEVER);
// Disallow manipulating this folder within the organizer UI.
bs.setFolderReadonly(folderId, true);
if (aIsRoot) {
// Mark as special left pane root.
as.setItemAnnotation(folderId, ORGANIZER_FOLDER_ANNO,
ORGANIZER_LEFTPANE_VERSION,
0, as.EXPIRE_NEVER);
}
else {
// Mark as special organizer folder.
as.setItemAnnotation(folderId, ORGANIZER_QUERY_ANNO, aFolderName,
0, as.EXPIRE_NEVER);
self.leftPaneQueries[aFolderName] = folderId;
}
return folderId;
},
runBatched: function CB_runBatched(aUserData) {
delete self.leftPaneQueries;
self.leftPaneQueries = { };
// Left Pane Root Folder
leftPaneRoot = PlacesUtils.bookmarks.createFolder(PlacesUtils.placesRootId, "", -1);
// ensure immediate children can't be removed
PlacesUtils.bookmarks.setFolderReadonly(leftPaneRoot, true);
// Left Pane Root Folder.
leftPaneRoot = this.create_folder("PlacesRoot", bs.placesRoot, true);
// History Query
let uri = PlacesUtils._uri("place:sort=4&");
let title = self.getString("OrganizerQueryHistory");
let itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, title);
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"History", 0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["History"] = itemId;
// History Query.
this.create_query("History", leftPaneRoot,
"place:type=" +
Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY +
"&sort=" +
Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING);
// XXX: Downloads
// XXX: Downloads.
// Tags Query
uri = PlacesUtils._uri("place:type=" +
// Tags Query.
this.create_query("Tags", leftPaneRoot,
"place:type=" +
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
"&sort=" +
Ci.nsINavHistoryQueryOptions.SORT_BY_TITLE_ASCENDING);
title = PlacesUtils.bookmarks.getItemTitle(PlacesUtils.tagsFolderId);
itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, title);
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"Tags", 0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["Tags"] = itemId;
// All Bookmarks Folder
title = self.getString("OrganizerQueryAllBookmarks");
itemId = PlacesUtils.bookmarks.createFolder(leftPaneRoot, title, -1);
allBookmarksId = itemId;
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"AllBookmarks", 0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["AllBookmarks"] = itemId;
// All Bookmarks Folder.
allBookmarksId = this.create_folder("AllBookmarks", leftPaneRoot, false);
// disallow manipulating this folder within the organizer UI
PlacesUtils.bookmarks.setFolderReadonly(allBookmarksId, true);
// All Bookmarks->Bookmarks Toolbar Query.
this.create_query("BookmarksToolbar", allBookmarksId,
"place:folder=TOOLBAR");
// All Bookmarks->Bookmarks Toolbar Query
uri = PlacesUtils._uri("place:folder=TOOLBAR");
itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"BookmarksToolbar", 0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["BookmarksToolbar"] = itemId;
// All Bookmarks->Bookmarks Menu Query.
this.create_query("BookmarksMenu", allBookmarksId,
"place:folder=BOOKMARKS_MENU");
// All Bookmarks->Bookmarks Menu Query
uri = PlacesUtils._uri("place:folder=BOOKMARKS_MENU");
itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"BookmarksMenu", 0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["BookmarksMenu"] = itemId;
// All Bookmarks->Unfiled bookmarks
uri = PlacesUtils._uri("place:folder=UNFILED_BOOKMARKS");
itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
"UnfiledBookmarks", 0,
EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(itemId,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
self.leftPaneQueries["UnfiledBookmarks"] = itemId;
// disallow manipulating this folder within the organizer UI
PlacesUtils.bookmarks.setFolderReadonly(leftPaneRoot, true);
// All Bookmarks->Unfiled Bookmarks Query.
this.create_query("UnfiledBookmarks", allBookmarksId,
"place:folder=UNFILED_BOOKMARKS");
}
};
PlacesUtils.bookmarks.runInBatchMode(callback, null);
PlacesUtils.annotations.setItemAnnotation(leftPaneRoot,
ORGANIZER_FOLDER_ANNO,
ORGANIZER_LEFTPANE_VERSION,
0, EXPIRE_NEVER);
PlacesUtils.annotations.setItemAnnotation(leftPaneRoot,
EXCLUDE_FROM_BACKUP_ANNO,
1, 0, EXPIRE_NEVER);
bs.runInBatchMode(callback, null);
delete this.leftPaneFolderId;
return this.leftPaneFolderId = leftPaneRoot;
},

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

@ -51,12 +51,31 @@ interface nsIPlacesImportExportService: nsISupports
/**
* Loads the given bookmarks.html file and replaces it with the current
* bookmarks hierarchy (if aIsInitialImport is true) or appends it
* (if aIsInitialImport is false)
* (if aIsInitialImport is false).
*
* Three nsIObserverService notifications are fired as a result of the
* import. "bookmarks-restore-begin" is fired just before the import is
* started. "bookmarks-restore-success" is fired right after the
* bookmarks are successfully imported. "bookmarks-restore-failed" is
* fired right after a failure occurs when importing the bookmarks.
* Observers will be passed through their data parameters either "html"
* if aIsInitialImport is false or "html-initial" if aIsInitialImport is
* true. The observer subject will be null.
*/
void importHTMLFromFile(in nsILocalFile aFile, in boolean aIsInitialImport);
/**
* Loads the given bookmarks.html file and puts it in the given folder
*
* Three nsIObserverService notifications are fired as a result of the
* import. "bookmarks-restore-begin" is fired just before the import is
* started. "bookmarks-restore-success" is fired right after the
* bookmarks are successfully imported. "bookmarks-restore-failed" is
* fired right after a failure occurs when importing the bookmarks.
* Observers will be passed through their data parameters either "html"
* if aIsInitialImport is false or "html-initial" if aIsInitialImport is
* true. The observer subject will be an nsISupportsPRInt64 whose value
* is aFolder.
*/
void importHTMLFromFileToFolder(in nsILocalFile aFile, in PRInt64 aFolder, in boolean aIsInitialImport);

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

@ -22,6 +22,7 @@
* Contributor(s):
* Brett Wilson <brettw@gmail.com>
* Dietrich Ayala <dietrich@mozilla.com>
* Drew Willcoxon <adw@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
@ -102,8 +103,9 @@
#include "nsIHTMLContentSink.h"
#include "nsIParser.h"
#include "prprf.h"
#include "nsVoidArray.h"
#include "nsIBrowserGlue.h"
#include "nsIObserverService.h"
#include "nsISupportsPrimitives.h"
static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
@ -132,6 +134,14 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
#define BOOKMARKS_MENU_ICON_URI "chrome://browser/skin/places/bookmarksMenu.png"
// The RESTORE_*_NSIOBSERVER_TOPIC #defines should match the constants of the
// same names in toolkit/components/places/src/utils.js
#define RESTORE_BEGIN_NSIOBSERVER_TOPIC "bookmarks-restore-begin"
#define RESTORE_SUCCESS_NSIOBSERVER_TOPIC "bookmarks-restore-success"
#define RESTORE_FAILED_NSIOBSERVER_TOPIC "bookmarks-restore-failed"
#define RESTORE_NSIOBSERVER_DATA NS_LITERAL_STRING("html")
#define RESTORE_INITIAL_NSIOBSERVER_DATA NS_LITERAL_STRING("html-initial")
// define to get debugging messages on console about import/export
//#define DEBUG_IMPORT
//#define DEBUG_EXPORT
@ -2165,14 +2175,68 @@ nsPlacesImportExportService::WriteContainerContents(nsINavHistoryResultNode* aFo
return NS_OK;
}
// NotifyImportObservers
//
// Notifies bookmarks-restore observers using nsIObserverService. This
// function is void and we simply return on failure because we don't want
// the import itself to fail if notifying observers does.
static void
NotifyImportObservers(const char* aTopic,
PRInt64 aFolderId,
PRBool aIsInitialImport)
{
nsresult rv;
nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv))
return;
nsCOMPtr<nsISupports> folderIdSupp = nsnull;
if (aFolderId > 0) {
nsCOMPtr<nsISupportsPRInt64> folderIdInt =
do_CreateInstance(NS_SUPPORTS_PRINT64_CONTRACTID, &rv);
if (NS_FAILED(rv))
return;
rv = folderIdInt->SetData(aFolderId);
if (NS_FAILED(rv))
return;
folderIdSupp = do_QueryInterface(folderIdInt);
}
obs->NotifyObservers(folderIdSupp,
aTopic,
(aIsInitialImport ? RESTORE_INITIAL_NSIOBSERVER_DATA :
RESTORE_NSIOBSERVER_DATA).get());
}
// nsIPlacesImportExportService::ImportHTMLFromFile
//
NS_IMETHODIMP
nsPlacesImportExportService::ImportHTMLFromFile(nsILocalFile* aFile, PRBool aIsInitialImport)
{
NotifyImportObservers(RESTORE_BEGIN_NSIOBSERVER_TOPIC, -1, aIsInitialImport);
// this version is exposed on the interface and disallows changing of roots
return ImportHTMLFromFileInternal(aFile, PR_FALSE, 0, aIsInitialImport);
nsresult rv = ImportHTMLFromFileInternal(aFile,
PR_FALSE,
0,
aIsInitialImport);
if (NS_FAILED(rv)) {
NotifyImportObservers(RESTORE_FAILED_NSIOBSERVER_TOPIC,
-1,
aIsInitialImport);
}
else {
NotifyImportObservers(RESTORE_SUCCESS_NSIOBSERVER_TOPIC,
-1,
aIsInitialImport);
}
return rv;
}
// nsIPlacesImportExportService::ImportHTMLFromFileToFolder
@ -2180,8 +2244,28 @@ nsPlacesImportExportService::ImportHTMLFromFile(nsILocalFile* aFile, PRBool aIsI
NS_IMETHODIMP
nsPlacesImportExportService::ImportHTMLFromFileToFolder(nsILocalFile* aFile, PRInt64 aFolderId, PRBool aIsInitialImport)
{
NotifyImportObservers(RESTORE_BEGIN_NSIOBSERVER_TOPIC,
aFolderId,
aIsInitialImport);
// this version is exposed on the interface and disallows changing of roots
return ImportHTMLFromFileInternal(aFile, PR_FALSE, aFolderId, aIsInitialImport);
nsresult rv = ImportHTMLFromFileInternal(aFile,
PR_FALSE,
aFolderId,
aIsInitialImport);
if (NS_FAILED(rv)) {
NotifyImportObservers(RESTORE_FAILED_NSIOBSERVER_TOPIC,
aFolderId,
aIsInitialImport);
}
else {
NotifyImportObservers(RESTORE_SUCCESS_NSIOBSERVER_TOPIC,
aFolderId,
aIsInitialImport);
}
return rv;
}
nsresult

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

@ -22,6 +22,7 @@
* Contributor(s):
* Sungjoon Steve Won <stevewon@gmail.com> (Original Author)
* Asaf Romano <mano@mozilla.com>
* Marco Bonarco <mak77@bonardo.net>
*
* 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
@ -392,10 +393,12 @@ placesCreateFolderTransactions.prototype = {
},
undoTransaction: function PCFT_undoTransaction() {
for (var i = 0; i < this._childItemsTransactions.length; ++i) {
// Undo transactions should always be done in reverse order.
for (var i = this._childItemsTransactions.length - 1; i >= 0 ; i--) {
var txn = this._childItemsTransactions[i];
txn.undoTransaction();
}
// Remove item only after all child transactions have been reverted.
PlacesUtils.bookmarks.removeFolder(this._id);
}
};
@ -436,11 +439,13 @@ placesCreateItemTransactions.prototype = {
},
undoTransaction: function PCIT_undoTransaction() {
PlacesUtils.bookmarks.removeItem(this._id);
for (var i = 0; i < this._childTransactions.length; ++i) {
// Undo transactions should always be done in reverse order.
for (var i = this._childTransactions.length - 1; i >= 0; i--) {
var txn = this._childTransactions[i];
txn.undoTransaction();
}
// Remove item only after all child transactions have been reverted.
PlacesUtils.bookmarks.removeItem(this._id);
}
};

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

@ -44,6 +44,8 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_0_library_left_pane_migration.js \
browser_library_left_pane_fixnames.js \
browser_425884.js \
browser_423515.js \
browser_410196_paste_into_tags.js \
@ -53,6 +55,9 @@ _BROWSER_TEST_FILES = \
browser_library_panel_leak.js \
browser_library_search.js \
browser_history_sidebar_search.js \
browser_bookmarksProperties.js \
browser_forgetthissite_single.js \
browser_library_left_pane_commands.js \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,144 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 Places test code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by devaring the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not devare
* 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 ***** */
/**
* Test we correctly migrate Library left pane to the latest version.
* Note: this test MUST be the first between browser chrome tests, or results
* of next tests could be unexpected due to PlacesUIUtils getters.
*/
const TEST_URI = "http://www.mozilla.org/";
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
ww.unregisterNotification(this);
var organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
organizer.addEventListener("load", function onLoad(event) {
organizer.removeEventListener("load", onLoad, false);
executeSoon(function () {
// Check left pane.
ok(PlacesUIUtils.leftPaneFolderId > 0,
"Left pane folder correctly created");
var leftPaneItems =
PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
is(leftPaneItems.length, 1,
"We correctly have only 1 left pane folder");
var leftPaneRoot = leftPaneItems[0];
is(leftPaneRoot, PlacesUIUtils.leftPaneFolderId,
"leftPaneFolderId getter has correct value");
// Check version has been upgraded.
var version =
PlacesUtils.annotations.getItemAnnotation(leftPaneRoot,
ORGANIZER_FOLDER_ANNO);
is(version, ORGANIZER_LEFTPANE_VERSION,
"Left pane version has been correctly upgraded");
// Check left pane is populated.
organizer.PlacesOrganizer.selectLeftPaneQuery('History');
is(organizer.PlacesOrganizer._places.selectedNode.itemId,
PlacesUIUtils.leftPaneQueries["History"],
"Library left pane is populated and working");
// Close Library window.
organizer.close();
// No need to cleanup anything, we have a correct left pane now.
finish();
});
}, false);
}
}
};
function test() {
waitForExplicitFinish();
// Sanity checks.
ok(PlacesUtils, "PlacesUtils is running in chrome context");
ok(PlacesUIUtils, "PlacesUIUtils is running in chrome context");
ok(ORGANIZER_LEFTPANE_VERSION > 0,
"Left pane version in chrome context, current version is: " + ORGANIZER_LEFTPANE_VERSION );
// Check if we have any left pane folder already set, remove it eventually.
var leftPaneItems = PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
if (leftPaneItems.length > 0) {
// The left pane has already been created, touching it now would cause
// next tests to rely on wrong values (and possibly crash)
is(leftPaneItems.length, 1, "We correctly have only 1 left pane folder");
// Check version.
var version = PlacesUtils.annotations.getItemAnnotation(leftPaneItems[0],
ORGANIZER_FOLDER_ANNO);
is(version, ORGANIZER_LEFTPANE_VERSION, "Left pane version is actual");
ok(true, "left pane has already been created, skipping test");
finish();
return;
}
// Create a fake left pane folder with an old version (current version - 1).
var fakeLeftPaneRoot =
PlacesUtils.bookmarks.createFolder(PlacesUtils.placesRootId, "",
PlacesUtils.bookmarks.DEFAULT_INDEX);
PlacesUtils.annotations.setItemAnnotation(fakeLeftPaneRoot,
ORGANIZER_FOLDER_ANNO,
ORGANIZER_LEFTPANE_VERSION - 1,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
// Check fake left pane root has been correctly created.
var leftPaneItems =
PlacesUtils.annotations.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
is(leftPaneItems.length, 1, "We correctly have only 1 left pane folder");
is(leftPaneItems[0], fakeLeftPaneRoot, "left pane root itemId is correct");
// Check version.
var version = PlacesUtils.annotations.getItemAnnotation(fakeLeftPaneRoot,
ORGANIZER_FOLDER_ANNO);
is(version, ORGANIZER_LEFTPANE_VERSION - 1, "Left pane version correctly set");
// Open Library, this will upgrade our left pane version.
ww.registerNotification(windowObserver);
ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
}

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

@ -91,7 +91,7 @@ function test() {
// need to add a history object
var testURI1 = PU._uri(MOZURISPEC);
isnot(testURI1, null, "testURI is not null");
visitId = add_visit(testURI1);
var visitId = add_visit(testURI1);
ok(visitId > 0, "A visit was added to the history");
ok(gh.isVisited(testURI1), MOZURISPEC + " is a visited url.");
},
@ -127,6 +127,9 @@ function test() {
copyHistNode: function (){
// focus the history object
PO.selectLeftPaneQuery("History");
var histContainer = PO._places.selectedNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
histContainer.containerOpen = true;
PO._places.selectNode(histContainer.getChild(0));
this.histNode = PO._content.view.nodeForTreeIndex(0);
PO._content.selectNode(this.histNode);
is(this.histNode.uri, MOZURISPEC,
@ -159,6 +162,9 @@ function test() {
historyNode: function (){
// re-focus the history again
PO.selectLeftPaneQuery("History");
var histContainer = PO._places.selectedNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
histContainer.containerOpen = true;
PO._places.selectNode(histContainer.getChild(0));
var histNode = PO._content.view.nodeForTreeIndex(0);
ok(histNode, "histNode exists: " + histNode.title);
// check to see if the history node is tagged!

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

@ -146,9 +146,14 @@ function test() {
var node = PlacesUtils.getFolderContents(PlacesUtils.placesRootId, false, true).root;
for (var i = 0; i < node.childCount; i++) {
var child = node.getChild(i);
if (child.itemId == aId)
if (child.itemId == aId) {
node.containerOpen = false;
return child;
}
}
node.containerOpen = false;
throw("Unable to find child node");
return null;
}
for (var i = 0; i < this.folders.length; i++) {
@ -157,8 +162,8 @@ function test() {
is(PlacesControllerDragHelper.canMoveContainer(id),
false, "shouldn't be able to move special folder id");
//var node = PlacesUtils.getFolderContents(id, false, true).root;
var node = getRootChildNode(id);
isnot(node, null, "Node found");
is(PlacesControllerDragHelper.canMoveNode(node),
false, "shouldn't be able to move special folder node");
@ -199,6 +204,8 @@ function test() {
is(PlacesControllerDragHelper.canMoveNode(tagNode),
false, "should not be able to move tag container node");
tagsNode.containerOpen = false;
}
});

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

@ -102,6 +102,10 @@ function test() {
folderBNode = testRootNode.getChild(1);
validate(folderBNode);
// Close containers, cleaning up their observers.
testRootNode.containerOpen = false;
toolbarNode.containerOpen = false;
// clean up
PlacesUIUtils.ptm.undoTransaction();
PlacesUtils.bookmarks.removeItem(folderAId);

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

@ -74,7 +74,7 @@ function test() {
var folderAGUIDs = getGUIDs(folderANode);
// test the test function
ok(checkGUIDs(folderANode, folderAGUIDs, true), "confirm guid test works");;
ok(checkGUIDs(folderANode, folderAGUIDs, true), "confirm guid test works");
// serialize the folder
var serializedNode = PlacesUtils.wrapNode(folderANode, PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER);
@ -115,6 +115,10 @@ function test() {
// in any new changes.
//ok(checkGUIDs(folderBNode, folderBGUIDs, true, true), "folder B GUIDs after under/redo should match pre-undo/redo folder B GUIDs");
// Close containers, cleaning up their observers.
testRootNode.containerOpen = false;
toolbarNode.containerOpen = false;
// clean up
PlacesUIUtils.ptm.undoTransaction();
PlacesUtils.bookmarks.removeItem(testRootId);

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

@ -0,0 +1,547 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net>
*
* 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 ***** */
/**
* Tests the bookmarks Properties dialog.
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
// DOM ids of Places sidebar trees.
const SIDEBAR_HISTORY_ID = "historyTree";
const SIDEBAR_BOOKMARKS_ID = "bookmarks-view";
// Action to execute on the current node.
const ACTION_EDIT = 0;
const ACTION_ADD = 1;
// If action is ACTION_ADD, set type to one of those, to define what do you
// want to create.
const TYPE_FOLDER = 0;
const TYPE_BOOKMARK = 1;
const TEST_URL = "http://www.mozilla.org/";
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
function add_visit(aURI, aDate) {
var visitId = PlacesUtils.history
.addVisit(aURI,
aDate,
null, // no referrer
PlacesUtils.history.TRANSITION_TYPED,
false, // not redirect
0);
return visitId;
}
function add_bookmark(aURI) {
var bId = PlacesUtils.bookmarks
.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
aURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark/" + aURI.spec);
return bId;
}
// Each test is an obj w/ a desc property and run method.
var gTests = [];
var gCurrentTest = null;
//------------------------------------------------------------------------------
// TEST SKELETON: use this template to add new tests.
/*
gTests.push({
desc: "Bug Description",
sidebar: SIDEBAR_BOOKMARKS_ID, // See SIDEBAR_ constants above.
action: ACTION_EDIT, // See ACTION_ constants above.
itemType: null, // See TYPE_ constants above, required for ACTION_ADD.
window: null, // Will contain handle of dialog window
setup: function() {
// Setup everything needed for this test, runs before everything else.
},
selectNode: function(tree) {
// Select the node to edit or to add to, runs when sidebar tree is visible.
},
run: function() {
// Actual test, runs when dialog is open.
},
finish: function() {
// Close window, toggle sidebar and goto next test.
this.window.document.documentElement.cancelDialog();
toggleSidebar("viewBookmarksSidebar", false);
runNextTest();
},
cleanup: function() {
// Undo everything added during setup, runs after dialog has been closed.
}
});
*/
//------------------------------------------------------------------------------
// Bug 479348 - Properties on a root should be read-only
gTests.push({
desc: "Bug 479348 - Properties on a root should be read-only",
sidebar: SIDEBAR_BOOKMARKS_ID,
action: ACTION_EDIT,
itemType: null,
window: null,
setup: function() {
// Nothing to do.
},
selectNode: function(tree) {
// Select Unfiled Bookmarks root.
var itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"];
tree.selectItems([itemId]);
this.selectedNode = tree.selectedNode;
},
run: function() {
// Check that the dialog is read-only.
ok(this.window.BookmarkPropertiesPanel._readOnly, "Dialog is read-only");
// Check that accept button is disabled
var acceptButton = this.window.document.documentElement.getButton("accept");
ok(acceptButton.disabled, "Accept button is disabled");
// Check that name picker is read only
var namepicker = this.window.document.getElementById("editBMPanel_namePicker");
ok(namepicker.readOnly, "Name field is disabled");
is(namepicker.value,
PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId),
"Node title is correct");
// Blur the field and ensure root's name has not been changed.
this.window.gEditItemOverlay.onNamePickerChange();
is(namepicker.value,
PlacesUtils.bookmarks.getItemTitle(PlacesUtils.unfiledBookmarksFolderId),
"Root title is correct");
// Check the shortcut's title.
is(PlacesUtils.bookmarks.getItemTitle(this.selectedNode.itemId), null,
"Shortcut title is null");
this.finish();
},
finish: function() {
this.window.document.documentElement.cancelDialog();
toggleSidebar("viewBookmarksSidebar", false);
runNextTest();
},
cleanup: function() {
// Nothing to do.
}
});
//------------------------------------------------------------------------------
// Bug 462662 - Pressing Enter to select tag from autocomplete closes bookmarks properties dialog
gTests.push({
desc: "Bug 462662 - Pressing Enter to select tag from autocomplete closes bookmarks properties dialog",
sidebar: SIDEBAR_BOOKMARKS_ID,
action: ACTION_EDIT,
itemType: null,
window: null,
_itemId: null,
setup: function() {
// Add a bookmark in unsorted bookmarks folder.
this._itemId = add_bookmark(PlacesUtils._uri(TEST_URL));
ok(this._itemId > 0, "Correctly added a bookmark");
// Add a tag to this bookmark.
PlacesUtils.tagging.tagURI(PlacesUtils._uri(TEST_URL),
["testTag"]);
var tags = PlacesUtils.tagging.getTagsForURI(PlacesUtils._uri(TEST_URL), {});
is(tags[0], "testTag", "Correctly added a tag");
},
selectNode: function(tree) {
tree.selectItems([this._itemId]);
is(tree.selectedNode.itemId, this._itemId, "Bookmark has been selected");
},
run: function() {
// open tags autocomplete and press enter
var tagsField = this.window.document.getElementById("editBMPanel_tagsField");
var self = this;
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowclosed") {
ww.unregisterNotification(this);
tagsField.popup.removeEventListener("popuphidden", popupListener, true);
ok(false, "Dialog window should not be closed by pressing Enter on the autocomplete popup");
self.finish();
}
}
};
var popupListener = {
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "popuphidden":
// Everything worked fine, we can stop observing the window.
ww.unregisterNotification(windowObserver);
tagsField.popup.removeEventListener("popuphidden", this, true);
self.window.document.documentElement.cancelDialog();
self.finish();
break;
case "popupshown":
tagsField.popup.removeEventListener("popupshown", this, true);
// In case this test fails the window will close, we should mark the
// failure and continue, to avoid timing out.
ww.registerNotification(windowObserver);
var tree = tagsField.popup.tree;
// Focus and select first result.
isnot(tree, null, "Autocomplete results tree exists");
is(tree.view.rowCount, 1, "We have 1 autocomplete result");
tagsField.popup.selectedIndex = 0;
is(tree.view.selection.count, 1,
"We have selected a tag from the autocomplete popup");
dump("About to focus the autocomplete results tree\n");
tree.focus();
EventUtils.synthesizeKey("VK_RETURN", {}, self.window);
break;
default:
ok(false, "unknown event: " + aEvent.type);
return;
}
}
};
tagsField.popup.addEventListener("popupshown", popupListener, true);
tagsField.popup.addEventListener("popuphidden", popupListener, true);
// Open tags autocomplete popup.
dump("About to focus the tagsField\n");
tagsField.focus();
tagsField.value = "";
EventUtils.synthesizeKey("t", {}, this.window);
},
finish: function() {
toggleSidebar("viewBookmarksSidebar", false);
runNextTest();
},
cleanup: function() {
// Check tags have not changed.
var tags = PlacesUtils.tagging.getTagsForURI(PlacesUtils._uri(TEST_URL), {});
is(tags[0], "testTag", "Tag on node has not changed");
// Cleanup.
PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["testTag"]);
PlacesUtils.bookmarks.removeItem(this._itemId);
}
});
//------------------------------------------------------------------------------
// Bug 475529 - Add button in new folder dialog not default anymore
gTests.push({
desc: "Bug 475529 - Add button in new folder dialog not default anymore",
sidebar: SIDEBAR_BOOKMARKS_ID,
action: ACTION_ADD,
itemType: TYPE_FOLDER,
window: null,
_itemId: null,
setup: function() {
// Nothing to do.
},
selectNode: function(tree) {
// Select Unfiled Bookmarks root.
var itemId = PlacesUIUtils.leftPaneQueries["UnfiledBookmarks"];
tree.selectItems([itemId]);
this.selectedNode = tree.selectedNode;
},
run: function() {
this._itemId = this.window.gEditItemOverlay._itemId;
// Change folder name
var namePicker = this.window.document.getElementById("editBMPanel_namePicker");
var userEnteredName = this.window.document.getElementById("editBMPanel_userEnteredName");
var self = this;
this.window.addEventListener("unload", function(event) {
this.window.removeEventListener("unload", arguments.callee, false);
executeSoon(function() {
self.finish();
});
}, false);
namePicker.value = "n";
userEnteredName.label = "n";
dump("About to focus the namePicker field\n");
namePicker.focus();
EventUtils.synthesizeKey("VK_RETURN", {}, this.window);
},
finish: function() {
// Window is already closed.
toggleSidebar("viewBookmarksSidebar", false);
runNextTest();
},
cleanup: function() {
// Check that folder name has been changed.
is(PlacesUtils.bookmarks.getItemTitle(this._itemId), "n",
"Folder name has been edited");
// Cleanup.
PlacesUtils.bookmarks.removeItem(this._itemId);
}
});
//------------------------------------------------------------------------------
// Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel
gTests.push({
desc: "Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel",
sidebar: SIDEBAR_BOOKMARKS_ID,
action: ACTION_EDIT,
itemType: null,
window: null,
_itemId: null,
setup: function() {
// Add a bookmark in unsorted bookmarks folder.
this._itemId = add_bookmark(PlacesUtils._uri(TEST_URL));
ok(this._itemId > 0, "Correctly added a bookmark");
// Add a tag to this bookmark.
PlacesUtils.tagging.tagURI(PlacesUtils._uri(TEST_URL),
["testTag"]);
var tags = PlacesUtils.tagging.getTagsForURI(PlacesUtils._uri(TEST_URL), {});
is(tags[0], "testTag", "Correctly added a tag");
},
selectNode: function(tree) {
tree.selectItems([this._itemId]);
is(tree.selectedNode.itemId, this._itemId, "Bookmark has been selected");
},
run: function() {
// open tags autocomplete and press enter
var tagsField = this.window.document.getElementById("editBMPanel_tagsField");
var self = this;
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowclosed") {
ww.unregisterNotification(this);
tagsField.popup.removeEventListener("popuphidden", popupListener, true);
ok(false, "Dialog window should not be closed by pressing Escape on the autocomplete popup");
self.finish();
}
}
};
var popupListener = {
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "popuphidden":
// Everything worked fine, we can stop observing the window.
ww.unregisterNotification(windowObserver);
tagsField.popup.removeEventListener("popuphidden", this, true);
self.window.document.documentElement.cancelDialog();
self.finish();
break;
case "popupshown":
tagsField.popup.removeEventListener("popupshown", this, true);
// In case this test fails the window will close, we should mark the
// failure and continue, to avoid timing out.
ww.registerNotification(windowObserver);
var tree = tagsField.popup.tree;
// Focus and select first result.
isnot(tree, null, "Autocomplete results tree exists");
is(tree.view.rowCount, 1, "We have 1 autocomplete result");
tagsField.popup.selectedIndex = 0;
is(tree.view.selection.count, 1,
"We have selected a tag from the autocomplete popup");
dump("About to focus the autocomplete results tree\n");
tree.focus();
EventUtils.synthesizeKey("VK_ESCAPE", {}, self.window);
break;
default:
ok(false, "unknown event: " + aEvent.type);
return;
}
}
};
tagsField.popup.addEventListener("popupshown", popupListener, true);
tagsField.popup.addEventListener("popuphidden", popupListener, true);
// Open tags autocomplete popup.
dump("About to focus the tagsField\n");
tagsField.focus();
tagsField.value = "";
EventUtils.synthesizeKey("t", {}, this.window);
},
finish: function() {
toggleSidebar("viewBookmarksSidebar", false);
runNextTest();
},
cleanup: function() {
// Check tags have not changed.
var tags = PlacesUtils.tagging.getTagsForURI(PlacesUtils._uri(TEST_URL), {});
is(tags[0], "testTag", "Tag on node has not changed");
// Cleanup.
PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL),
["testTag"]);
PlacesUtils.bookmarks.removeItem(this._itemId);
}
});
//------------------------------------------------------------------------------
function test() {
dump("Starting test browser_bookmarksProperties.js\n");
waitForExplicitFinish();
// Sanity checks.
ok(PlacesUtils, "PlacesUtils in context");
ok(PlacesUIUtils, "PlacesUIUtils in context");
// kick off tests
runNextTest();
}
function runNextTest() {
// Cleanup from previous test.
if (gCurrentTest) {
gCurrentTest.cleanup();
ok(true, "*** FINISHED TEST ***");
}
if (gTests.length > 0) {
// Goto next tests.
gCurrentTest = gTests.shift();
ok(true, "*** TEST: " + gCurrentTest.desc);
dump("*** TEST: " + gCurrentTest.desc + "\n");
gCurrentTest.setup();
execute_test_in_sidebar();
}
else {
// Finished all tests.
finish();
}
}
/**
* Global functions to run a test in Properties dialog context.
*/
function execute_test_in_sidebar() {
var sidebar = document.getElementById("sidebar");
sidebar.addEventListener("load", function() {
sidebar.removeEventListener("load", arguments.callee, true);
// Need to executeSoon since the tree is initialized on sidebar load.
executeSoon(open_properties_dialog);
}, true);
toggleSidebar("viewBookmarksSidebar", true);
}
function open_properties_dialog() {
var sidebar = document.getElementById("sidebar");
// Get sidebar's Places tree.
var tree = sidebar.contentDocument.getElementById(gCurrentTest.sidebar);
ok(tree, "Sidebar tree has been loaded");
// Ask current test to select the node to edit.
gCurrentTest.selectNode(tree);
ok(tree.selectedNode,
"We have a places node selected: " + tree.selectedNode.title);
// Wait for the Properties dialog.
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
ww.unregisterNotification(this);
var win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function onLoad(event) {
win.removeEventListener("load", onLoad, false);
// Windows has been loaded, execute our test now.
executeSoon(function () {
// Ensure overlay is loaded
ok(win.gEditItemOverlay._initialized, "EditItemOverlay is initialized");
gCurrentTest.window = win;
try {
gCurrentTest.run();
} catch (ex) {
ok(false, "An error occured during test run: " + ex.message);
}
});
}, false);
}
}
};
ww.registerNotification(windowObserver);
var command = null;
switch(gCurrentTest.action) {
case ACTION_EDIT:
command = "placesCmd_show:info";
break;
case ACTION_ADD:
if (gCurrentTest.itemType == TYPE_FOLDER)
command = "placesCmd_new:folder";
else if (gCurrentTest.itemType == TYPE_BOOKMARK)
command = "placesCmd_new:bookmark";
else
ok(false, "You didn't set a valid itemType for adding an item");
break;
default:
ok(false, "You didn't set a valid action for this test");
}
// Ensure command is enabled for this node.
ok(tree.controller.isCommandEnabled(command),
"Properties command on current selected node is enabled");
// This will open the dialog.
tree.controller.doCommand(command);
}

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

@ -0,0 +1,123 @@
/* ***** 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 Places test code.
*
* The Initial Developer of the Original Code is
* Ehsan Akhgari.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 ***** */
// This test makes sure that the Forget This Site command is hidden for multiple
// selections.
function test() {
// initialization
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
waitForExplicitFinish();
// Add a history entry.
let TEST_URIs = ["http://www.mozilla.org/test1", "http://www.mozilla.org/test2"];
ok(PlacesUtils, "checking PlacesUtils, running in chrome context?");
let history = PlacesUtils.history;
TEST_URIs.forEach(function(TEST_URI) {
let visitId = history.addVisit(PlacesUtils._uri(TEST_URI), Date.now() * 1000,
null, PlacesUtils.history.TRANSITION_TYPED, false, 0);
ok(visitId > 0, TEST_URI + " successfully marked visited");
});
function testForgetThisSiteVisibility(selectionCount, funcNext) {
let observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
ww.unregisterNotification(this);
let organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
organizer.addEventListener("load", function onLoad(event) {
organizer.removeEventListener("load", onLoad, false);
executeSoon(function () {
// Select History in the left pane.
organizer.PlacesOrganizer.selectLeftPaneQuery('History');
let PO = organizer.PlacesOrganizer;
let histContainer = PO._places.selectedNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
histContainer.containerOpen = true;
PO._places.selectNode(histContainer.getChild(0));
// Select the first history entry.
let doc = organizer.document;
let tree = PO._content;
let selection = tree.view.selection;
selection.clearSelection();
selection.rangedSelect(0, selectionCount - 1, true);
is(selection.count, selectionCount,
"The selected range is as big as expected");
// Open the context menu
let contextmenu = doc.getElementById("placesContext");
contextmenu.addEventListener("popupshown", function() {
contextmenu.removeEventListener("popupshown", arguments.callee, false);
let forgetThisSite = doc.getElementById("placesContext_deleteHost");
let hideForgetThisSite = (selectionCount != 1);
is(forgetThisSite.hidden, hideForgetThisSite,
"The Forget this site menu item should " + (hideForgetThisSite ? "" : "not ") +
"be hidden with " + selectionCount + " items selected");
// Close the context menu
contextmenu.hidePopup();
// Close Library window.
organizer.close();
// Proceed
funcNext();
}, false);
let event = document.createEvent("MouseEvents");
event.initMouseEvent("contextmenu", true, true, organizer, 0,
0, 0, 0, 0, false, false, false, false,
0, null);
tree.dispatchEvent(event);
});
}, false);
}
}
};
ww.registerNotification(observer);
ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
}
testForgetThisSiteVisibility(1, function() {
testForgetThisSiteVisibility(2, function() {
// Cleanup
history.QueryInterface(Ci.nsIBrowserHistory)
.removeAllPages();
finish();
});
});
}

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

@ -0,0 +1,210 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 Places test code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by devaring the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not devare
* 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 ***** */
/**
* Test enabled commands in the left pane folder of the Library.
*/
const TEST_URI = "http://www.mozilla.org/";
var gTests = [];
var gLibrary;
//------------------------------------------------------------------------------
gTests.push({
desc: "Bug 489351 - Date containers under History in Library cannot be deleted/cut",
run: function() {
var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
// Add a visit.
PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URI), Date.now() * 1000,
null, PlacesUtils.history.TRANSITION_TYPED,
false, 0);
ok(bhist.isVisited(PlacesUtils._uri(TEST_URI)), "Visit has been added");
// Select and open the left pane "History" query.
var PO = gLibrary.PlacesOrganizer;
PO.selectLeftPaneQuery('History');
isnot(PO._places.selectedNode, null, "We correctly selected History");
// Check that both delete and cut commands are disabled.
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
var historyNode = PO._places.selectedNode
.QueryInterface(Ci.nsINavHistoryContainerResultNode);
historyNode.containerOpen = true;
// Check that we have a child container. It is "Today" container.
is(historyNode.childCount, 1, "History node has one child");
var todayNode = historyNode.getChild(0);
var todayNodeExpectedTitle = PlacesUtils.getString("finduri-AgeInDays-is-0");
is(todayNode.title, todayNodeExpectedTitle,
"History child is the expected container");
// Select "Today" container.
PO._places.selectNode(todayNode);
is(PO._places.selectedNode, todayNode,
"We correctly selected Today container");
// Check that delete command is enabled but cut command is disabled.
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
// Execute the delete command and check visit has been removed.
PO._places.controller.doCommand("cmd_delete");
ok(!bhist.isVisited(PlacesUtils._uri(TEST_URI)), "Visit has been removed");
// Test live update of "History" query.
is(historyNode.childCount, 0, "History node has no more children");
historyNode.containerOpen = false;
nextTest();
}
});
//------------------------------------------------------------------------------
gTests.push({
desc: "Bug 490156 - Can't delete smart bookmark containers",
run: function() {
// Select and open the left pane "Bookmarks Toolbar" folder.
var PO = gLibrary.PlacesOrganizer;
PO.selectLeftPaneQuery('BookmarksToolbar');
isnot(PO._places.selectedNode, null, "We have a valid selection");
is(PlacesUtils.getConcreteItemId(PO._places.selectedNode),
PlacesUtils.toolbarFolderId,
"We have correctly selected bookmarks toolbar node.");
// Check that both cut and delete commands are disabled.
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is disabled");
ok(!PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is disabled");
var toolbarNode = PO._places.selectedNode
.QueryInterface(Ci.nsINavHistoryContainerResultNode);
toolbarNode.containerOpen = true;
// Add an History query to the toolbar.
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.toolbarFolderId,
PlacesUtils._uri("place:sort=4"),
0, // Insert at start.
"special_query");
// Get first child and check it is the "Most Visited" smart bookmark.
ok(toolbarNode.childCount > 0, "Toolbar node has children");
var queryNode = toolbarNode.getChild(0);
is(queryNode.title, "special_query", "Query node is correctly selected");
// Select query node.
PO._places.selectNode(queryNode);
is(PO._places.selectedNode, queryNode, "We correctly selected query node");
// Check that both cut and delete commands are enabled.
ok(PO._places.controller.isCommandEnabled("cmd_cut"),
"Cut command is enabled");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
// Execute the delete command and check bookmark has been removed.
PO._places.controller.doCommand("cmd_delete");
try {
PlacesUtils.bookmarks.getFolderIdForItem(queryNode.itemId);
ok(false, "Unable to remove query node bookmark");
} catch(ex) {
ok(true, "Query node bookmark has been correctly removed");
}
toolbarNode.containerOpen = false;
nextTest();
}
});
//------------------------------------------------------------------------------
function nextTest() {
if (gTests.length) {
var test = gTests.shift();
ok(true, "TEST: " + test.desc);
dump("TEST: " + test.desc + "\n");
test.run();
}
else {
// Close Library window.
gLibrary.close();
// No need to cleanup anything, we have a correct left pane now.
finish();
}
}
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
ww.unregisterNotification(this);
gLibrary = aSubject.QueryInterface(Ci.nsIDOMWindow);
gLibrary.addEventListener("load", function onLoad(event) {
gLibrary.removeEventListener("load", onLoad, false);
executeSoon(function () {
// Execute tests.
nextTest();
});
}, false);
}
}
};
function test() {
dump("Starting test browser_library_left_pane_commands.js\n");
waitForExplicitFinish();
// Sanity checks.
ok(PlacesUtils, "PlacesUtils is running in chrome context");
ok(PlacesUIUtils, "PlacesUIUtils is running in chrome context");
// Open Library.
ww.registerNotification(windowObserver);
ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
}

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

@ -0,0 +1,123 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 Places test code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by devaring the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not devare
* 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 ***** */
/**
* Test we correctly fix broken Library left pane queries names.
*/
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
// Array of left pane queries objects, each one has the following properties:
// name: query's identifier got from annotations,
// itemId: query's itemId,
// correctTitle: original and correct query's title.
var leftPaneQueries = [];
var windowObserver = {
observe: function(aSubject, aTopic, aData) {
if (aTopic === "domwindowopened") {
ww.unregisterNotification(this);
var organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
organizer.addEventListener("load", function onLoad(event) {
organizer.removeEventListener("load", onLoad, false);
executeSoon(function () {
// Check titles have been fixed.
for (var i = 0; i < leftPaneQueries.length; i++) {
var query = leftPaneQueries[i];
is(PlacesUtils.bookmarks.getItemTitle(query.itemId),
query.correctTitle, "Title is correct for query " + query.name);
}
// Close Library window.
organizer.close();
// No need to cleanup anything, we have a correct left pane now.
finish();
});
}, false);
}
}
};
function test() {
waitForExplicitFinish();
// Sanity checks.
ok(PlacesUtils, "PlacesUtils is running in chrome context");
ok(PlacesUIUtils, "PlacesUIUtils is running in chrome context");
ok(ORGANIZER_LEFTPANE_VERSION > 0,
"Left pane version in chrome context, current version is: " + ORGANIZER_LEFTPANE_VERSION );
// Ensure left pane is initialized.
ok(PlacesUIUtils.leftPaneFolderId > 0, "left pane folder is initialized");
// Get the left pane folder.
var leftPaneItems = PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_FOLDER_ANNO, {});
is(leftPaneItems.length, 1, "We correctly have only 1 left pane folder");
// Check version.
var version = PlacesUtils.annotations
.getItemAnnotation(leftPaneItems[0],
ORGANIZER_FOLDER_ANNO);
is(version, ORGANIZER_LEFTPANE_VERSION, "Left pane version is actual");
// Get all left pane queries.
var items = PlacesUtils.annotations
.getItemsWithAnnotation(ORGANIZER_QUERY_ANNO, {});
// Get current queries names.
for (var i = 0; i < items.length; i++) {
var itemId = items[i];
var queryName = PlacesUtils.annotations
.getItemAnnotation(items[i],
ORGANIZER_QUERY_ANNO);
leftPaneQueries.push({ name: queryName,
itemId: itemId,
correctTitle: PlacesUtils.bookmarks
.getItemTitle(itemId) });
// Rename to a bad title.
PlacesUtils.bookmarks.setItemTitle(itemId, "badName");
}
// Open Library, this will kick-off left pane code.
ww.registerNotification(windowObserver);
ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
}

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

@ -59,6 +59,8 @@
* 6. if folder scope was clicked, searches again and ensures folder scope
* remains selected.
*/
const TEST_URL = "http://dummy.mozilla.org/";
// Add your tests here. Each is a function that's called by testHelper().
var testCases = [
@ -66,7 +68,7 @@ var testCases = [
// All Bookmarks
function () {
var defScope = getDefaultScope(PlacesUIUtils.allBookmarksFolderId);
search(PlacesUIUtils.allBookmarksFolderId, "dummy search", defScope);
search(PlacesUIUtils.allBookmarksFolderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
"Folder scope should be disabled for All Bookmarks");
resetSearch(defScope);
@ -74,8 +76,8 @@ var testCases = [
// History
function () {
defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["History"]);
search(PlacesUIUtils.leftPaneQueries["History"], "dummy search", defScope);
var defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["History"]);
search(PlacesUIUtils.leftPaneQueries["History"], "dummy", defScope);
is(selectScope("scopeBarFolder"), false,
"Folder scope should be disabled for History");
resetSearch(defScope);
@ -83,14 +85,14 @@ var testCases = [
// Toolbar folder
function () {
defScope = getDefaultScope(bmsvc.toolbarFolder);
search(bmsvc.toolbarFolder, "dummy search", defScope);
var defScope = getDefaultScope(bmsvc.toolbarFolder);
search(bmsvc.toolbarFolder, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
"Folder scope should be enabled for toolbar folder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(bmsvc.toolbarFolder, "dummy search", "scopeBarFolder");
search(bmsvc.toolbarFolder, "dummy", "scopeBarFolder");
},
// A regular non-root subfolder
@ -98,14 +100,14 @@ var testCases = [
var folderId = bmsvc.createFolder(bmsvc.toolbarFolder,
"dummy folder",
bmsvc.DEFAULT_INDEX);
defScope = getDefaultScope(folderId);
search(folderId, "dummy search", defScope);
var defScope = getDefaultScope(folderId);
search(folderId, "dummy", defScope);
is(selectScope("scopeBarFolder"), true,
"Folder scope should be enabled for regular subfolder");
// Ensure that folder scope is still selected after resetting and searching
// again.
resetSearch("scopeBarFolder");
search(folderId, "dummy search", "scopeBarFolder");
search(folderId, "dummy", "scopeBarFolder");
bmsvc.removeItem(folderId);
},
];
@ -219,6 +221,15 @@ function search(aFolderId, aSearchStr, aExpectedScopeButtonId) {
"Content tree's searchTerms should be text in search box");
is(doc.getElementById("searchModifiers").hidden, false,
"Scope bar should not be hidden after searching");
if (getSelectedScopeButtonId() == "scopeBarHistory" ||
getSelectedScopeButtonId() == "scopeBarAll" ||
aFolderId == PlacesUtils.bookmarks.unfiledBookmarksFolder) {
// Check that search has returned a valid result.
contentTree.view.selection.select(0);
var foundNode = contentTree.selectedNode;
isnot(foundNode, null, "Found a valid node");
is(foundNode.uri, TEST_URL);
}
}
else {
is(query.hasSearchTerms, false,
@ -260,6 +271,12 @@ function testHelper(aLibraryWin) {
libraryWin = aLibraryWin;
testCases.forEach(function (aTest) aTest());
aLibraryWin.close();
// Cleanup.
PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.unfiledBookmarksFolder);
PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
finish();
}
@ -268,6 +285,18 @@ function testHelper(aLibraryWin) {
function test() {
waitForExplicitFinish();
// Sanity:
ok(PlacesUtils, "PlacesUtils in context");
// Add a visit, a bookmark and a tag.
PlacesUtils.history.addVisit(PlacesUtils._uri(TEST_URL),
Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_TYPED, false, 0);
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.bookmarks.unfiledBookmarksFolder,
PlacesUtils._uri(TEST_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"dummy");
PlacesUtils.tagging.tagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);

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

@ -45,6 +45,9 @@ include $(topsrcdir)/config/rules.mk
_CHROME_TEST_FILES = \
test_treeview_date.xul \
test_bug485100-change-case-loses-tag.xul \
test_bug427633_no_newfolder_if_noip.xul \
test_multiple_left_pane.xul \
$(NULL)
libs:: $(_CHROME_TEST_FILES)

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

@ -0,0 +1,123 @@
<?xml version="1.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 the Places test code.
-
- The Initial Developer of the Original Code is Mozilla Corp.
- Portions created by the Initial Developer are Copyright (C) 2009
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Marco Bonardo <mak77@bonardo.net> (Original Author)
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
%editBookmarkOverlayDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Bug 427633 - Disable creating a New Folder in the bookmarks dialogs if insertionPoint is invalid"
onload="runTest();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
<body xmlns="http://www.w3.org/1999/xhtml" />
<vbox id="editBookmarkPanelContent"/>
<script type="application/javascript">
<![CDATA[
/**
* Bug 427633 - Disable creating a New Folder in the bookmarks dialogs if
* insertionPoint is invalid.
*/
function runTest() {
const Cc = Components.classes;
const Ci = Components.interfaces;
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
function uri(spec) {
return ios.newURI(spec, null, null);
}
// Add a bookmark.
var itemId = bs.insertBookmark(bs.toolbarFolder,
uri("http://www.mozilla.org/"),
bs.DEFAULT_INDEX,
"mozilla");
// Init panel.
ok(gEditItemOverlay, "gEditItemOverlay is in context");
gEditItemOverlay.initPanel(itemId);
ok(gEditItemOverlay._initialized, "gEditItemOverlay is initialized");
// We must be sure tree is initialized, so we wait for place to be set.
SimpleTest.waitForExplicitFinish();
var tree = gEditItemOverlay._element("folderTree");
tree.addEventListener("DOMAttrModified", function(event) {
if (event.attrName != "place")
return;
tree.removeEventListener("DOMAttrModified", arguments.callee, false);
SimpleTest.executeSoon(function() {
tree.view.selection.clearSelection();
ok(document.getElementById("editBMPanel_newFolderButton").disabled,
"New folder button is disabled if there's no selection");
// Cleanup.
bs.removeItem(itemId);
SimpleTest.finish();
});
}, false);
// Open the folder tree.
document.getElementById("editBMPanel_foldersExpander").doCommand();
}
]]>
</script>
</window>

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

@ -0,0 +1,123 @@
<?xml version="1.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 the Places test code.
-
- The Initial Developer of the Original Code is Mozilla Corp.
- Portions created by the Initial Developer are Copyright (C) 2009
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Marco Bonardo <mak77@bonardo.net> (Original Author)
- Dietrich Ayala <dietrich@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 ***** -->
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
%editBookmarkOverlayDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="485100: Exchanging a letter of a tag name with its big/small equivalent removes tag from bookmark"
onload="runTest();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
<body xmlns="http://www.w3.org/1999/xhtml" />
<vbox id="editBookmarkPanelContent"/>
<script type="application/javascript">
<![CDATA[
function runTest() {
const Cc = Components.classes;
const Ci = Components.interfaces;
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
var ts = Cc["@mozilla.org/browser/tagging-service;1"].
getService(Ci.nsITaggingService);
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
function uri(spec) {
return ios.newURI(spec, null, null);
}
var testURI = uri("http://www.mozilla.org/");
var testTag = "foo";
var testTagUpper = "Foo";
// Add a bookmark
var itemId = bs.insertBookmark(bs.toolbarFolder,
testURI,
bs.DEFAULT_INDEX,
"mozilla");
// Init panel
ok(gEditItemOverlay, "gEditItemOverlay is in context");
gEditItemOverlay.initPanel(itemId);
// add a tag
document.getElementById("editBMPanel_tagsField").value = testTag;
gEditItemOverlay.onTagsFieldBlur();
// test that the tag has been added in the backend
is(ts.getTagsForURI(testURI, {})[0], testTag, "tags match");
// change the tag
document.getElementById("editBMPanel_tagsField").value = testTagUpper;
gEditItemOverlay.onTagsFieldBlur();
// test that the tag has been added in the backend
is(ts.getTagsForURI(testURI, {})[0], testTagUpper, "tags match");
// Cleanup.
ts.untagURI(testURI, [testTag]);
bs.removeItem(itemId);
}
]]>
</script>
</window>

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