merge fx-team to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2014-05-26 14:59:21 +02:00
Родитель 4f8c9846a1 bb7b1a3197
Коммит 2446abd3df
44 изменённых файлов: 706 добавлений и 323 удалений

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

@ -219,30 +219,37 @@
accesskey="&hidePluginCmd.accesskey;"
oncommand="gContextMenu.hidePlugin();"/>
<menuseparator id="context-sep-ctp"/>
<menuitem id="context-back"
label="&backCmd.label;"
accesskey="&backCmd.accesskey;"
command="Browser:BackOrBackDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-forward"
label="&forwardCmd.label;"
accesskey="&forwardCmd.accesskey;"
command="Browser:ForwardOrForwardDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-reload"
label="&reloadCmd.label;"
accesskey="&reloadCmd.accesskey;"
oncommand="gContextMenu.reload(event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-stop"
label="&stopCmd.label;"
accesskey="&stopCmd.accesskey;"
command="Browser:Stop"/>
<menuseparator id="context-sep-stop"/>
<menuitem id="context-bookmarkpage"
label="&bookmarkPageCmd2.label;"
accesskey="&bookmarkPageCmd2.accesskey;"
oncommand="gContextMenu.bookmarkThisPage();"/>
<menugroup id="context-navigation">
<menuitem id="context-back"
class="menuitem-iconic"
tooltiptext="&backButton.tooltip;"
aria-label="&backCmd.label;"
command="Browser:BackOrBackDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-forward"
class="menuitem-iconic"
tooltiptext="&forwardButton.tooltip;"
aria-label="&forwardCmd.label;"
command="Browser:ForwardOrForwardDuplicate"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-reload"
class="menuitem-iconic"
tooltiptext="&reloadButton.tooltip;"
aria-label="&reloadCmd.label;"
oncommand="gContextMenu.reload(event);"
onclick="checkForMiddleClick(this, event);"/>
<menuitem id="context-stop"
class="menuitem-iconic"
tooltiptext="&stopButton.tooltip;"
aria-label="&stopCmd.label;"
command="Browser:Stop"/>
<menuitem id="context-bookmarkpage"
class="menuitem-iconic"
tooltiptext="&bookmarkPageCmd2.label;"
aria-label="&bookmarkPageCmd2.label;"
oncommand="gContextMenu.bookmarkThisPage();"/>
</menugroup>
<menuseparator id="context-sep-navigation"/>
<menuitem id="context-sharepage"
label="&sharePageCmd.label;"
accesskey="&sharePageCmd.accesskey;"

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

@ -1133,3 +1133,9 @@ toolbarpaletteitem[place="palette"][hidden] {
animation-name: uitour-color;
animation-duration: 2s;
}
/* Combined context-menu items */
#context-navigation > .menuitem-iconic > .menu-iconic-text,
#context-navigation > .menuitem-iconic > .menu-accel-container {
display: none;
}

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

@ -151,8 +151,8 @@ nsContextMenu.prototype = {
var shouldShow = !(this.isContentSelected || this.onLink || this.onImage ||
this.onCanvas || this.onVideo || this.onAudio ||
this.onTextInput || this.onSocial);
this.showItem("context-back", shouldShow);
this.showItem("context-forward", shouldShow);
this.showItem("context-navigation", shouldShow);
this.showItem("context-sep-navigation", shouldShow);
let stopped = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true";
@ -163,7 +163,6 @@ nsContextMenu.prototype = {
this.showItem("context-reload", stopReloadItem == "reload");
this.showItem("context-stop", stopReloadItem == "stop");
this.showItem("context-sep-stop", !!stopReloadItem);
// XXX: Stop is determined in browser.js; the canStop broadcaster is broken
//this.setItemAttrFromNode( "context-stop", "disabled", "canStop" );
@ -270,7 +269,8 @@ nsContextMenu.prototype = {
// Use "Bookmark This Link" if on a link.
this.showItem("context-bookmarkpage",
!(this.isContentSelected || this.onTextInput || this.onLink ||
this.onImage || this.onVideo || this.onAudio || this.onSocial));
this.onImage || this.onVideo || this.onAudio || this.onSocial ||
this.onCanvas));
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
!this.onSocial) || this.onPlainTextLink);
this.showItem("context-keywordfield",

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

@ -26,11 +26,13 @@ function test() {
EventUtils.synthesizeMouseAtCenter(video1,
{ type: "contextmenu", button: 2 },
gBrowser.contentWindow);
info("context menu click on video1");
});
});
function contextMenuOpened(event) {
event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
info("context menu opened on video1");
// Create the folder the video will be saved into.
var destDir = createTemporarySaveDirectory();
@ -56,6 +58,7 @@ function test() {
// Select "Save Video As" option from context menu
var saveVideoCommand = document.getElementById("context-savevideo");
saveVideoCommand.doCommand();
info("context-savevideo command executed");
event.target.hidePopup();
}

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

@ -96,10 +96,23 @@ function getVisibleMenuItems(aMenu, aData) {
}
items.push(item.id);
items.push(!item.disabled);
// Add a dummy item to that the indexes in checkMenu are the same
// Add a dummy item so that the indexes in checkMenu are the same
// for expectedItems and actualItems.
items.push([]);
items.push(null);
} else if (item.nodeName == "menugroup") {
ok(item.id, "child menugroup #" + i + " has an ID");
items.push(item.id);
items.push(!item.disabled);
var menugroupChildren = [];
for (var child of item.children) {
if (child.hidden)
continue;
menugroupChildren.push([child.id, !child.disabled]);
}
items.push(menugroupChildren);
items.push(null);
} else {
ok(false, "child #" + i + " of menu ID " + aMenu.id +
" has an unknown type (" + item.nodeName + ")");
@ -114,6 +127,43 @@ function checkContextMenu(expectedItems) {
checkMenu(contextMenu, expectedItems, data);
}
function checkMenuItem(actualItem, actualEnabled, expectedItem, expectedEnabled, index) {
is(actualItem, expectedItem,
"checking item #" + index/2 + " (" + expectedItem + ") name");
if (typeof expectedEnabled == "object" && expectedEnabled != null ||
typeof actualEnabled == "object" && actualEnabled != null) {
ok(!(actualEnabled == null), "actualEnabled is not null");
ok(!(expectedEnabled == null), "expectedEnabled is not null");
is(typeof actualEnabled, typeof expectedEnabled, "checking types");
if (typeof actualEnabled != typeof expectedEnabled ||
actualEnabled == null || expectedEnabled == null)
return;
is(actualEnabled.type, expectedEnabled.type,
"checking item #" + index/2 + " (" + expectedItem + ") type attr value");
var icon = actualEnabled.icon;
if (icon) {
var tmp = "";
var j = icon.length - 1;
while (j && icon[j] != "/") {
tmp = icon[j--] + tmp;
}
icon = tmp;
}
is(icon, expectedEnabled.icon,
"checking item #" + index/2 + " (" + expectedItem + ") icon attr value");
is(actualEnabled.checked, expectedEnabled.checked,
"checking item #" + index/2 + " (" + expectedItem + ") has checked attr");
is(actualEnabled.disabled, expectedEnabled.disabled,
"checking item #" + index/2 + " (" + expectedItem + ") has disabled attr");
} else if (expectedEnabled != null)
is(actualEnabled, expectedEnabled,
"checking item #" + index/2 + " (" + expectedItem + ") enabled state");
}
/*
* checkMenu - checks to see if the specified <menupopup> contains the
* expected items and state.
@ -136,50 +186,26 @@ function checkMenu(menu, expectedItems, data) {
var expectedItem = expectedItems[i];
var expectedEnabled = expectedItems[i + 1];
if (expectedItem instanceof Array) {
ok(true, "Checking submenu...");
var menuID = expectedItems[i - 2]; // The last item was the menu ID.
var submenu = menu.getElementsByAttribute("id", menuID)[0];
ok(submenu, "got a submenu element of id='" + menuID + "'");
if (submenu) {
is(submenu.nodeName, "menu", "submenu element of id='" + menuID +
ok(true, "Checking submenu/menugroup...");
var previousId = expectedItems[i - 2]; // The last item was the menu ID.
var previousItem = menu.getElementsByAttribute("id", previousId)[0];
ok(previousItem, (previousItem ? previousItem.nodeName : "item") + " with previous id (" + previousId + ") found");
if (previousItem && previousItem.nodeName == "menu") {
ok(previousItem, "got a submenu element of id='" + previousId + "'");
is(previousItem.nodeName, "menu", "submenu element of id='" + previousId +
"' has expected nodeName");
checkMenu(submenu.menupopup, expectedItem, data);
checkMenu(previousItem.menupopup, expectedItem, data, i);
} else if (previousItem && previousItem.nodeName == "menugroup") {
ok(expectedItem.length, "menugroup must not be empty");
for (var j = 0; j < expectedItem.length / 2; j++) {
checkMenuItem(actualItems[i][j][0], actualItems[i][j][1], expectedItem[j*2], expectedItem[j*2+1], i+j*2);
}
i += j;
} else {
ok(false, "previous item is not a menu or menugroup");
}
} else {
is(actualItem, expectedItem,
"checking item #" + i/2 + " (" + expectedItem + ") name");
if (typeof expectedEnabled == "object" && expectedEnabled != null ||
typeof actualEnabled == "object" && actualEnabled != null) {
ok(!(actualEnabled == null), "actualEnabled is not null");
ok(!(expectedEnabled == null), "expectedEnabled is not null");
is(typeof actualEnabled, typeof expectedEnabled, "checking types");
if (typeof actualEnabled != typeof expectedEnabled ||
actualEnabled == null || expectedEnabled == null)
continue;
is(actualEnabled.type, expectedEnabled.type,
"checking item #" + i/2 + " (" + expectedItem + ") type attr value");
var icon = actualEnabled.icon;
if (icon) {
var tmp = "";
var j = icon.length - 1;
while (j && icon[j] != "/") {
tmp = icon[j--] + tmp;
}
icon = tmp;
}
is(icon, expectedEnabled.icon,
"checking item #" + i/2 + " (" + expectedItem + ") icon attr value");
is(actualEnabled.checked, expectedEnabled.checked,
"checking item #" + i/2 + " (" + expectedItem + ") has checked attr");
is(actualEnabled.disabled, expectedEnabled.disabled,
"checking item #" + i/2 + " (" + expectedItem + ") has disabled attr");
} else if (expectedEnabled != null)
is(actualEnabled, expectedEnabled,
"checking item #" + i/2 + " (" + expectedItem + ") enabled state");
checkMenuItem(actualItem, actualEnabled, expectedItem, expectedEnabled, i);
}
}
// Could find unexpected extra items at the end...

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

@ -91,11 +91,12 @@ function runTest(testNum) {
case 2:
// Context menu for plain text
plainTextItems = ["context-back", false,
"context-forward", false,
"context-reload", true,
plainTextItems = ["context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -163,7 +164,6 @@ function runTest(testNum) {
// Context menu for a canvas
checkContextMenu(["context-viewimage", true,
"context-saveimage", true,
"context-bookmarkpage", true,
"context-selectall", true
].concat(inspectItems));
closeContextMenu();
@ -264,11 +264,12 @@ function runTest(testNum) {
case 11:
// Context menu for an iframe
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
checkContextMenu(["context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -468,11 +469,12 @@ function runTest(testNum) {
"---", null,
"+Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}], null,
"---", null,
"context-back", false,
"context-forward", false,
"context-reload", true,
"context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -501,11 +503,12 @@ function runTest(testNum) {
// Context menu for DOM Fullscreen mode (NOTE: this is *NOT* on an img)
checkContextMenu(["context-leave-dom-fullscreen", true,
"---", null,
"context-back", false,
"context-forward", false,
"context-reload", true,
"context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -529,11 +532,12 @@ function runTest(testNum) {
case 21:
// Context menu for element with assigned content context menu
// The shift key should bypass content context menu processing
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
checkContextMenu(["context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -693,11 +697,12 @@ function runTest(testNum) {
checkContextMenu(["context-ctp-play", true,
"context-ctp-hide", true,
"---", null,
"context-back", false,
"context-forward", false,
"context-reload", true,
"context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@ -730,11 +735,12 @@ function runTest(testNum) {
case 29:
// Context menu for an iframe with srcdoc attribute set
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
checkContextMenu(["context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,

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

@ -189,11 +189,12 @@ function runTest(testNum) {
case 13: // type='number'
case 14: // type='color'
case 15: // type='range'
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
checkContextMenu(["context-navigation", null,
["context-back", false,
"context-forward", false,
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,

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

@ -74,9 +74,12 @@ function test1() {
// When the popupshown DOM event is fired, the actual showing of the popup
// may still be pending. Clear the event loop before continuing so that
// subsequently-opened popups aren't cancelled by accident.
let goToNext = function() {
let goToNext = function(aEvent) {
window.document.removeEventListener("popupshown", goToNext, false);
executeSoon(test2);
executeSoon(function() {
test2();
aEvent.target.hidePopup();
});
};
window.document.addEventListener("popupshown", goToNext, false);
EventUtils.synthesizeMouseAtCenter(plugin,

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

@ -85,7 +85,7 @@ function checkSpecialContextMenus() {
let menuPopup = document.getElementById(kSpecialItemIDs[menuID]);
info("Waiting to open menu for " + menuID);
let shownPromise = popupShown(menuPopup);
EventUtils.synthesizeMouseAtCenter(menuItem, {});
menuPopup.openPopup(menuItem, null, 0, 0, false, false, null);
yield shownPromise;
yield checkPlacesContextMenu(menuPopup);

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

@ -15,6 +15,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups",
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
"resource://gre/modules/DownloadUtils.jsm");
const RESTORE_FILEPICKER_FILTER_EXT = "*.json;*.jsonlz4";
var PlacesOrganizer = {
_places: null,
@ -489,7 +491,7 @@ var PlacesOrganizer = {
fp.init(window, PlacesUIUtils.getString("bookmarksRestoreTitle"),
Ci.nsIFilePicker.modeOpen);
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
RESTORE_FILEPICKER_FILTER_EXT);
fp.appendFilters(Ci.nsIFilePicker.filterAll);
fp.displayDirectory = backupsDir;
fp.open(fpCallback);
@ -500,7 +502,7 @@ var PlacesOrganizer = {
*/
restoreBookmarksFromFile: function PO_restoreBookmarksFromFile(aFilePath) {
// check file extension
if (!aFilePath.endsWith("json")) {
if (!aFilePath.endsWith("json") && !aFilePath.endsWith("jsonlz4")) {
this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreFormatError"));
return;
}
@ -551,7 +553,7 @@ var PlacesOrganizer = {
fp.init(window, PlacesUIUtils.getString("bookmarksBackupTitle"),
Ci.nsIFilePicker.modeSave);
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
RESTORE_FILEPICKER_FILTER_EXT);
fp.defaultString = PlacesBackups.getFilenameForDate();
fp.displayDirectory = backupsDir;
fp.open(fpCallback);

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

@ -153,18 +153,14 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
<!ENTITY backCmd.label "Back">
<!ENTITY backCmd.accesskey "B">
<!ENTITY backButton.tooltip "Go back one page">
<!ENTITY forwardCmd.label "Forward">
<!ENTITY forwardCmd.accesskey "F">
<!ENTITY forwardButton.tooltip "Go forward one page">
<!ENTITY backForwardButtonMenu.tooltip "Right-click or pull down to show history">
<!ENTITY backForwardButtonMenuMac.tooltip "Pull down to show history">
<!ENTITY reloadCmd.label "Reload">
<!ENTITY reloadCmd.accesskey "R">
<!ENTITY reloadButton.tooltip "Reload current page">
<!ENTITY stopCmd.label "Stop">
<!ENTITY stopCmd.accesskey "S">
<!ENTITY stopCmd.macCommandKey ".">
<!ENTITY stopButton.tooltip "Stop loading this page">
<!ENTITY goEndCap.tooltip "Go to the address in the Location Bar">
@ -443,7 +439,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY setDesktopBackgroundCmd.label "Set As Desktop Background…">
<!ENTITY setDesktopBackgroundCmd.accesskey "S">
<!ENTITY bookmarkPageCmd2.label "Bookmark This Page">
<!ENTITY bookmarkPageCmd2.accesskey "m">
<!ENTITY bookmarkThisLinkCmd.label "Bookmark This Link">
<!ENTITY bookmarkThisLinkCmd.accesskey "L">
<!ENTITY bookmarkThisFrameCmd.label "Bookmark This Frame">

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

@ -13,7 +13,6 @@ bookmarksRestoreAlertTitle=Revert Bookmarks
bookmarksRestoreAlert=This will replace all of your current bookmarks with the backup. Are you sure?
bookmarksRestoreTitle=Select a bookmarks backup
bookmarksRestoreFilterName=JSON
bookmarksRestoreFilterExtension=*.json
bookmarksRestoreFormatError=Unsupported file type.
bookmarksRestoreParseError=Unable to process the backup file.

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

@ -437,24 +437,11 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
list-style-image: url("moz-icon://stock/gtk-preferences?size=menu");
}
#context-stop {
list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
}
#context-stop[disabled] {
list-style-image: url("moz-icon://stock/gtk-stop?size=menu&state=disabled");
}
#placesContext_reload,
#context-reload,
#context-reloadframe {
list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
}
#context-reload[disabled] {
list-style-image: url("moz-icon://stock/gtk-refresh?size=menu&state=disabled");
}
#menu_zoomEnlarge {
list-style-image: url("moz-icon://stock/gtk-zoom-in?size=menu");
}
@ -467,38 +454,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
list-style-image: url("moz-icon://stock/gtk-zoom-100?size=menu");
}
#context-back {
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu");
}
#context-back[disabled] {
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu&state=disabled");
}
#context-back:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu");
}
#context-back[disabled]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu&state=disabled");
}
#context-forward {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu");
}
#context-forward[disabled] {
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
}
#context-forward:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu");
}
#context-forward[disabled]:-moz-locale-dir(rtl) {
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
}
#menu_showAllHistory {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-moz-image-region: rect(0px 32px 16px 16px);
@ -2289,3 +2244,23 @@ chatbox {
#UITourTooltipButtons {
margin-bottom: -10px;
}
%include ../shared/contextmenu.inc.css
#context-navigation {
background-color: -moz-dialog;
padding-bottom: 2px;
margin-bottom: 2px;
-moz-appearance: menuitem;
}
#context-navigation > .menuitem-iconic > .menu-iconic-left {
visibility: visible;
/* override toolkit/themes/linux/global/menu.css */
-moz-padding-end: 0 !important;
-moz-margin-end: 0 !important;
}
#context-sep-navigation {
margin-top: -4px;
}

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

@ -47,6 +47,11 @@ spinbuttons {
-moz-appearance: none;
}
.treecol-sortdirection {
/* override the Linux only toolkit rule */
-moz-appearance: none;
}
.actionsMenu {
font-family: "Clear Sans", sans-serif;
font-size: 1.25rem;

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

@ -4430,3 +4430,10 @@ window > chatbox {
width: 16px;
}
}
%include ../shared/contextmenu.inc.css
#context-navigation > .menuitem-iconic {
padding-left: 0;
padding-right: 0;
}

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

@ -0,0 +1,51 @@
menugroup > .menuitem-iconic[disabled="true"] > .menu-iconic-left {
opacity: .3;
}
#context-navigation > .menuitem-iconic {
-moz-box-flex: 1;
-moz-box-pack: center;
-moz-box-align: center;
}
#context-navigation > .menuitem-iconic > .menu-iconic-left {
-moz-appearance: none;
}
#context-navigation > #context-back > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 36px, 18px, 18px);
}
#context-navigation > #context-forward > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 72px, 18px, 54px);
}
#context-navigation > #context-reload > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-moz-image-region: rect(0, 14px, 14px, 0);
}
#context-navigation > #context-stop > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-moz-image-region: rect(0, 28px, 14px, 14px);
}
#context-navigation > #context-bookmarkpage > .menu-iconic-left {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 144px, 18px, 126px);
}
#context-back:-moz-locale-dir(rtl),
#context-forward:-moz-locale-dir(rtl),
#context-reload:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
#context-navigation > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
width: 18px;
height: 18px;
margin: 7px;
}

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

@ -2935,3 +2935,16 @@ chatbox {
#UITourTooltipButtons {
margin: 24px -4px -4px;
}
%include ../shared/contextmenu.inc.css
#context-navigation {
background-color: -moz-dialog;
padding-bottom: 2px;
margin-bottom: 2px;
}
#context-sep-navigation {
-moz-margin-start: -28px;
margin-top: -4px;
}

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

@ -1013,6 +1013,11 @@ nsGenericDOMDataNode::TextIsOnlyWhitespace()
bool
nsGenericDOMDataNode::HasTextForTranslation()
{
if (NodeType() != nsIDOMNode::TEXT_NODE &&
NodeType() != nsIDOMNode::CDATA_SECTION_NODE) {
return false;
}
if (mText.Is2b()) {
// The fragment contains non-8bit characters which means there
// was at least one "interesting" character to trigger non-8bit.

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

@ -565,6 +565,7 @@ GK_ATOM(menu, "menu")
GK_ATOM(menubar, "menubar")
GK_ATOM(menubutton, "menubutton")
GK_ATOM(menuButton, "menu-button")
GK_ATOM(menugroup, "menugroup")
GK_ATOM(menuitem, "menuitem")
GK_ATOM(menulist, "menulist")
GK_ATOM(menupopup, "menupopup")

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

@ -206,5 +206,22 @@
expected="p[root] a b span em">
<p>Lorem <a>ipsum <b>dolor <span>sit</span> amet</b></a>, <em>consetetur</em></p>
</div>
<!-- Test that comment nodes are not considered for translation -->
<div id="testcase16"
expected="p[root] p[root]">
<p>Lorem ipsum</p>
<div> <!-- Comment --> </div>
<p>Lorem ipsum</p>
</div>
<!-- Test that comment nodes are not considered for translation -->
<div id="testcase17"
expected="p[root]">
<div>
<!-- Comment -->
<p>Lorem Ipsum</p>
</div>
</div>
</body>
</html>

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

@ -37,10 +37,6 @@ html|input.ac {
padding: 0 4px !important;
}
#mac html|input.ac {
padding: 0 3px !important;
}
html|input.empty {
color: graytext;
}

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

@ -986,11 +986,11 @@ nsMenuFrame::UpdateMenuSpecialState(nsPresContext* aPresContext)
// get the first sibling in this menu popup. This frame may be it, and if we're
// being called at creation time, this frame isn't yet in the parent's child list.
// All I'm saying is that this may fail, but it's most likely alright.
nsIFrame* sib = GetParent()->GetFirstPrincipalChild();
nsIFrame* firstMenuItem = nsXULPopupManager::GetNextMenuItem(GetParent(), nullptr, true);
nsIFrame* sib = firstMenuItem;
while (sib) {
nsMenuFrame* menu = do_QueryFrame(sib);
if (sib != this) {
nsMenuFrame* menu = do_QueryFrame(sib);
if (menu && menu->GetMenuType() == eMenuType_Radio &&
menu->IsChecked() && menu->GetRadioGroupName() == mGroupName) {
/* uncheck the old item */
@ -1000,8 +1000,10 @@ nsMenuFrame::UpdateMenuSpecialState(nsPresContext* aPresContext)
return;
}
}
sib = sib->GetNextSibling();
sib = nsXULPopupManager::GetNextMenuItem(GetParent(), menu, true);
if (sib == firstMenuItem) {
break;
}
}
}

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

@ -1682,13 +1682,13 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction
lastKeyTime = keyTime;
nsIFrame* currFrame;
// NOTE: If you crashed here due to a bogus |immediateParent| it is
// possible that the menu whose shortcut is being looked up has
// been destroyed already. One strategy would be to
// setTimeout(<func>,0) as detailed in:
// <http://bugzilla.mozilla.org/show_bug.cgi?id=126675#c32>
currFrame = immediateParent->GetFirstPrincipalChild();
nsIFrame* firstMenuItem = nsXULPopupManager::GetNextMenuItem(immediateParent, nullptr, true);
nsIFrame* currFrame = firstMenuItem;
int32_t menuAccessKey = -1;
nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
@ -1697,64 +1697,64 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction
// -- before current and after current -- by the current item
while (currFrame) {
nsIContent* current = currFrame->GetContent();
// See if it's a menu item.
if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, true)) {
nsAutoString textKey;
if (menuAccessKey >= 0) {
// Get the shortcut attribute.
current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, textKey);
}
if (textKey.IsEmpty()) { // No shortcut, try first letter
isShortcut = false;
current->GetAttr(kNameSpaceID_None, nsGkAtoms::label, textKey);
if (textKey.IsEmpty()) // No label, try another attribute (value)
current->GetAttr(kNameSpaceID_None, nsGkAtoms::value, textKey);
nsAutoString textKey;
if (menuAccessKey >= 0) {
// Get the shortcut attribute.
current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, textKey);
}
if (textKey.IsEmpty()) { // No shortcut, try first letter
isShortcut = false;
current->GetAttr(kNameSpaceID_None, nsGkAtoms::label, textKey);
if (textKey.IsEmpty()) // No label, try another attribute (value)
current->GetAttr(kNameSpaceID_None, nsGkAtoms::value, textKey);
}
else
isShortcut = true;
if (StringBeginsWith(textKey, incrementalString,
nsCaseInsensitiveStringComparator())) {
// mIncrementalString is a prefix of textKey
nsMenuFrame* menu = do_QueryFrame(currFrame);
if (menu) {
// There is one match
matchCount++;
if (isShortcut) {
// There is one shortcut-key match
matchShortcutCount++;
// Record the matched item. If there is only one matched shortcut item, do it
frameShortcut = menu;
}
if (!foundActive) {
// It's a first candidate item located before/on the current item
if (!frameBefore)
frameBefore = menu;
}
else {
// It's a first candidate item located after the current item
if (!frameAfter)
frameAfter = menu;
}
}
else
isShortcut = true;
return nullptr;
}
if (StringBeginsWith(textKey, incrementalString,
nsCaseInsensitiveStringComparator())) {
// mIncrementalString is a prefix of textKey
nsMenuFrame* menu = do_QueryFrame(currFrame);
if (menu) {
// There is one match
matchCount++;
if (isShortcut) {
// There is one shortcut-key match
matchShortcutCount++;
// Record the matched item. If there is only one matched shortcut item, do it
frameShortcut = menu;
}
if (!foundActive) {
// It's a first candidate item located before/on the current item
if (!frameBefore)
frameBefore = menu;
}
else {
// It's a first candidate item located after the current item
if (!frameAfter)
frameAfter = menu;
}
}
else
return nullptr;
}
// Get the active status
if (current->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
nsGkAtoms::_true, eCaseMatters)) {
foundActive = true;
if (stringLength > 1) {
// If there is more than one char typed, the current item has highest priority,
// otherwise the item next to current has highest priority
if (currFrame == frameBefore)
return frameBefore;
}
// Get the active status
if (current->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
nsGkAtoms::_true, eCaseMatters)) {
foundActive = true;
if (stringLength > 1) {
// If there is more than one char typed, the current item has highest priority,
// otherwise the item next to current has highest priority
if (currFrame == frameBefore)
return frameBefore;
}
}
currFrame = currFrame->GetNextSibling();
nsMenuFrame* menu = do_QueryFrame(currFrame);
currFrame = nsXULPopupManager::GetNextMenuItem(immediateParent, menu, true);
if (currFrame == firstMenuItem)
break;
}
doAction = (isMenu && (matchCount == 1 || matchShortcutCount == 1));

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

@ -1761,7 +1761,10 @@ nsXULPopupManager::UpdateMenuItems(nsIContent* aPopup)
for (nsCOMPtr<nsIContent> grandChild = aPopup->GetFirstChild();
grandChild;
grandChild = grandChild->GetNextSibling()) {
if (grandChild->NodeInfo()->Equals(nsGkAtoms::menuitem, kNameSpaceID_XUL)) {
if (grandChild->IsXUL(nsGkAtoms::menugroup)) {
grandChild = grandChild->GetFirstChild();
}
if (grandChild->IsXUL(nsGkAtoms::menuitem)) {
// See if we have a command attribute.
nsAutoString command;
grandChild->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
@ -1794,6 +1797,10 @@ nsXULPopupManager::UpdateMenuItems(nsIContent* aPopup)
}
}
}
if (!grandChild->GetNextSibling() &&
grandChild->GetParent()->IsXUL(nsGkAtoms::menugroup)) {
grandChild = grandChild->GetParent();
}
}
}
@ -2155,17 +2162,28 @@ nsXULPopupManager::GetNextMenuItem(nsContainerFrame* aParent,
immediateParent = aParent;
nsIFrame* currFrame = nullptr;
if (aStart)
currFrame = aStart->GetNextSibling();
else
if (aStart) {
if (aStart->GetNextSibling())
currFrame = aStart->GetNextSibling();
else if (aStart->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = aStart->GetParent()->GetNextSibling();
}
else
currFrame = immediateParent->GetFirstPrincipalChild();
while (currFrame) {
// See if it's a menu item.
if (IsValidMenuItem(presContext, currFrame->GetContent(), aIsPopup)) {
nsIContent* currFrameContent = currFrame->GetContent();
if (IsValidMenuItem(presContext, currFrameContent, aIsPopup)) {
return do_QueryFrame(currFrame);
}
currFrame = currFrame->GetNextSibling();
if (currFrameContent->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetFirstPrincipalChild();
else if (!currFrame->GetNextSibling() &&
currFrame->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetParent()->GetNextSibling();
else
currFrame = currFrame->GetNextSibling();
}
currFrame = immediateParent->GetFirstPrincipalChild();
@ -2173,11 +2191,17 @@ nsXULPopupManager::GetNextMenuItem(nsContainerFrame* aParent,
// Still don't have anything. Try cycling from the beginning.
while (currFrame && currFrame != aStart) {
// See if it's a menu item.
if (IsValidMenuItem(presContext, currFrame->GetContent(), aIsPopup)) {
nsIContent* currFrameContent = currFrame->GetContent();
if (IsValidMenuItem(presContext, currFrameContent, aIsPopup)) {
return do_QueryFrame(currFrame);
}
currFrame = currFrame->GetNextSibling();
if (currFrameContent->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetFirstPrincipalChild();
else if (!currFrame->GetNextSibling() &&
currFrame->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetParent()->GetNextSibling();
else
currFrame = currFrame->GetNextSibling();
}
// No luck. Just return our start value.
@ -2198,17 +2222,30 @@ nsXULPopupManager::GetPreviousMenuItem(nsContainerFrame* aParent,
const nsFrameList& frames(immediateParent->PrincipalChildList());
nsIFrame* currFrame = nullptr;
if (aStart)
currFrame = aStart->GetPrevSibling();
if (aStart) {
if (aStart->GetPrevSibling())
currFrame = aStart->GetPrevSibling();
else if (aStart->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = aStart->GetParent()->GetPrevSibling();
}
else
currFrame = frames.LastChild();
while (currFrame) {
// See if it's a menu item.
if (IsValidMenuItem(presContext, currFrame->GetContent(), aIsPopup)) {
nsIContent* currFrameContent = currFrame->GetContent();
if (IsValidMenuItem(presContext, currFrameContent, aIsPopup)) {
return do_QueryFrame(currFrame);
}
currFrame = currFrame->GetPrevSibling();
if (currFrameContent->IsXUL(nsGkAtoms::menugroup)) {
const nsFrameList& menugroupFrames(currFrame->PrincipalChildList());
currFrame = menugroupFrames.LastChild();
}
else if (!currFrame->GetPrevSibling() &&
currFrame->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetParent()->GetPrevSibling();
else
currFrame = currFrame->GetPrevSibling();
}
currFrame = frames.LastChild();
@ -2216,11 +2253,19 @@ nsXULPopupManager::GetPreviousMenuItem(nsContainerFrame* aParent,
// Still don't have anything. Try cycling from the end.
while (currFrame && currFrame != aStart) {
// See if it's a menu item.
if (IsValidMenuItem(presContext, currFrame->GetContent(), aIsPopup)) {
nsIContent* currFrameContent = currFrame->GetContent();
if (IsValidMenuItem(presContext, currFrameContent, aIsPopup)) {
return do_QueryFrame(currFrame);
}
currFrame = currFrame->GetPrevSibling();
if (currFrameContent->IsXUL(nsGkAtoms::menugroup)) {
const nsFrameList& menugroupFrames(currFrame->PrincipalChildList());
currFrame = menugroupFrames.LastChild();
}
else if (!currFrame->GetPrevSibling() &&
currFrame->GetParent()->GetContent()->IsXUL(nsGkAtoms::menugroup))
currFrame = currFrame->GetParent()->GetPrevSibling();
else
currFrame = currFrame->GetPrevSibling();
}
// No luck. Just return our start value.

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

@ -25,6 +25,9 @@ public interface TelemetryContract {
// Cancel a state, action, etc.
public static final String CANCEL = "cancel.1";
// Editing an item.
public static final String EDIT = "edit.1";
// Launching (opening) an external application.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String LAUNCH = "launch.1";
@ -39,6 +42,9 @@ public interface TelemetryContract {
// Set default panel.
public static final String PANEL_SET_DEFAULT = "setdefault.1";
// Pinning an item.
public static final String PIN = "pin.1";
// Outcome of data policy notification: can be true or false.
public static final String POLICY_NOTIFICATION_SUCCESS = "policynotification.success.1:";
@ -52,14 +58,8 @@ public interface TelemetryContract {
// Sharing content.
public static final String SHARE = "share.1";
// Top site edited.
public static final String TOP_SITES_EDIT = "edit.1";
// Top site pinned.
public static final String TOP_SITES_PIN = "pin.1";
// Top site un-pinned.
public static final String TOP_SITES_UNPIN = "unpin.1";
// Unpinning an item.
public static final String UNPIN = "unpin.1";
// Stop holding a resource (reader, bookmark, etc) for viewing later.
// Note: Only used in JavaScript for now, but here for completeness.
@ -69,11 +69,10 @@ public interface TelemetryContract {
/**
* Holds event methods. Intended for use in
* Telemetry.sendUIEvent() as the "method" parameter.
*
* Please keep this list sorted.
*/
public interface Method {
// Action triggered from a list.
public static final String LIST = "list";
// Action triggered from the action bar (including the toolbar).
public static final String ACTIONBAR = "actionbar";
@ -83,40 +82,51 @@ public interface TelemetryContract {
// Action triggered from a button.
public static final String BUTTON = "button";
// Action triggered from a dialog.
public static final String DIALOG = "dialog";
// Action occurred via an intent.
public static final String INTENT = "intent";
// Action occurred via the main menu.
public static final String MENU = "menu";
// Action occurred via a context menu.
public static final String CONTEXT_MENU = "contextmenu";
// Action triggered from a dialog.
public static final String DIALOG = "dialog";
// Action triggered from a view grid item, like a thumbnail.
public static final String GRID_ITEM = "griditem";
// Action occurred via an intent.
public static final String INTENT = "intent";
// Action triggered from a list.
public static final String LIST = "list";
// Action triggered from a view list item, like a row of a list.
public static final String LIST_ITEM = "listitem";
// Action triggered from a suggestion provided to the user.
public static final String SUGGESTION = "suggestion";
// Action occurred via the main menu.
public static final String MENU = "menu";
// Action triggered from a pageaction in the URLBar.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String PAGEACTION = "pageaction";
// Action triggered from a suggestion provided to the user.
public static final String SUGGESTION = "suggestion";
}
/**
* Holds session names. Intended for use with
* Telemetry.startUISession() as the "sessionName" parameter.
*
* Please keep this list sorted.
*/
public interface Session {
// Awesomescreen (including frecency search) is active.
public static final String AWESOMESCREEN = "awesomescreen.1";
// Started the very first time we believe the application has been launched.
public static final String FIRSTRUN = "firstrun.1";
// Awesomescreen frecency search is active.
public static final String FRECENCY = "frecency.1";
// Started when a user enters about:home.
public static final String HOME = "home.1";
@ -127,17 +137,13 @@ public interface TelemetryContract {
// Started when a Reader viewer becomes active in the foreground.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String READER = "reader.1";
// Awesomescreen frecency search is active.
public static final String FRECENCY = "frecency.1";
// Started the very first time we believe the application has been launched.
public static final String FIRSTRUN = "firstrun.1";
}
/**
* Holds reasons for stopping a session. Intended for use in
* Telemetry.stopUISession() as the "reason" parameter.
*
* Please keep this list sorted.
*/
public interface Reason {
// Changes were committed.

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

@ -328,7 +328,7 @@ public class TopSitesPanel extends HomeFragment {
}
});
Telemetry.sendUIEvent(TelemetryContract.Event.TOP_SITES_PIN);
Telemetry.sendUIEvent(TelemetryContract.Event.PIN);
return true;
}
@ -343,7 +343,7 @@ public class TopSitesPanel extends HomeFragment {
}
});
Telemetry.sendUIEvent(TelemetryContract.Event.TOP_SITES_UNPIN);
Telemetry.sendUIEvent(TelemetryContract.Event.UNPIN);
return true;
}
@ -352,7 +352,7 @@ public class TopSitesPanel extends HomeFragment {
// Decode "user-entered" URLs before showing them.
mEditPinnedSiteListener.onEditPinnedSite(info.position, decodeUserEnteredUrl(info.url));
Telemetry.sendUIEvent(TelemetryContract.Event.TOP_SITES_EDIT);
Telemetry.sendUIEvent(TelemetryContract.Event.EDIT);
return true;
}

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

@ -36,9 +36,7 @@ skip-if = android_version == "10" || processor == "x86"
# disabled on 2.3; bug 986172
skip-if = android_version == "10"
[testFilterOpenTab]
[testFindInPage]
# disabled on Android 2.3; bug 975155
skip-if = android_version == "10"
# [testFindInPage] # see bug 975155, bug 1014708
[testFlingCorrectness]
# disabled on x86 only; bug 927476
skip-if = processor == "x86"

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

@ -15,11 +15,9 @@ public class testFindInPage extends PixelTest {
String url = getAbsoluteUrl("/robocop/robocop_text_page.html");
loadAndPaint(url);
// Select the upper left corner of the screen
height = mDriver.getGeckoHeight()/8;
width = mDriver.getGeckoWidth()/8;
width = mDriver.getGeckoWidth()/2;
/* Disabled by bug 958111.
// Search that does not find the term and therefor should not pan the page
Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
findText("Robocoop", 3); // This will be close enough to existing text to test that search finds just what it should
@ -30,12 +28,11 @@ public class testFindInPage extends PixelTest {
} finally {
painted.close();
}
*/
// Search that finds matches and therefor pans the page
Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
paintExpecter = mActions.expectPaint();
findText("Robocop", 3);
PaintedSurface painted = waitForPaint(paintExpecter);
painted = waitForPaint(paintExpecter);
paintExpecter.unregisterListener();
try {
mAsserter.isnotpixel(painted.getPixelAt(width,height), 255, 0, 0, "Pixel at " + String.valueOf(width) + "," + String.valueOf(height));

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

@ -77,7 +77,8 @@ var FindHelper = {
this._targetTab.sendViewportUpdate();
}
} else {
ZoomHelper.zoomToRect(aData.rect, -1, false, true);
// Disabled until bug 1014113 is fixed
//ZoomHelper.zoomToRect(aData.rect, -1, false, true);
this._viewportChanged = true;
}
}

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

@ -247,6 +247,9 @@ var Addons = {
let list = document.getElementById("addons-list");
list.innerHTML = "";
aAddons.sort(function(a,b) {
return a.name.localeCompare(b.name);
});
for (let i=0; i<aAddons.length; i++) {
let item = self._createItemForAddon(aAddons[i]);
list.appendChild(item);

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

@ -3883,9 +3883,12 @@ Tab.prototype = {
// Once document is fully loaded, parse it
Reader.parseDocumentFromTab(this.id, function (article) {
// The loaded page may have changed while we were parsing the document.
// Make sure we've got the current one.
let uri = this.browser.currentURI;
let tabURL = uri.specIgnoringRef;
// Do nothing if there's no article or the page in this tab has
// changed
let tabURL = uri.specIgnoringRef;
if (article == null || (article.url != tabURL)) {
// Don't clear the article for about:reader pages since we want to
// use the article from the previous page

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

@ -77,7 +77,7 @@ this.BookmarkJSONUtils = Object.freeze({
* before executing the restore.
*
* @param aFilePath
* OS.File path string of bookmarks in JSON format to be restored.
* OS.File path string of bookmarks in JSON or JSONlz4 format to be restored.
* @param aReplace
* Boolean if true, replace existing bookmarks, else merge.
*
@ -101,8 +101,11 @@ this.BookmarkJSONUtils = Object.freeze({
throw new Error("Cannot restore from nonexisting json file");
let importer = new BookmarkImporter(aReplace);
yield importer.importFromURL(OS.Path.toFileURI(aFilePath));
if (aFilePath.endsWith("jsonlz4")) {
yield importer.importFromCompressedFile(aFilePath);
} else {
yield importer.importFromURL(OS.Path.toFileURI(aFilePath));
}
notifyObservers(PlacesUtils.TOPIC_BOOKMARKS_RESTORE_SUCCESS);
} catch(ex) {
Cu.reportError("Failed to restore bookmarks from " + aFilePath + ": " + ex);
@ -116,11 +119,12 @@ this.BookmarkJSONUtils = Object.freeze({
* Serializes bookmarks using JSON, and writes to the supplied file path.
*
* @param aFilePath
* OS.File path string for the "bookmarks.json" file to be created.
* OS.File path string for the bookmarks file to be created.
* @param [optional] aOptions
* Object containing options for the export:
* - failIfHashIs: if the generated file would have the same hash
* defined here, will reject with ex.becauseSameHash
* - compress: if true, writes file using lz4 compression
* @return {Promise}
* @resolves once the file has been created, to an object with the
* following properties:
@ -169,8 +173,11 @@ this.BookmarkJSONUtils = Object.freeze({
// Do not write to the tmp folder, otherwise if it has a different
// filesystem writeAtomic will fail. Eventual dangling .tmp files should
// be cleaned up by the caller.
yield OS.File.writeAtomic(aFilePath, jsonString,
{ tmpPath: OS.Path.join(aFilePath + ".tmp") });
let writeOptions = { tmpPath: OS.Path.join(aFilePath + ".tmp") };
if (aOptions.compress)
writeOptions.compression = "lz4";
yield OS.File.writeAtomic(aFilePath, jsonString, writeOptions);
return { count: count, hash: hash };
});
}
@ -226,6 +233,25 @@ BookmarkImporter.prototype = {
return deferred.promise;
},
/**
* Import bookmarks from a compressed file.
*
* @param aFilePath
* OS.File path string of the bookmark data.
*
* @return {Promise}
* @resolves When the new bookmarks have been created.
* @rejects JavaScript exception.
*/
importFromCompressedFile: function* BI_importFromCompressedFile(aFilePath) {
let aResult = yield OS.File.read(aFilePath, { compression: "lz4" });
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let jsonString = converter.convertFromByteArray(aResult, aResult.length);
yield this.importFromJSON(jsonString);
},
/**
* Import bookmarks from a JSON string.
*

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

@ -29,7 +29,7 @@ XPCOMUtils.defineLazyGetter(this, "localFileCtor",
"nsILocalFile", "initWithPath"));
XPCOMUtils.defineLazyGetter(this, "filenamesRegex",
() => new RegExp("^bookmarks-([0-9\-]+)(?:_([0-9]+)){0,1}(?:_([a-z0-9=\+\-]{24})){0,1}\.(json|html)", "i")
() => new RegExp("^bookmarks-([0-9\-]+)(?:_([0-9]+)){0,1}(?:_([a-z0-9=\+\-]{24})){0,1}\.(json(lz4)?)$", "i")
);
/**
@ -225,13 +225,17 @@ this.PlacesBackups = {
* @param [optional] aDateObj
* Date object used to build the filename.
* Will use current date if empty.
* @param [optional] bool - aCompress
* Determines if file extension is json or jsonlz4
Default is json
* @return A bookmarks backup filename.
*/
getFilenameForDate: function PB_getFilenameForDate(aDateObj) {
getFilenameForDate: function PB_getFilenameForDate(aDateObj, aCompress) {
let dateObj = aDateObj || new Date();
// Use YYYY-MM-DD (ISO 8601) as it doesn't contain illegal characters
// and makes the alphabetical order of multiple backup files more useful.
return "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json";
return "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json" +
(aCompress ? "lz4" : "");
},
/**
@ -262,7 +266,7 @@ this.PlacesBackups = {
"https://bugzilla.mozilla.org/show_bug.cgi?id=859695");
for (let i = 0; i < this._entries.length; i++) {
let rx = new RegExp("\.json$");
let rx = new RegExp("\.json(lz4)?$");
if (this._entries[i].leafName.match(rx))
return this._entries[i];
}
@ -279,7 +283,7 @@ this.PlacesBackups = {
return Task.spawn(function* () {
let entries = yield this.getBackupFiles();
for (let entry of entries) {
let rx = new RegExp("\.json$");
let rx = new RegExp("\.json(lz4)?$");
if (OS.Path.basename(entry).match(rx)) {
return entry;
}
@ -321,13 +325,13 @@ this.PlacesBackups = {
this._backupFiles.unshift(aFilePath);
} else {
// If we are saving to a folder different than our backups folder, then
// we also want to copy this new backup to it.
// we also want to create a new compressed version in it.
// This way we ensure the latest valid backup is the same saved by the
// user. See bug 424389.
let mostRecentBackupFile = yield this.getMostRecentBackup();
if (!mostRecentBackupFile ||
hash != getHashFromFilename(OS.Path.basename(mostRecentBackupFile))) {
let name = this.getFilenameForDate();
let name = this.getFilenameForDate(undefined, true);
let newFilename = appendMetaDataToFilename(name,
{ count: nodeCount,
hash: hash });
@ -348,8 +352,8 @@ this.PlacesBackups = {
yield this.getBackupFiles();
this._backupFiles.unshift(newFilePath);
}
yield OS.File.copy(aFilePath, newFilePath);
let jsonString = yield OS.File.read(aFilePath);
yield OS.File.writeAtomic(newFilePath, jsonString, { compression: "lz4" });
}
}
@ -359,7 +363,7 @@ this.PlacesBackups = {
/**
* Creates a dated backup in <profile>/bookmarkbackups.
* Stores the bookmarks using JSON.
* Stores the bookmarks using a lz4 compressed JSON file.
* Note: any item that should not be backed up must be annotated with
* "places/excludeFromBackup".
*
@ -396,7 +400,7 @@ this.PlacesBackups = {
// Ensure to initialize _backupFiles
if (!this._backupFiles)
yield this.getBackupFiles();
let newBackupFilename = this.getFilenameForDate();
let newBackupFilename = this.getFilenameForDate(undefined, true);
// If we already have a backup for today we should do nothing, unless we
// were required to enforce a new backup.
let backupFile = yield getBackupFileForSameDate(newBackupFilename);
@ -423,7 +427,8 @@ this.PlacesBackups = {
try {
let { count: nodeCount, hash: hash } =
yield BookmarkJSONUtils.exportToFile(newBackupFile,
{ failIfHashIs: mostRecentHash });
{ compress: true,
failIfHashIs: mostRecentHash });
newFilenameWithMetaData = appendMetaDataToFilename(newBackupFilename,
{ count: nodeCount,
hash: hash });

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

@ -11,13 +11,12 @@ add_task(function check_max_backups_is_respected() {
// Get bookmarkBackups directory
let backupFolder = yield PlacesBackups.getBackupFolder();
// Create an html dummy backup in the past.
let htmlPath = OS.Path.join(backupFolder, "bookmarks-2008-01-01.html");
let htmlFile = yield OS.File.open(htmlPath, { truncate: true });
htmlFile.close();
do_check_true(yield OS.File.exists(htmlPath));
// Create 2 json dummy backups in the past.
let oldJsonPath = OS.Path.join(backupFolder, "bookmarks-2008-01-01.json");
let oldJsonFile = yield OS.File.open(oldJsonPath, { truncate: true });
oldJsonFile.close();
do_check_true(yield OS.File.exists(oldJsonPath));
// Create a json dummy backup in the past.
let jsonPath = OS.Path.join(backupFolder, "bookmarks-2008-01-31.json");
let jsonFile = yield OS.File.open(jsonPath, { truncate: true });
jsonFile.close();
@ -43,7 +42,7 @@ add_task(function check_max_backups_is_respected() {
do_check_eq(count, 2);
do_check_neq(lastBackupPath, null);
do_check_false(yield OS.File.exists(htmlPath));
do_check_false(yield OS.File.exists(oldJsonPath));
do_check_true(yield OS.File.exists(jsonPath));
});

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

@ -0,0 +1,59 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function run_test() {
run_next_test();
}
add_task(function* compress_bookmark_backups_test() {
let backupFolder = yield PlacesBackups.getBackupFolder();
// Check for jsonlz4 extension
let todayFilename = PlacesBackups.getFilenameForDate(new Date(2014, 04, 15), true);
do_check_eq(todayFilename, "bookmarks-2014-05-15.jsonlz4");
yield PlacesBackups.create();
// Check that a backup for today has been created and the regex works fine for lz4.
do_check_eq((yield PlacesBackups.getBackupFiles()).length, 1);
let mostRecentBackupFile = yield PlacesBackups.getMostRecentBackup();
do_check_neq(mostRecentBackupFile, null);
do_check_true(PlacesBackups.filenamesRegex.test(OS.Path.basename(mostRecentBackupFile)));
// The most recent backup file has to be removed since saveBookmarksToJSONFile
// will otherwise over-write the current backup, since it will be made on the
// same date
yield OS.File.remove(mostRecentBackupFile);
do_check_false((yield OS.File.exists(mostRecentBackupFile)));
// Check that, if the user created a custom backup out of the default
// backups folder, it gets copied (compressed) into it.
let jsonFile = OS.Path.join(OS.Constants.Path.profileDir, "bookmarks.json");
yield PlacesBackups.saveBookmarksToJSONFile(jsonFile);
do_check_eq((yield PlacesBackups.getBackupFiles()).length, 1);
// Check if import works from lz4 compressed json
let uri = NetUtil.newURI("http://www.mozilla.org/en-US/");
let bm = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
uri,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bookmark");
// Force create a compressed backup, Remove the bookmark, the restore the backup
yield PlacesBackups.create(undefined, true);
let recentBackup = yield PlacesBackups.getMostRecentBackup();
PlacesUtils.bookmarks.removeItem(bm);
yield BookmarkJSONUtils.importFromFile(recentBackup, true);
let root = PlacesUtils.getFolderContents(PlacesUtils.unfiledBookmarksFolderId).root;
let node = root.getChild(0);
do_check_eq(node.uri, uri.spec);
root.containerOpen = false;
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
// Cleanup.
yield OS.File.remove(jsonFile);
});

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

@ -30,5 +30,6 @@ tail =
[test_protectRoots.js]
[test_818593-store-backup-metadata.js]
[test_818584-discard-duplicate-backups.js]
[test_818587_compress-bookmarks-backups.js]
[test_992901-backup-unsorted-hierarchy.js]
[test_997030-bookmarks-html-encode.js]

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

@ -5,6 +5,7 @@ support-files =
window_menubar.xul
[test_contextmenu_nested.xul]
[test_contextmenu_menugroup.xul]
[test_editor_currentURI.xul]
[test_menubar.xul]
skip-if = os == 'mac'

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

@ -0,0 +1,99 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<window title="Context menugroup Tests"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="popup_shared.js"></script>
<menupopup id="context">
<menugroup>
<menuitem id="a"/>
<menuitem id="b"/>
</menugroup>
<menuitem id="c" label="c"/>
</menupopup>
<button label="Check"/>
<vbox id="popuparea" popup="context" width="20" height="20"/>
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
var gMenuPopup = $("context");
ok(gMenuPopup, "Got the reference to the context menu");
var popupTests = [
{
testname: "one-down-key",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "popupshowing context", "popupshown context", "DOMMenuItemActive a" ],
test: function () {
synthesizeMouse($("popuparea"), 4, 4, {});
synthesizeKey("VK_DOWN", {});
},
result: function (testname) {
checkActive(gMenuPopup, "a", testname);
}
},
{
testname: "two-down-keys",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "DOMMenuItemInactive a", "DOMMenuItemActive b" ],
test: function () synthesizeKey("VK_DOWN", {}),
result: function (testname) {
checkActive(gMenuPopup, "b", testname);
}
},
{
testname: "three-down-keys",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "DOMMenuItemInactive b", "DOMMenuItemActive c" ],
test: function () synthesizeKey("VK_DOWN", {}),
result: function (testname) {
checkActive(gMenuPopup, "c", testname);
}
},
{
testname: "three-down-keys-one-up-key",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "DOMMenuItemInactive c", "DOMMenuItemActive b" ],
test: function () synthesizeKey("VK_UP", {}),
result: function (testname) {
checkActive(gMenuPopup, "b", testname);
}
},
{
testname: "three-down-keys-two-up-keys",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "DOMMenuItemInactive b", "DOMMenuItemActive a" ],
test: function () synthesizeKey("VK_UP", {}),
result: function (testname) {
checkActive(gMenuPopup, "a", testname);
}
},
{
testname: "three-down-keys-three-up-key",
condition: function() { return (navigator.platform.indexOf("Mac") == -1); },
events: [ "DOMMenuItemInactive a", "DOMMenuItemActive c" ],
test: function () synthesizeKey("VK_UP", {}),
result: function (testname) {
checkActive(gMenuPopup, "c", testname);
}
},
];
SimpleTest.waitForFocus(function runTest() startPopupTests(popupTests));
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml"><p id="display"/></body>
</window>

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

@ -15,8 +15,8 @@ textbox {
cursor: text;
margin: 2px 4px;
border: 1px solid #555555;
padding: 2px 3px 3px;
-moz-padding-start: 5px;
padding: 2px 2px 3px;
-moz-padding-start: 4px;
background-color: white;
color: black;
}
@ -25,7 +25,7 @@ html|*.textbox-input,
html|*.textbox-textarea {
margin: 0px !important;
border: none !important;
padding: 0px !important;
padding: 0px 1px !important;
background-color: inherit;
color: inherit;
font: inherit;
@ -59,6 +59,11 @@ textbox.plain {
border: none !important;
}
textbox.plain html|*.textbox-input,
textbox.plain html|*.textbox-textarea {
padding: 0px !important;
}
/* ::::: search textbox ::::: */
.textbox-search-icon {

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

@ -14,7 +14,7 @@
/* .padded is used by autocomplete widgets that don't have an icon. Gross. -dwh */
textbox:not(.padded) {
cursor: default;
padding: 0 1px;
padding: 0;
}
textbox[enablehistory="true"] {

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

@ -30,7 +30,7 @@ html|*.numberbox-input {
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
padding: 3px 4px;
padding: 3px;
}
textbox[hidespinbuttons="true"] > .numberbox-input-box {

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

@ -20,8 +20,8 @@ textbox {
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
padding: 2px 3px 3px;
-moz-padding-start: 5px;
padding: 2px 2px 3px;
-moz-padding-start: 4px;
background-color: -moz-Field;
color: -moz-FieldText;
}
@ -30,7 +30,7 @@ html|*.textbox-input,
html|*.textbox-textarea {
margin: 0px !important;
border: none !important;
padding: 0px !important;
padding: 0px 1px !important;
background-color: inherit;
color: inherit;
font: inherit;
@ -65,6 +65,11 @@ textbox.plain {
border: none !important;
}
textbox.plain html|*.textbox-input,
textbox.plain html|*.textbox-textarea {
padding: 0px !important;
}
/* ::::: search textbox ::::: */
.textbox-search-icon {

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

@ -16,7 +16,7 @@ textbox {
-moz-border-left-colors: transparent #888888 #000000;
border-top-right-radius: 2px;
border-bottom-left-radius: 2px;
padding: 0px 1px;
padding: 0px;
background-color: -moz-Field;
color: -moz-FieldText;
}
@ -25,7 +25,7 @@ html|*.textbox-input,
html|*.textbox-textarea {
margin: 0px !important;
border: none !important;
padding: 0px !important;
padding: 0px 1px !important;
background-color: inherit;
color: inherit;
font: inherit;
@ -65,11 +65,16 @@ textbox.plain {
border: none !important;
}
textbox.plain html|*.textbox-input,
textbox.plain html|*.textbox-textarea {
padding: 0px !important;
}
/* ::::: search box ::::: */
textbox[type="search"] {
-moz-appearance: searchfield;
padding: 1px 2px;
padding: 1px;
font-size: 12px;
}
@ -84,7 +89,7 @@ textbox[type="search"] {
}
textbox[type="search"].compact {
padding: 0 1px;
padding: 0;
font-size: 11px;
}

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

@ -20,8 +20,8 @@ textbox {
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
padding: 2px 3px 3px;
-moz-padding-start: 5px;
padding: 2px 2px 3px;
-moz-padding-start: 4px;
background-color: -moz-Field;
color: -moz-FieldText;
}
@ -30,7 +30,7 @@ html|*.textbox-input,
html|*.textbox-textarea {
margin: 0px !important;
border: none !important;
padding: 0px !important;
padding: 0px 1px !important;
background-color: inherit;
color: inherit;
font: inherit;
@ -65,6 +65,11 @@ textbox.plain {
border: none !important;
}
textbox.plain html|*.textbox-input,
textbox.plain html|*.textbox-textarea {
padding: 0px !important;
}
/* ::::: search textbox ::::: */
.textbox-search-icon {