mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
Bug 480169 - Clear recent history refresh (sprint)
Item list hidden behind expander/progressive disclosure button, added a warning when clearing all history, added a tree view for selecting a fine-grained timespan. We decided to remove the tree view at the last minute; code is still there but #ifdef'ed out. r=mconnor
This commit is contained in:
parent
c7862e55bd
commit
73f247cb0f
@ -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);
|
||||
|
@ -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: {
|
||||
@ -395,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>
|
||||
|
19
browser/base/content/sanitizeDialog.css
Normal file
19
browser/base/content/sanitizeDialog.css
Normal file
@ -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;
|
||||
}
|
934
browser/base/content/sanitizeDialog.js
Normal file
934
browser/base/content/sanitizeDialog.js
Normal file
@ -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
|
@ -63,6 +63,11 @@ _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 \
|
||||
@ -107,6 +112,7 @@ _BROWSER_FILES = browser_sanitize-timespans.js \
|
||||
browser_bug479408_sample.html \
|
||||
browser_scope.js \
|
||||
browser_overflowScroll.js \
|
||||
browser_sanitizeDialog.js \
|
||||
$(NULL)
|
||||
|
||||
ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
721
browser/base/content/test/browser_sanitizeDialog.js
Normal file
721
browser/base/content/test/browser_sanitizeDialog.js
Normal file
@ -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();
|
||||
}
|
674
browser/base/content/test/browser_sanitizeDialog_treeView.js
Normal file
674
browser/base/content/test/browser_sanitizeDialog_treeView.js
Normal file
@ -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();
|
||||
}
|
@ -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)
|
||||
|
@ -1,6 +1,7 @@
|
||||
classic.jar:
|
||||
% skin browser classic/1.0 %skin/classic/browser/
|
||||
% override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
|
||||
skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css)
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
|
88
browser/themes/gnomestripe/browser/sanitizeDialog.css
Normal file
88
browser/themes/gnomestripe/browser/sanitizeDialog.css
Normal file
@ -0,0 +1,88 @@
|
||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||
takes up a little space, causing the end of the dropdown to not be aligned
|
||||
with the warning box. */
|
||||
#sanitizeDurationSuffixLabel[value=""] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Places tree */
|
||||
#placesTreechildren::-moz-tree-row(selected),
|
||||
#placesTreechildren::-moz-tree-row(grippyRow) {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
#placesTreechildren::-moz-tree-cell-text(selected) {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
|
||||
/* Sanitize everything warning box */
|
||||
#sanitizeEverythingWarningBox {
|
||||
background-color: Window;
|
||||
border: 1px solid ThreeDDarkShadow;
|
||||
-moz-border-radius: 5px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/warning-large.png");
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningDescBox {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* Progressive disclosure button */
|
||||
#detailsExpanderWrapper {
|
||||
padding: 0;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-left: -6px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.expander-up,
|
||||
.expander-down {
|
||||
min-width: 0;
|
||||
padding: 2px 0;
|
||||
-moz-padding-start: 2px;
|
||||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
|
||||
}
|
||||
|
||||
.expander-down:hover:active {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
|
||||
}
|
||||
|
||||
.expander-up:hover:active {
|
||||
list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
|
||||
}
|
||||
|
||||
|
||||
/* Make the item list the same width as the warning box */
|
||||
#itemList {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Make the rightmost dialog button ("accept") align wih right side of the
|
||||
warning box */
|
||||
.prefWindow-dlgbuttons {
|
||||
margin-right: 0;
|
||||
}
|
||||
.dialog-button[dlgtype="accept"] {
|
||||
margin-right: 0;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
classic.jar:
|
||||
% skin browser classic/1.0 %skin/classic/browser/
|
||||
skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css)
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
|
89
browser/themes/pinstripe/browser/sanitizeDialog.css
Normal file
89
browser/themes/pinstripe/browser/sanitizeDialog.css
Normal file
@ -0,0 +1,89 @@
|
||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||
takes up a little space, causing the end of the dropdown to not be aligned
|
||||
with the warning box. */
|
||||
#sanitizeDurationSuffixLabel[value=""] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Places tree */
|
||||
#placesTreechildren::-moz-tree-row(selected),
|
||||
#placesTreechildren::-moz-tree-row(grippyRow) {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
#placesTreechildren::-moz-tree-cell-text(selected) {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
|
||||
/* Sanitize everything warning box */
|
||||
#sanitizeEverythingWarningBox {
|
||||
background-color: Window;
|
||||
border: 1px solid ThreeDDarkShadow;
|
||||
-moz-border-radius: 5px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/warning-large.png");
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningDescBox {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* Progressive disclosure button */
|
||||
#detailsExpanderWrapper {
|
||||
padding: 0;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-left: -2px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.expander-up,
|
||||
.expander-down {
|
||||
-moz-appearance: none;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open.png");
|
||||
}
|
||||
|
||||
.expander-up:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open-active.png");
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed.png");
|
||||
}
|
||||
|
||||
.expander-down:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed-active.png");
|
||||
}
|
||||
|
||||
|
||||
/* Make the item list the same width as the warning box */
|
||||
#itemList {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Make the rightmost dialog button ("accept") align wih right side of the
|
||||
warning box */
|
||||
.prefWindow-dlgbuttons {
|
||||
margin-right: 0;
|
||||
}
|
||||
.dialog-button[dlgtype="accept"] {
|
||||
margin-right: 0;
|
||||
}
|
@ -3,6 +3,7 @@ classic.jar:
|
||||
% skin browser classic/1.0 %skin/classic/browser/ os!=WINNT
|
||||
# NOTE: If you add a new file here, you'll need to add it to the aero
|
||||
# section at the bottom of this file
|
||||
skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css)
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
@ -95,6 +96,7 @@ classic.jar:
|
||||
#ifdef XP_WIN
|
||||
classic.jar:
|
||||
% skin browser classic/1.0 %skin/classic/aero/browser/ os=WINNT osversion>=6
|
||||
skin/classic/aero/browser/sanitizeDialog.css (sanitizeDialog.css)
|
||||
* skin/classic/aero/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/aero/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/aero/browser/aboutCertError.css (aboutCertError.css)
|
||||
|
84
browser/themes/winstripe/browser/sanitizeDialog.css
Normal file
84
browser/themes/winstripe/browser/sanitizeDialog.css
Normal file
@ -0,0 +1,84 @@
|
||||
/* Hide the duration dropdown suffix label if it's empty. Otherwise it
|
||||
takes up a little space, causing the end of the dropdown to not be aligned
|
||||
with the warning box. */
|
||||
#sanitizeDurationSuffixLabel[value=""] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Places tree */
|
||||
#placesTreechildren::-moz-tree-row(selected),
|
||||
#placesTreechildren::-moz-tree-row(grippyRow) {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
#placesTreechildren::-moz-tree-cell-text(selected) {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
|
||||
/* Sanitize everything warning box */
|
||||
#sanitizeEverythingWarningBox {
|
||||
background-color: Window;
|
||||
border: 1px solid ThreeDDarkShadow;
|
||||
-moz-border-radius: 5px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/warning-large.png");
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#sanitizeEverythingWarningDescBox {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* Progressive disclosure button */
|
||||
#detailsExpanderWrapper {
|
||||
padding: 0;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
margin-left: -1px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.expander-up,
|
||||
.expander-down {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.expander-up > hbox,
|
||||
.expander-down > hbox {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://global/skin/icons/collapse.png");
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://global/skin/icons/expand.png");
|
||||
}
|
||||
|
||||
|
||||
/* Make the item list the same width as the warning box */
|
||||
#itemList {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Make the rightmost dialog button ("cancel") align wih right side of the
|
||||
warning box */
|
||||
.prefWindow-dlgbuttons {
|
||||
margin-right: 0;
|
||||
}
|
||||
.dialog-button[dlgtype="cancel"] {
|
||||
margin-right: 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user