зеркало из https://github.com/mozilla/gecko-dev.git
Merge the trunk into HTML5 parsing repo
This commit is contained in:
Коммит
1f9455f387
|
@ -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$
|
||||
|
|
13
Makefile.in
13
Makefile.in
|
@ -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 O’Shannessy <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="©.label;" command="cmd_copy" accesskey="©.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>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче