Merge fx-team to m-c. a=merge
|
@ -14,6 +14,30 @@
|
|||
%endif
|
||||
}
|
||||
|
||||
/* These values are chosen to keep the Loop detached chat window from
|
||||
* getting too small. When it's too small, three bad things happen:
|
||||
*
|
||||
* - It looks terrible
|
||||
* - It's not really usable
|
||||
* - It's possible for the user to be transmitting video that's cropped by the
|
||||
* the edge of the window, so that they're not aware of it, which is a
|
||||
* privacy problem
|
||||
*
|
||||
* Note that if the chat window grows more users than Loop who want this
|
||||
* ability, we'll need to generalize. A partial patch for this is in
|
||||
* bug 1112264.
|
||||
*/
|
||||
|
||||
#chat-window {
|
||||
/*
|
||||
* In some ideal world, we'd have a simple way to express "block resizing
|
||||
* along any dimension beyond the point at which an overflow event would
|
||||
* occur". But none of -moz-{fit,max,min}-content do what we want here. So..
|
||||
*/
|
||||
min-width: 320px;
|
||||
min-height: 280px;
|
||||
}
|
||||
|
||||
#main-window[customize-entered] {
|
||||
min-width: -moz-fit-content;
|
||||
}
|
||||
|
@ -849,7 +873,7 @@ toolbarbutton[type="socialmark"] {
|
|||
|
||||
toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
max-width: 16px;
|
||||
max-width: 18px;
|
||||
}
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
max-width: 32px;
|
||||
|
|
|
@ -95,8 +95,8 @@ addMessageListener("MixedContent:ReenableProtection", function() {
|
|||
addMessageListener("SecondScreen:tab-mirror", function(message) {
|
||||
let app = SimpleServiceDiscovery.findAppForService(message.data.service);
|
||||
if (app) {
|
||||
let width = content.scrollWidth;
|
||||
let height = content.scrollHeight;
|
||||
let width = content.innerWidth;
|
||||
let height = content.innerHeight;
|
||||
let viewport = {cssWidth: width, cssHeight: height, width: width, height: height};
|
||||
app.mirror(function() {}, content, viewport, function() {}, content);
|
||||
}
|
||||
|
|
|
@ -1190,6 +1190,10 @@
|
|||
// We need to explicitly focus the new tab, because
|
||||
// tabbox.xml does this only in some cases.
|
||||
this.mCurrentTab.focus();
|
||||
} else if (gMultiProcessBrowser) {
|
||||
// Clear focus so that _adjustFocusAfterTabSwitch can detect if
|
||||
// some element has been focused and respect that.
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
if (!gMultiProcessBrowser)
|
||||
|
@ -1207,12 +1211,12 @@
|
|||
<method name="_adjustFocusAfterTabSwitch">
|
||||
<parameter name="newTab"/>
|
||||
<body><![CDATA[
|
||||
let newBrowser = this.getBrowserForTab(newTab);
|
||||
|
||||
// Don't steal focus from the tab bar.
|
||||
if (document.activeElement == newTab)
|
||||
return;
|
||||
|
||||
let newBrowser = this.getBrowserForTab(newTab);
|
||||
|
||||
// If there's a tabmodal prompt showing, focus it.
|
||||
if (newBrowser.hasAttribute("tabmodalPromptShowing")) {
|
||||
let XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
@ -1226,7 +1230,6 @@
|
|||
// In full screen mode, only bother making the location bar visible
|
||||
// if the tab is a blank one.
|
||||
if (newBrowser._urlbarFocused && gURLBar) {
|
||||
|
||||
// Explicitly close the popup if the URL bar retains focus
|
||||
gURLBar.closePopup();
|
||||
|
||||
|
@ -1248,20 +1251,13 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Otherwise, focus the content area. If we're not using remote tabs, we
|
||||
// can focus the content area right away, since tab switching is synchronous.
|
||||
// If we're using remote tabs, we have to wait until after we've finalized
|
||||
// switching the tabs.
|
||||
|
||||
if (newTab._skipContentFocus) {
|
||||
// It's possible the tab we're switching to is ready to focus asynchronously,
|
||||
// when we've already focused something else. In that case, this
|
||||
// _skipContentFocus property can be set so that we skip focusing the
|
||||
// content after we switch tabs.
|
||||
delete newTab._skipContentFocus;
|
||||
// Don't focus the content area if something has been focused after the
|
||||
// tab switch was initiated.
|
||||
if (gMultiProcessBrowser &&
|
||||
document.activeElement != document.documentElement)
|
||||
return;
|
||||
}
|
||||
|
||||
// We're now committed to focusing the content area.
|
||||
let fm = Services.focus;
|
||||
let focusFlags = fm.FLAG_NOSCROLL;
|
||||
|
||||
|
|
|
@ -1035,17 +1035,17 @@
|
|||
"searchbar-oneoffheader-searchtext");
|
||||
let textbox = searchbar.textbox;
|
||||
let self = this;
|
||||
let keyPressHandler = function() {
|
||||
let inputHandler = function() {
|
||||
headerSearchText.setAttribute("value", textbox.value);
|
||||
if (textbox.value)
|
||||
self.removeAttribute("showonlysettings");
|
||||
};
|
||||
textbox.addEventListener("keyup", keyPressHandler);
|
||||
textbox.addEventListener("input", inputHandler);
|
||||
this.addEventListener("popuphiding", function hiding() {
|
||||
textbox.removeEventListener("keyup", keyPressHandler);
|
||||
textbox.removeEventListener("input", inputHandler);
|
||||
this.removeEventListener("popuphiding", hiding);
|
||||
});
|
||||
keyPressHandler();
|
||||
inputHandler();
|
||||
|
||||
// Handle opensearch items. This needs to be done before building the
|
||||
// list of one off providers, as that code will return early if all the
|
||||
|
@ -1060,8 +1060,6 @@
|
|||
|
||||
let addEngines = gBrowser.selectedBrowser.engines;
|
||||
if (addEngines && addEngines.length > 0) {
|
||||
const kBundleURI = "chrome://browser/locale/search.properties";
|
||||
let bundle = Services.strings.createBundle(kBundleURI);
|
||||
for (let engine of addEngines) {
|
||||
let button = document.createElementNS(kXULNS, "button");
|
||||
let label = bundle.formatStringFromName("cmd_addFoundEngine",
|
||||
|
|
|
@ -309,8 +309,6 @@ function openLinkIn(url, where, params) {
|
|||
// result in a new frontmost window (e.g. "javascript:window.open('');").
|
||||
w.focus();
|
||||
|
||||
let newTab;
|
||||
|
||||
switch (where) {
|
||||
case "current":
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
|
@ -333,7 +331,7 @@ function openLinkIn(url, where, params) {
|
|||
loadInBackground = !loadInBackground;
|
||||
// fall through
|
||||
case "tab":
|
||||
newTab = w.gBrowser.loadOneTab(url, {
|
||||
w.gBrowser.loadOneTab(url, {
|
||||
referrerURI: aReferrerURI,
|
||||
charset: aCharset,
|
||||
postData: aPostData,
|
||||
|
@ -349,12 +347,6 @@ function openLinkIn(url, where, params) {
|
|||
w.gBrowser.selectedBrowser.focus();
|
||||
|
||||
if (!loadInBackground && w.isBlankPageURL(url)) {
|
||||
if (newTab && gMultiProcessBrowser) {
|
||||
// Remote browsers are switched to asynchronously, and we need to
|
||||
// ensure that the location bar remains focused in that case rather
|
||||
// than the content area being focused.
|
||||
newTab._skipContentFocus = true;
|
||||
}
|
||||
w.focusAndSelectUrlBar();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -570,6 +570,27 @@ this.LoopRooms = {
|
|||
return LoopRoomsInternal.maybeRefresh(user);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is only useful for unit tests to set the rooms cache to contain
|
||||
* a list of fake room data that can be asserted in tests.
|
||||
*
|
||||
* @param {Map} stub Stub cache containing fake rooms data
|
||||
*/
|
||||
stubCache: function(stub) {
|
||||
LoopRoomsInternal.rooms.clear();
|
||||
if (stub) {
|
||||
// Fill up the rooms cache with room objects provided in the `stub` Map.
|
||||
for (let [key, value] of stub.entries()) {
|
||||
LoopRoomsInternal.rooms.set(key, value);
|
||||
}
|
||||
gDirty = false;
|
||||
} else {
|
||||
// Restore the cache to not be stubbed anymore, but it'll need a refresh
|
||||
// from the server for sure.
|
||||
gDirty = true;
|
||||
}
|
||||
},
|
||||
|
||||
promise: function(method, ...params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this[method](...params, (error, result) => {
|
||||
|
|
|
@ -23,6 +23,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
|
|||
"resource://gre/modules/MozSocialAPI.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "appInfo", function() {
|
||||
return Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULAppInfo)
|
||||
|
@ -735,7 +737,21 @@ function injectLoopAPI(targetWindow) {
|
|||
callId: callid
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies the UITour module that an event occurred that it might be
|
||||
* interested in.
|
||||
*
|
||||
* @param {String} subject Subject of the notification
|
||||
*/
|
||||
notifyUITour: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function(subject) {
|
||||
UITour.notify(subject);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function onStatusChanged(aSubject, aTopic, aData) {
|
||||
|
|
|
@ -81,6 +81,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
handleTextareaKeyDown: function(event) {
|
||||
// Submit the form as soon as the user press Enter in that field
|
||||
// Note: We're using a textarea instead of a simple text input to display
|
||||
// placeholder and entered text on two lines, to circumvent l10n
|
||||
// rendering/UX issues for some locales.
|
||||
if (event.which === 13) {
|
||||
this.handleFormSubmit(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleFormSubmit: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
|
@ -129,9 +139,10 @@ loop.roomViews = (function(mozL10n) {
|
|||
mozL10n.get("rooms_name_change_failed_label")
|
||||
),
|
||||
React.DOM.form({onSubmit: this.handleFormSubmit},
|
||||
React.DOM.input({type: "text", className: "input-room-name",
|
||||
React.DOM.textarea({rows: "2", type: "text", className: "input-room-name",
|
||||
valueLink: this.linkState("newRoomName"),
|
||||
onBlur: this.handleFormSubmit,
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: mozL10n.get("rooms_name_this_room_label")})
|
||||
),
|
||||
React.DOM.p(null, mozL10n.get("invite_header_text")),
|
||||
|
|
|
@ -81,6 +81,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.stopListening(this.props.roomStore);
|
||||
},
|
||||
|
||||
handleTextareaKeyDown: function(event) {
|
||||
// Submit the form as soon as the user press Enter in that field
|
||||
// Note: We're using a textarea instead of a simple text input to display
|
||||
// placeholder and entered text on two lines, to circumvent l10n
|
||||
// rendering/UX issues for some locales.
|
||||
if (event.which === 13) {
|
||||
this.handleFormSubmit(event);
|
||||
}
|
||||
},
|
||||
|
||||
handleFormSubmit: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
|
@ -129,9 +139,10 @@ loop.roomViews = (function(mozL10n) {
|
|||
{mozL10n.get("rooms_name_change_failed_label")}
|
||||
</p>
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<input type="text" className="input-room-name"
|
||||
<textarea rows="2" type="text" className="input-room-name"
|
||||
valueLink={this.linkState("newRoomName")}
|
||||
onBlur={this.handleFormSubmit}
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder={mozL10n.get("rooms_name_this_room_label")} />
|
||||
</form>
|
||||
<p>{mozL10n.get("invite_header_text")}</p>
|
||||
|
|
|
@ -810,15 +810,20 @@ html, .fx-embedded, #main,
|
|||
}
|
||||
|
||||
.room-invitation-overlay form {
|
||||
padding: 8em 0 2.5em 0;
|
||||
padding: 6em 0 2em 0;
|
||||
}
|
||||
|
||||
.room-invitation-overlay input[type="text"] {
|
||||
.room-invitation-overlay textarea {
|
||||
display: block;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
color: #fff;
|
||||
font-family: "Helvetica Neue", Arial, sans;
|
||||
font-size: 1.2em;
|
||||
border: none;
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
padding: .2em .4em;
|
||||
border-radius: .5em;
|
||||
}
|
||||
|
||||
.room-invitation-overlay .btn-group {
|
||||
|
|
|
@ -298,6 +298,7 @@ loop.store = loop.store || {};
|
|||
*/
|
||||
copyRoomUrl: function(actionData) {
|
||||
this._mozLoop.copyString(actionData.roomUrl);
|
||||
this._mozLoop.notifyUITour("Loop:RoomURLCopied");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -307,6 +308,7 @@ loop.store = loop.store || {};
|
|||
*/
|
||||
emailRoomUrl: function(actionData) {
|
||||
loop.shared.utils.composeCallUrlEmail(actionData.roomUrl);
|
||||
this._mozLoop.notifyUITour("Loop:RoomURLEmailed");
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -146,9 +146,9 @@ describe("loop.roomViews", function () {
|
|||
}));
|
||||
});
|
||||
|
||||
it("should dispatch a RenameRoom action when enter is pressed",
|
||||
it("should dispatch a RenameRoom action when Enter key is pressed",
|
||||
function() {
|
||||
React.addons.TestUtils.Simulate.submit(roomNameBox);
|
||||
TestUtils.Simulate.keyDown(roomNameBox, {key: "Enter", which: 13});
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
|
|
|
@ -77,6 +77,7 @@ describe("loop.store.RoomStore", function () {
|
|||
beforeEach(function() {
|
||||
fakeMozLoop = {
|
||||
copyString: function() {},
|
||||
notifyUITour: function() {},
|
||||
rooms: {
|
||||
create: function() {},
|
||||
getAll: function() {},
|
||||
|
|
|
@ -704,7 +704,11 @@
|
|||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
React.renderComponent(App(null), document.body);
|
||||
try {
|
||||
React.renderComponent(App(null), document.body);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
_renderComponentsInIframes();
|
||||
|
||||
|
|
|
@ -704,7 +704,11 @@
|
|||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
React.renderComponent(<App />, document.body);
|
||||
try {
|
||||
React.renderComponent(<App />, document.body);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
_renderComponentsInIframes();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<?xml-stylesheet
|
||||
href="chrome://browser/content/preferences/handlers.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/preferences/in-content/search.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/in-content/search.css"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const ENGINE_FLAVOR = "text/x-moz-search-engine";
|
||||
|
||||
var gEngineView = null;
|
||||
|
||||
var gSearchPane = {
|
||||
|
||||
init: function ()
|
||||
|
@ -15,9 +19,37 @@ var gSearchPane = {
|
|||
return;
|
||||
}
|
||||
|
||||
gEngineView = new EngineView(new EngineStore());
|
||||
document.getElementById("engineList").view = gEngineView;
|
||||
this.buildDefaultEngineDropDown();
|
||||
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", false);
|
||||
window.addEventListener("unload", () => {
|
||||
Services.obs.removeObserver(this, "browser-search-engine-modified", false);
|
||||
});
|
||||
},
|
||||
|
||||
buildDefaultEngineDropDown: function() {
|
||||
// This is called each time something affects the list of engines.
|
||||
let list = document.getElementById("defaultEngine");
|
||||
let currentEngine = Services.search.currentEngine.name;
|
||||
Services.search.getVisibleEngines().forEach(e => {
|
||||
let currentEngine;
|
||||
|
||||
// First, try to preserve the current selection.
|
||||
if (list.selectedItem)
|
||||
currentEngine = list.selectedItem.label;
|
||||
|
||||
// If there's no current selection, use the current default engine.
|
||||
if (!currentEngine)
|
||||
currentEngine = Services.search.currentEngine.name;
|
||||
|
||||
// If the current engine isn't in the list any more, select the first item.
|
||||
let engines = gEngineView._engineStore._engines;
|
||||
if (!engines.some(e => e.name == currentEngine))
|
||||
currentEngine = engines[0].name;
|
||||
|
||||
// Now clean-up and rebuild the list.
|
||||
list.removeAllItems();
|
||||
gEngineView._engineStore._engines.forEach(e => {
|
||||
let item = list.appendItem(e.name);
|
||||
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
|
||||
if (e.iconURI)
|
||||
|
@ -26,42 +58,119 @@ var gSearchPane = {
|
|||
if (e.name == currentEngine)
|
||||
list.selectedItem = item;
|
||||
});
|
||||
|
||||
this.displayOneClickEnginesList();
|
||||
|
||||
document.getElementById("oneClickProvidersList")
|
||||
.addEventListener("CheckboxStateChange", gSearchPane.saveOneClickEnginesList);
|
||||
},
|
||||
|
||||
displayOneClickEnginesList: function () {
|
||||
let richlistbox = document.getElementById("oneClickProvidersList");
|
||||
let pref = document.getElementById("browser.search.hiddenOneOffs").value;
|
||||
let hiddenList = pref ? pref.split(",") : [];
|
||||
observe: function(aEngine, aTopic, aVerb) {
|
||||
if (aTopic == "browser-search-engine-modified") {
|
||||
aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
|
||||
switch (aVerb) {
|
||||
case "engine-added":
|
||||
gEngineView._engineStore.addEngine(aEngine);
|
||||
gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
break;
|
||||
case "engine-changed":
|
||||
gEngineView._engineStore.reloadIcons();
|
||||
gEngineView.invalidate();
|
||||
break;
|
||||
case "engine-removed":
|
||||
case "engine-current":
|
||||
case "engine-default":
|
||||
// Not relevant
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
while (richlistbox.firstChild)
|
||||
richlistbox.firstChild.remove();
|
||||
onTreeSelect: function() {
|
||||
document.getElementById("removeEngineButton").disabled =
|
||||
gEngineView.selectedIndex == -1 || gEngineView.lastIndex == 0;
|
||||
},
|
||||
|
||||
let currentEngine = Services.search.currentEngine.name;
|
||||
Services.search.getVisibleEngines().forEach(e => {
|
||||
if (e.name == currentEngine)
|
||||
return;
|
||||
onTreeKeyPress: function(aEvent) {
|
||||
let index = gEngineView.selectedIndex;
|
||||
let tree = document.getElementById("engineList");
|
||||
if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
|
||||
// Space toggles the checkbox.
|
||||
let newValue = !gEngineView._engineStore.engines[index].shown;
|
||||
gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
|
||||
newValue.toString());
|
||||
}
|
||||
else {
|
||||
let isMac = Services.appinfo.OS == "Darwin";
|
||||
if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
|
||||
(!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2))
|
||||
tree.startEditing(index, tree.columns.getLastColumn());
|
||||
}
|
||||
},
|
||||
|
||||
let item = document.createElement("richlistitem");
|
||||
item.setAttribute("label", e.name);
|
||||
if (hiddenList.indexOf(e.name) == -1)
|
||||
item.setAttribute("checked", "true");
|
||||
if (e.iconURI)
|
||||
item.setAttribute("src", e.iconURI.spec);
|
||||
richlistbox.appendChild(item);
|
||||
});
|
||||
onRestoreDefaults: function() {
|
||||
let num = gEngineView._engineStore.restoreDefaultEngines();
|
||||
gEngineView.rowCountChanged(0, num);
|
||||
gEngineView.invalidate();
|
||||
},
|
||||
|
||||
showRestoreDefaults: function(aEnable) {
|
||||
document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
gEngineView._engineStore.removeEngine(gEngineView.selectedEngine);
|
||||
let index = gEngineView.selectedIndex;
|
||||
gEngineView.rowCountChanged(index, -1);
|
||||
gEngineView.invalidate();
|
||||
gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
|
||||
gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
|
||||
document.getElementById("engineList").focus();
|
||||
},
|
||||
|
||||
editKeyword: function(aEngine, aNewKeyword) {
|
||||
if (aNewKeyword) {
|
||||
let bduplicate = false;
|
||||
let eduplicate = false;
|
||||
let dupName = "";
|
||||
|
||||
try {
|
||||
let bmserv =
|
||||
Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
|
||||
.getService(Components.interfaces.nsINavBookmarksService);
|
||||
if (bmserv.getURIForKeyword(aNewKeyword))
|
||||
bduplicate = true;
|
||||
} catch(ex) {}
|
||||
|
||||
// Check for duplicates in changes we haven't committed yet
|
||||
let engines = gEngineView._engineStore.engines;
|
||||
for each (let engine in engines) {
|
||||
if (engine.alias == aNewKeyword &&
|
||||
engine.name != aEngine.name) {
|
||||
eduplicate = true;
|
||||
dupName = engine.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the user if they have chosen an existing engine/bookmark keyword
|
||||
if (eduplicate || bduplicate) {
|
||||
let strings = document.getElementById("engineManagerBundle");
|
||||
let dtitle = strings.getString("duplicateTitle");
|
||||
let bmsg = strings.getString("duplicateBookmarkMsg");
|
||||
let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
|
||||
|
||||
Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gEngineView._engineStore.changeEngine(aEngine, "alias", aNewKeyword);
|
||||
gEngineView.invalidate();
|
||||
return true;
|
||||
},
|
||||
|
||||
saveOneClickEnginesList: function () {
|
||||
let richlistbox = document.getElementById("oneClickProvidersList");
|
||||
let hiddenList = [];
|
||||
for (let child of richlistbox.childNodes) {
|
||||
if (!child.checked)
|
||||
hiddenList.push(child.getAttribute("label"));
|
||||
for (let engine of gEngineView._engineStore.engines) {
|
||||
if (!engine.shown)
|
||||
hiddenList.push(engine.name);
|
||||
}
|
||||
document.getElementById("browser.search.hiddenOneOffs").value =
|
||||
hiddenList.join(",");
|
||||
|
@ -70,6 +179,273 @@ var gSearchPane = {
|
|||
setDefaultEngine: function () {
|
||||
Services.search.currentEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
this.displayOneClickEnginesList();
|
||||
}
|
||||
};
|
||||
|
||||
function onDragEngineStart(event) {
|
||||
var selectedIndex = gEngineView.selectedIndex;
|
||||
if (selectedIndex >= 0) {
|
||||
event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
|
||||
event.dataTransfer.effectAllowed = "move";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function EngineStore() {
|
||||
let pref = document.getElementById("browser.search.hiddenOneOffs").value;
|
||||
this.hiddenList = pref ? pref.split(",") : [];
|
||||
|
||||
this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
|
||||
this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
|
||||
|
||||
// check if we need to disable the restore defaults button
|
||||
var someHidden = this._defaultEngines.some(function (e) e.hidden);
|
||||
gSearchPane.showRestoreDefaults(someHidden);
|
||||
}
|
||||
EngineStore.prototype = {
|
||||
_engines: null,
|
||||
_defaultEngines: null,
|
||||
|
||||
get engines() {
|
||||
return this._engines;
|
||||
},
|
||||
set engines(val) {
|
||||
this._engines = val;
|
||||
return val;
|
||||
},
|
||||
|
||||
_getIndexForEngine: function ES_getIndexForEngine(aEngine) {
|
||||
return this._engines.indexOf(aEngine);
|
||||
},
|
||||
|
||||
_getEngineByName: function ES_getEngineByName(aName) {
|
||||
for each (var engine in this._engines)
|
||||
if (engine.name == aName)
|
||||
return engine;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_cloneEngine: function ES_cloneEngine(aEngine) {
|
||||
var clonedObj={};
|
||||
for (var i in aEngine)
|
||||
clonedObj[i] = aEngine[i];
|
||||
clonedObj.originalEngine = aEngine;
|
||||
clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
|
||||
return clonedObj;
|
||||
},
|
||||
|
||||
// Callback for Array's some(). A thisObj must be passed to some()
|
||||
_isSameEngine: function ES_isSameEngine(aEngineClone) {
|
||||
return aEngineClone.originalEngine == this.originalEngine;
|
||||
},
|
||||
|
||||
addEngine: function ES_addEngine(aEngine) {
|
||||
this._engines.push(this._cloneEngine(aEngine));
|
||||
},
|
||||
|
||||
moveEngine: function ES_moveEngine(aEngine, aNewIndex) {
|
||||
if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
|
||||
throw new Error("ES_moveEngine: invalid aNewIndex!");
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("ES_moveEngine: invalid engine?");
|
||||
|
||||
if (index == aNewIndex)
|
||||
return; // nothing to do
|
||||
|
||||
// Move the engine in our internal store
|
||||
var removedEngine = this._engines.splice(index, 1)[0];
|
||||
this._engines.splice(aNewIndex, 0, removedEngine);
|
||||
|
||||
Services.search.moveEngine(aEngine.originalEngine, aNewIndex);
|
||||
},
|
||||
|
||||
removeEngine: function ES_removeEngine(aEngine) {
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
this._engines.splice(index, 1);
|
||||
Services.search.removeEngine(aEngine.originalEngine);
|
||||
|
||||
if (this._defaultEngines.some(this._isSameEngine, aEngine))
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
},
|
||||
|
||||
restoreDefaultEngines: function ES_restoreDefaultEngines() {
|
||||
var added = 0;
|
||||
|
||||
for (var i = 0; i < this._defaultEngines.length; ++i) {
|
||||
var e = this._defaultEngines[i];
|
||||
|
||||
// If the engine is already in the list, just move it.
|
||||
if (this._engines.some(this._isSameEngine, e)) {
|
||||
this.moveEngine(this._getEngineByName(e.name), i);
|
||||
} else {
|
||||
// Otherwise, add it back to our internal store
|
||||
this._engines.splice(i, 0, e);
|
||||
let engine = e.originalEngine;
|
||||
engine.hidden = false;
|
||||
Services.search.moveEngine(engine, i);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
gSearchPane.showRestoreDefaults(false);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
return added;
|
||||
},
|
||||
|
||||
changeEngine: function ES_changeEngine(aEngine, aProp, aNewValue) {
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
this._engines[index][aProp] = aNewValue;
|
||||
aEngine.originalEngine[aProp] = aNewValue;
|
||||
},
|
||||
|
||||
reloadIcons: function ES_reloadIcons() {
|
||||
this._engines.forEach(function (e) {
|
||||
e.uri = e.originalEngine.uri;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function EngineView(aEngineStore) {
|
||||
this._engineStore = aEngineStore;
|
||||
}
|
||||
EngineView.prototype = {
|
||||
_engineStore: null,
|
||||
tree: null,
|
||||
|
||||
get lastIndex() {
|
||||
return this.rowCount - 1;
|
||||
},
|
||||
get selectedIndex() {
|
||||
var seln = this.selection;
|
||||
if (seln.getRangeCount() > 0) {
|
||||
var min = {};
|
||||
seln.getRangeAt(0, min, {});
|
||||
return min.value;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
get selectedEngine() {
|
||||
return this._engineStore.engines[this.selectedIndex];
|
||||
},
|
||||
|
||||
// Helpers
|
||||
rowCountChanged: function (index, count) {
|
||||
this.tree.rowCountChanged(index, count);
|
||||
},
|
||||
|
||||
invalidate: function () {
|
||||
this.tree.invalidate();
|
||||
},
|
||||
|
||||
ensureRowIsVisible: function (index) {
|
||||
this.tree.ensureRowIsVisible(index);
|
||||
},
|
||||
|
||||
getSourceIndexFromDrag: function (dataTransfer) {
|
||||
return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
|
||||
},
|
||||
|
||||
// nsITreeView
|
||||
get rowCount() {
|
||||
return this._engineStore.engines.length;
|
||||
},
|
||||
|
||||
getImageSrc: function(index, column) {
|
||||
if (column.id == "engineName" && this._engineStore.engines[index].iconURI)
|
||||
return this._engineStore.engines[index].iconURI.spec;
|
||||
return "";
|
||||
},
|
||||
|
||||
getCellText: function(index, column) {
|
||||
if (column.id == "engineName")
|
||||
return this._engineStore.engines[index].name;
|
||||
else if (column.id == "engineKeyword")
|
||||
return this._engineStore.engines[index].alias;
|
||||
return "";
|
||||
},
|
||||
|
||||
setTree: function(tree) {
|
||||
this.tree = tree;
|
||||
},
|
||||
|
||||
canDrop: function(targetIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
return (sourceIndex != -1 &&
|
||||
sourceIndex != targetIndex &&
|
||||
sourceIndex != targetIndex + orientation);
|
||||
},
|
||||
|
||||
drop: function(dropIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
var sourceEngine = this._engineStore.engines[sourceIndex];
|
||||
|
||||
const nsITreeView = Components.interfaces.nsITreeView;
|
||||
if (dropIndex > sourceIndex) {
|
||||
if (orientation == nsITreeView.DROP_BEFORE)
|
||||
dropIndex--;
|
||||
} else {
|
||||
if (orientation == nsITreeView.DROP_AFTER)
|
||||
dropIndex++;
|
||||
}
|
||||
|
||||
this._engineStore.moveEngine(sourceEngine, dropIndex);
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
|
||||
// Redraw, and adjust selection
|
||||
this.invalidate();
|
||||
this.selection.select(dropIndex);
|
||||
},
|
||||
|
||||
selection: null,
|
||||
getRowProperties: function(index) { return ""; },
|
||||
getCellProperties: function(index, column) { return ""; },
|
||||
getColumnProperties: function(column) { return ""; },
|
||||
isContainer: function(index) { return false; },
|
||||
isContainerOpen: function(index) { return false; },
|
||||
isContainerEmpty: function(index) { return false; },
|
||||
isSeparator: function(index) { return false; },
|
||||
isSorted: function(index) { return false; },
|
||||
getParentIndex: function(index) { return -1; },
|
||||
hasNextSibling: function(parentIndex, index) { return false; },
|
||||
getLevel: function(index) { return 0; },
|
||||
getProgressMode: function(index, column) { },
|
||||
getCellValue: function(index, column) {
|
||||
if (column.id == "engineShown")
|
||||
return this._engineStore.engines[index].shown;
|
||||
return undefined;
|
||||
},
|
||||
toggleOpenState: function(index) { },
|
||||
cycleHeader: function(column) { },
|
||||
selectionChanged: function() { },
|
||||
cycleCell: function(row, column) { },
|
||||
isEditable: function(index, column) { return column.id != "engineName"; },
|
||||
isSelectable: function(index, column) { return false; },
|
||||
setCellValue: function(index, column, value) {
|
||||
if (column.id == "engineShown") {
|
||||
this._engineStore.engines[index].shown = value == "true";
|
||||
gEngineView.invalidate();
|
||||
gSearchPane.saveOneClickEnginesList();
|
||||
}
|
||||
},
|
||||
setCellText: function(index, column, value) {
|
||||
if (column.id == "engineKeyword") {
|
||||
if (!gSearchPane.editKeyword(this._engineStore.engines[index], value)) {
|
||||
setTimeout(() => {
|
||||
document.getElementById("engineList").startEditing(index, column);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
performAction: function(action) { },
|
||||
performActionOnRow: function(action, index) { },
|
||||
performActionOnCell: function(action, index, column) { }
|
||||
};
|
||||
|
|
|
@ -39,8 +39,34 @@
|
|||
<caption label="&oneClickSearchEngines.label;"/>
|
||||
<label>&chooseWhichOneToDisplay.label;</label>
|
||||
|
||||
<richlistbox id="oneClickProvidersList"/>
|
||||
<hbox pack="end">
|
||||
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
|
||||
seltype="single" onselect="gSearchPane.onTreeSelect();"
|
||||
onkeypress="gSearchPane.onTreeKeyPress(event);">
|
||||
<treechildren id="engineChildren" flex="1"
|
||||
ondragstart="onDragEngineStart(event);"/>
|
||||
<treecols>
|
||||
<treecol id="engineShown" type="checkbox" style="min-width: 26px;" editable="true"/>
|
||||
<treecol id="engineName" flex="4" label="&engineNameColumn.label;"/>
|
||||
<treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
|
||||
<hbox>
|
||||
<button id="restoreDefaultSearchEngines"
|
||||
label="&restoreDefaultSearchEngines.label;"
|
||||
accesskey="&restoreDefaultSearchEngines.accesskey;"
|
||||
oncommand="gSearchPane.onRestoreDefaults();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="removeEngineButton"
|
||||
label="&removeEngine.label;"
|
||||
accesskey="&removeEngine.accesskey;"
|
||||
disabled="true"
|
||||
oncommand="gSearchPane.remove();"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox pack="start" style="margin-bottom: 1em">
|
||||
<label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"
|
||||
onclick="if (event.button == 0) { Services.wm.getMostRecentWindow('navigator:browser').BrowserSearch.loadAddEngines(); }"/>
|
||||
</hbox>
|
||||
|
|
|
@ -45,7 +45,6 @@ browser.jar:
|
|||
content/browser/preferences/sync.js
|
||||
#endif
|
||||
content/browser/preferences/search.xul
|
||||
content/browser/preferences/search.css
|
||||
content/browser/preferences/search.js
|
||||
* content/browser/preferences/tabs.xul
|
||||
* content/browser/preferences/tabs.js
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
-->
|
||||
<?xml-stylesheet href="chrome://browser/content/preferences/handlers.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/preferences/search.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?>
|
||||
|
||||
<!DOCTYPE prefwindow [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
#oneClickProvidersList richlistitem {
|
||||
-moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox");
|
||||
-moz-padding-start: 5px;
|
||||
height: 22px; /* setting the height of checkboxes is required to let the
|
||||
window auto-sizing code work. */
|
||||
}
|
||||
|
||||
#oneClickProvidersList {
|
||||
height: 178px;
|
||||
}
|
||||
|
||||
.searchengine-menuitem > .menu-iconic-left {
|
||||
display: -moz-box
|
||||
}
|
||||
|
||||
.checkbox-label-box {
|
||||
-moz-box-align: center;
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.checkbox-icon {
|
||||
margin: 3px 3px;
|
||||
max-width: 16px;
|
||||
}
|
|
@ -4,13 +4,45 @@
|
|||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const ENGINE_FLAVOR = "text/x-moz-search-engine";
|
||||
|
||||
var gEngineView = null;
|
||||
|
||||
var gSearchPane = {
|
||||
|
||||
init: function ()
|
||||
{
|
||||
gEngineView = new EngineView(new EngineStore());
|
||||
document.getElementById("engineList").view = gEngineView;
|
||||
this.buildDefaultEngineDropDown();
|
||||
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", false);
|
||||
window.addEventListener("unload", () => {
|
||||
Services.obs.removeObserver(this, "browser-search-engine-modified", false);
|
||||
});
|
||||
},
|
||||
|
||||
buildDefaultEngineDropDown: function() {
|
||||
// This is called each time something affects the list of engines.
|
||||
let list = document.getElementById("defaultEngine");
|
||||
let currentEngine = Services.search.currentEngine.name;
|
||||
Services.search.getVisibleEngines().forEach(e => {
|
||||
let currentEngine;
|
||||
|
||||
// First, try to preserve the current selection.
|
||||
if (list.selectedItem)
|
||||
currentEngine = list.selectedItem.label;
|
||||
|
||||
// If there's no current selection, use the current default engine.
|
||||
if (!currentEngine)
|
||||
currentEngine = Services.search.currentEngine.name;
|
||||
|
||||
// If the current engine isn't in the list any more, select the first item.
|
||||
let engines = gEngineView._engineStore._engines;
|
||||
if (!engines.some(e => e.name == currentEngine))
|
||||
currentEngine = engines[0].name;
|
||||
|
||||
// Now clean-up and rebuild the list.
|
||||
list.removeAllItems();
|
||||
gEngineView._engineStore._engines.forEach(e => {
|
||||
let item = list.appendItem(e.name);
|
||||
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
|
||||
if (e.iconURI)
|
||||
|
@ -19,50 +51,472 @@ var gSearchPane = {
|
|||
if (e.name == currentEngine)
|
||||
list.selectedItem = item;
|
||||
});
|
||||
|
||||
this.displayOneClickEnginesList();
|
||||
|
||||
document.getElementById("oneClickProvidersList")
|
||||
.addEventListener("CheckboxStateChange", gSearchPane.saveOneClickEnginesList);
|
||||
},
|
||||
|
||||
displayOneClickEnginesList: function () {
|
||||
let richlistbox = document.getElementById("oneClickProvidersList");
|
||||
let pref = document.getElementById("browser.search.hiddenOneOffs").value;
|
||||
let hiddenList = pref ? pref.split(",") : [];
|
||||
observe: function(aEngine, aTopic, aVerb) {
|
||||
if (aTopic == "browser-search-engine-modified") {
|
||||
aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
|
||||
switch (aVerb) {
|
||||
case "engine-added":
|
||||
gEngineView._engineStore.addEngine(aEngine);
|
||||
gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
break;
|
||||
case "engine-changed":
|
||||
gEngineView._engineStore.reloadIcons();
|
||||
gEngineView.invalidate();
|
||||
break;
|
||||
case "engine-removed":
|
||||
case "engine-current":
|
||||
case "engine-default":
|
||||
// Not relevant
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
while (richlistbox.firstChild)
|
||||
richlistbox.firstChild.remove();
|
||||
onTreeSelect: function() {
|
||||
document.getElementById("removeEngineButton").disabled =
|
||||
gEngineView.selectedIndex == -1 || gEngineView.lastIndex == 0;
|
||||
},
|
||||
|
||||
let currentEngine = Services.search.currentEngine.name;
|
||||
Services.search.getVisibleEngines().forEach(e => {
|
||||
if (e.name == currentEngine)
|
||||
return;
|
||||
onTreeKeyPress: function(aEvent) {
|
||||
let index = gEngineView.selectedIndex;
|
||||
let tree = document.getElementById("engineList");
|
||||
if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
|
||||
// Space toggles the checkbox.
|
||||
let newValue = !gEngineView._engineStore.engines[index].shown;
|
||||
gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
|
||||
newValue.toString());
|
||||
}
|
||||
else {
|
||||
let isMac = Services.appinfo.OS == "Darwin";
|
||||
if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
|
||||
(!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2))
|
||||
tree.startEditing(index, tree.columns.getLastColumn());
|
||||
}
|
||||
},
|
||||
|
||||
let item = document.createElement("richlistitem");
|
||||
item.setAttribute("label", e.name);
|
||||
if (hiddenList.indexOf(e.name) == -1)
|
||||
item.setAttribute("checked", "true");
|
||||
if (e.iconURI)
|
||||
item.setAttribute("src", e.iconURI.spec);
|
||||
richlistbox.appendChild(item);
|
||||
});
|
||||
onRestoreDefaults: function() {
|
||||
let num = gEngineView._engineStore.restoreDefaultEngines();
|
||||
gEngineView.rowCountChanged(0, num);
|
||||
gEngineView.invalidate();
|
||||
},
|
||||
|
||||
showRestoreDefaults: function(aEnable) {
|
||||
document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
gEngineView._engineStore.removeEngine(gEngineView.selectedEngine);
|
||||
let index = gEngineView.selectedIndex;
|
||||
gEngineView.rowCountChanged(index, -1);
|
||||
gEngineView.invalidate();
|
||||
gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
|
||||
gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
|
||||
document.getElementById("engineList").focus();
|
||||
},
|
||||
|
||||
editKeyword: function(aEngine, aNewKeyword) {
|
||||
if (aNewKeyword) {
|
||||
let bduplicate = false;
|
||||
let eduplicate = false;
|
||||
let dupName = "";
|
||||
|
||||
try {
|
||||
let bmserv =
|
||||
Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
|
||||
.getService(Components.interfaces.nsINavBookmarksService);
|
||||
if (bmserv.getURIForKeyword(aNewKeyword))
|
||||
bduplicate = true;
|
||||
} catch(ex) {}
|
||||
|
||||
// Check for duplicates in changes we haven't committed yet
|
||||
let engines = gEngineView._engineStore.engines;
|
||||
for each (let engine in engines) {
|
||||
if (engine.alias == aNewKeyword &&
|
||||
engine.name != aEngine.name) {
|
||||
eduplicate = true;
|
||||
dupName = engine.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the user if they have chosen an existing engine/bookmark keyword
|
||||
if (eduplicate || bduplicate) {
|
||||
let strings = document.getElementById("engineManagerBundle");
|
||||
let dtitle = strings.getString("duplicateTitle");
|
||||
let bmsg = strings.getString("duplicateBookmarkMsg");
|
||||
let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
|
||||
|
||||
Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gEngineView._engineStore.changeEngine(aEngine, "alias", aNewKeyword);
|
||||
gEngineView.invalidate();
|
||||
return true;
|
||||
},
|
||||
|
||||
saveOneClickEnginesList: function () {
|
||||
let richlistbox = document.getElementById("oneClickProvidersList");
|
||||
let hiddenList = [];
|
||||
for (let child of richlistbox.childNodes) {
|
||||
if (!child.checked)
|
||||
hiddenList.push(child.getAttribute("label"));
|
||||
for (let engine of gEngineView._engineStore.engines) {
|
||||
if (!engine.shown)
|
||||
hiddenList.push(engine.name);
|
||||
}
|
||||
document.getElementById("browser.search.hiddenOneOffs").value =
|
||||
hiddenList.join(",");
|
||||
},
|
||||
|
||||
setDefaultEngine: function () {
|
||||
Services.search.currentEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
this.displayOneClickEnginesList();
|
||||
if (document.documentElement.instantApply) {
|
||||
Services.search.currentEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onDragEngineStart(event) {
|
||||
var selectedIndex = gEngineView.selectedIndex;
|
||||
if (selectedIndex >= 0) {
|
||||
event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
|
||||
event.dataTransfer.effectAllowed = "move";
|
||||
}
|
||||
}
|
||||
|
||||
// "Operation" objects
|
||||
function EngineMoveOp(aEngineClone, aNewIndex) {
|
||||
if (!aEngineClone)
|
||||
throw new Error("bad args to new EngineMoveOp!");
|
||||
this._engine = aEngineClone.originalEngine;
|
||||
this._newIndex = aNewIndex;
|
||||
}
|
||||
EngineMoveOp.prototype = {
|
||||
_engine: null,
|
||||
_newIndex: null,
|
||||
commit: function EMO_commit() {
|
||||
Services.search.moveEngine(this._engine, this._newIndex);
|
||||
}
|
||||
};
|
||||
|
||||
function EngineRemoveOp(aEngineClone) {
|
||||
if (!aEngineClone)
|
||||
throw new Error("bad args to new EngineRemoveOp!");
|
||||
this._engine = aEngineClone.originalEngine;
|
||||
}
|
||||
EngineRemoveOp.prototype = {
|
||||
_engine: null,
|
||||
commit: function ERO_commit() {
|
||||
Services.search.removeEngine(this._engine);
|
||||
}
|
||||
};
|
||||
|
||||
function EngineUnhideOp(aEngineClone, aNewIndex) {
|
||||
if (!aEngineClone)
|
||||
throw new Error("bad args to new EngineUnhideOp!");
|
||||
this._engine = aEngineClone.originalEngine;
|
||||
this._newIndex = aNewIndex;
|
||||
}
|
||||
EngineUnhideOp.prototype = {
|
||||
_engine: null,
|
||||
_newIndex: null,
|
||||
commit: function EUO_commit() {
|
||||
this._engine.hidden = false;
|
||||
Services.search.moveEngine(this._engine, this._newIndex);
|
||||
}
|
||||
};
|
||||
|
||||
function EngineChangeOp(aEngineClone, aProp, aValue) {
|
||||
if (!aEngineClone)
|
||||
throw new Error("bad args to new EngineChangeOp!");
|
||||
|
||||
this._engine = aEngineClone.originalEngine;
|
||||
this._prop = aProp;
|
||||
this._newValue = aValue;
|
||||
}
|
||||
EngineChangeOp.prototype = {
|
||||
_engine: null,
|
||||
_prop: null,
|
||||
_newValue: null,
|
||||
commit: function ECO_commit() {
|
||||
this._engine[this._prop] = this._newValue;
|
||||
}
|
||||
};
|
||||
|
||||
function EngineStore() {
|
||||
let pref = document.getElementById("browser.search.hiddenOneOffs").value;
|
||||
this.hiddenList = pref ? pref.split(",") : [];
|
||||
|
||||
this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
|
||||
this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
|
||||
|
||||
if (document.documentElement.instantApply) {
|
||||
this._ops = {
|
||||
push: function(op) { op.commit(); }
|
||||
};
|
||||
}
|
||||
else {
|
||||
this._ops = [];
|
||||
document.documentElement.addEventListener("beforeaccept", () => {
|
||||
gEngineView._engineStore.commit();
|
||||
});
|
||||
}
|
||||
|
||||
// check if we need to disable the restore defaults button
|
||||
var someHidden = this._defaultEngines.some(function (e) e.hidden);
|
||||
gSearchPane.showRestoreDefaults(someHidden);
|
||||
}
|
||||
EngineStore.prototype = {
|
||||
_engines: null,
|
||||
_defaultEngines: null,
|
||||
_ops: null,
|
||||
|
||||
get engines() {
|
||||
return this._engines;
|
||||
},
|
||||
set engines(val) {
|
||||
this._engines = val;
|
||||
return val;
|
||||
},
|
||||
|
||||
_getIndexForEngine: function ES_getIndexForEngine(aEngine) {
|
||||
return this._engines.indexOf(aEngine);
|
||||
},
|
||||
|
||||
_getEngineByName: function ES_getEngineByName(aName) {
|
||||
for each (var engine in this._engines)
|
||||
if (engine.name == aName)
|
||||
return engine;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_cloneEngine: function ES_cloneEngine(aEngine) {
|
||||
var clonedObj={};
|
||||
for (var i in aEngine)
|
||||
clonedObj[i] = aEngine[i];
|
||||
clonedObj.originalEngine = aEngine;
|
||||
clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
|
||||
return clonedObj;
|
||||
},
|
||||
|
||||
// Callback for Array's some(). A thisObj must be passed to some()
|
||||
_isSameEngine: function ES_isSameEngine(aEngineClone) {
|
||||
return aEngineClone.originalEngine == this.originalEngine;
|
||||
},
|
||||
|
||||
commit: function ES_commit() {
|
||||
for (op of this._ops)
|
||||
op.commit();
|
||||
|
||||
Services.search.currentEngine =
|
||||
document.getElementById("defaultEngine").selectedItem.engine;
|
||||
},
|
||||
|
||||
addEngine: function ES_addEngine(aEngine) {
|
||||
this._engines.push(this._cloneEngine(aEngine));
|
||||
},
|
||||
|
||||
moveEngine: function ES_moveEngine(aEngine, aNewIndex) {
|
||||
if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
|
||||
throw new Error("ES_moveEngine: invalid aNewIndex!");
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("ES_moveEngine: invalid engine?");
|
||||
|
||||
if (index == aNewIndex)
|
||||
return; // nothing to do
|
||||
|
||||
// Move the engine in our internal store
|
||||
var removedEngine = this._engines.splice(index, 1)[0];
|
||||
this._engines.splice(aNewIndex, 0, removedEngine);
|
||||
|
||||
this._ops.push(new EngineMoveOp(aEngine, aNewIndex));
|
||||
},
|
||||
|
||||
removeEngine: function ES_removeEngine(aEngine) {
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
this._engines.splice(index, 1);
|
||||
this._ops.push(new EngineRemoveOp(aEngine));
|
||||
if (this._defaultEngines.some(this._isSameEngine, aEngine))
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
},
|
||||
|
||||
restoreDefaultEngines: function ES_restoreDefaultEngines() {
|
||||
var added = 0;
|
||||
|
||||
for (var i = 0; i < this._defaultEngines.length; ++i) {
|
||||
var e = this._defaultEngines[i];
|
||||
|
||||
// If the engine is already in the list, just move it.
|
||||
if (this._engines.some(this._isSameEngine, e)) {
|
||||
this.moveEngine(this._getEngineByName(e.name), i);
|
||||
} else {
|
||||
// Otherwise, add it back to our internal store
|
||||
this._engines.splice(i, 0, e);
|
||||
this._ops.push(new EngineUnhideOp(e, i));
|
||||
added++;
|
||||
}
|
||||
}
|
||||
gSearchPane.showRestoreDefaults(false);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
return added;
|
||||
},
|
||||
|
||||
changeEngine: function ES_changeEngine(aEngine, aProp, aNewValue) {
|
||||
var index = this._getIndexForEngine(aEngine);
|
||||
if (index == -1)
|
||||
throw new Error("invalid engine?");
|
||||
|
||||
this._engines[index][aProp] = aNewValue;
|
||||
this._ops.push(new EngineChangeOp(aEngine, aProp, aNewValue));
|
||||
},
|
||||
|
||||
reloadIcons: function ES_reloadIcons() {
|
||||
this._engines.forEach(function (e) {
|
||||
e.uri = e.originalEngine.uri;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function EngineView(aEngineStore) {
|
||||
this._engineStore = aEngineStore;
|
||||
}
|
||||
EngineView.prototype = {
|
||||
_engineStore: null,
|
||||
tree: null,
|
||||
|
||||
get lastIndex() {
|
||||
return this.rowCount - 1;
|
||||
},
|
||||
get selectedIndex() {
|
||||
var seln = this.selection;
|
||||
if (seln.getRangeCount() > 0) {
|
||||
var min = {};
|
||||
seln.getRangeAt(0, min, {});
|
||||
return min.value;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
get selectedEngine() {
|
||||
return this._engineStore.engines[this.selectedIndex];
|
||||
},
|
||||
|
||||
// Helpers
|
||||
rowCountChanged: function (index, count) {
|
||||
this.tree.rowCountChanged(index, count);
|
||||
},
|
||||
|
||||
invalidate: function () {
|
||||
this.tree.invalidate();
|
||||
},
|
||||
|
||||
ensureRowIsVisible: function (index) {
|
||||
this.tree.ensureRowIsVisible(index);
|
||||
},
|
||||
|
||||
getSourceIndexFromDrag: function (dataTransfer) {
|
||||
return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
|
||||
},
|
||||
|
||||
// nsITreeView
|
||||
get rowCount() {
|
||||
return this._engineStore.engines.length;
|
||||
},
|
||||
|
||||
getImageSrc: function(index, column) {
|
||||
if (column.id == "engineName" && this._engineStore.engines[index].iconURI)
|
||||
return this._engineStore.engines[index].iconURI.spec;
|
||||
return "";
|
||||
},
|
||||
|
||||
getCellText: function(index, column) {
|
||||
if (column.id == "engineName")
|
||||
return this._engineStore.engines[index].name;
|
||||
else if (column.id == "engineKeyword")
|
||||
return this._engineStore.engines[index].alias;
|
||||
return "";
|
||||
},
|
||||
|
||||
setTree: function(tree) {
|
||||
this.tree = tree;
|
||||
},
|
||||
|
||||
canDrop: function(targetIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
return (sourceIndex != -1 &&
|
||||
sourceIndex != targetIndex &&
|
||||
sourceIndex != targetIndex + orientation);
|
||||
},
|
||||
|
||||
drop: function(dropIndex, orientation, dataTransfer) {
|
||||
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
|
||||
var sourceEngine = this._engineStore.engines[sourceIndex];
|
||||
|
||||
const nsITreeView = Components.interfaces.nsITreeView;
|
||||
if (dropIndex > sourceIndex) {
|
||||
if (orientation == nsITreeView.DROP_BEFORE)
|
||||
dropIndex--;
|
||||
} else {
|
||||
if (orientation == nsITreeView.DROP_AFTER)
|
||||
dropIndex++;
|
||||
}
|
||||
|
||||
this._engineStore.moveEngine(sourceEngine, dropIndex);
|
||||
gSearchPane.showRestoreDefaults(true);
|
||||
gSearchPane.buildDefaultEngineDropDown();
|
||||
|
||||
// Redraw, and adjust selection
|
||||
this.invalidate();
|
||||
this.selection.select(dropIndex);
|
||||
},
|
||||
|
||||
selection: null,
|
||||
getRowProperties: function(index) { return ""; },
|
||||
getCellProperties: function(index, column) { return ""; },
|
||||
getColumnProperties: function(column) { return ""; },
|
||||
isContainer: function(index) { return false; },
|
||||
isContainerOpen: function(index) { return false; },
|
||||
isContainerEmpty: function(index) { return false; },
|
||||
isSeparator: function(index) { return false; },
|
||||
isSorted: function(index) { return false; },
|
||||
getParentIndex: function(index) { return -1; },
|
||||
hasNextSibling: function(parentIndex, index) { return false; },
|
||||
getLevel: function(index) { return 0; },
|
||||
getProgressMode: function(index, column) { },
|
||||
getCellValue: function(index, column) {
|
||||
if (column.id == "engineShown")
|
||||
return this._engineStore.engines[index].shown;
|
||||
return undefined;
|
||||
},
|
||||
toggleOpenState: function(index) { },
|
||||
cycleHeader: function(column) { },
|
||||
selectionChanged: function() { },
|
||||
cycleCell: function(row, column) { },
|
||||
isEditable: function(index, column) { return column.id != "engineName"; },
|
||||
isSelectable: function(index, column) { return false; },
|
||||
setCellValue: function(index, column, value) {
|
||||
if (column.id == "engineShown") {
|
||||
this._engineStore.engines[index].shown = value == "true";
|
||||
gEngineView.invalidate();
|
||||
gSearchPane.saveOneClickEnginesList();
|
||||
}
|
||||
},
|
||||
setCellText: function(index, column, value) {
|
||||
if (column.id == "engineKeyword") {
|
||||
if (!gSearchPane.editKeyword(this._engineStore.engines[index], value)) {
|
||||
setTimeout(() => {
|
||||
document.getElementById("engineList").startEditing(index, column);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
performAction: function(action) { },
|
||||
performActionOnRow: function(action, index) { },
|
||||
performActionOnCell: function(action, index, column) { }
|
||||
};
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
<script type="application/javascript" src="chrome://browser/content/preferences/search.js"/>
|
||||
|
||||
<stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
|
||||
|
||||
<!-- Default Search Engine -->
|
||||
<groupbox id="defaultEngineGroup" align="start">
|
||||
<caption label="&defaultSearchEngine.label;"/>
|
||||
|
@ -51,8 +53,34 @@
|
|||
<caption label="&oneClickSearchEngines.label;"/>
|
||||
<label>&chooseWhichOneToDisplay.label;</label>
|
||||
|
||||
<richlistbox id="oneClickProvidersList"/>
|
||||
<hbox pack="end" style="margin-bottom: 1em">
|
||||
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
|
||||
seltype="single" onselect="gSearchPane.onTreeSelect();"
|
||||
onkeypress="gSearchPane.onTreeKeyPress(event);">
|
||||
<treechildren id="engineChildren" flex="1"
|
||||
ondragstart="onDragEngineStart(event);"/>
|
||||
<treecols>
|
||||
<treecol id="engineShown" type="checkbox" style="min-width: 26px;" editable="true"/>
|
||||
<treecol id="engineName" flex="4" label="&engineNameColumn.label;"/>
|
||||
<treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"/>
|
||||
</treecols>
|
||||
</tree>
|
||||
|
||||
<hbox>
|
||||
<button id="restoreDefaultSearchEngines"
|
||||
label="&restoreDefaultSearchEngines.label;"
|
||||
accesskey="&restoreDefaultSearchEngines.accesskey;"
|
||||
oncommand="gSearchPane.onRestoreDefaults();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="removeEngineButton"
|
||||
label="&removeEngine.label;"
|
||||
accesskey="&removeEngine.accesskey;"
|
||||
disabled="true"
|
||||
oncommand="gSearchPane.remove();"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox pack="start" style="margin-bottom: 1em">
|
||||
<label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"
|
||||
onclick="if (event.button == 0) { Services.wm.getMostRecentWindow('navigator:browser').BrowserSearch.loadAddEngines(); }"/>
|
||||
</hbox>
|
||||
|
|
|
@ -6,6 +6,7 @@ const {Cc, Ci, Cu} = require("chrome");
|
|||
const {rgbToHsl} = require("devtools/css-color").colorUtils;
|
||||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -546,7 +547,7 @@ Eyedropper.prototype = {
|
|||
* Callback to be called when the color is in the clipboard.
|
||||
*/
|
||||
copyColor: function(callback) {
|
||||
Services.appShell.hiddenDOMWindow.clearTimeout(this._copyTimeout);
|
||||
clearTimeout(this._copyTimeout);
|
||||
|
||||
let color = this._colorValue.value;
|
||||
clipboardHelper.copyString(color);
|
||||
|
@ -554,7 +555,7 @@ Eyedropper.prototype = {
|
|||
this._colorValue.classList.add("highlight");
|
||||
this._colorValue.value = "✓ " + l10n.GetStringFromName("colorValue.copied");
|
||||
|
||||
this._copyTimeout = Services.appShell.hiddenDOMWindow.setTimeout(() => {
|
||||
this._copyTimeout = setTimeout(() => {
|
||||
this._colorValue.classList.remove("highlight");
|
||||
this._colorValue.value = color;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const promise = require("projecteditor/helpers/promise");
|
|||
const { on, forget } = require("projecteditor/helpers/event");
|
||||
const { FileResource } = require("projecteditor/stores/resource");
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
|
||||
const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
|
||||
const CHECK_LINKED_DIRECTORY_DELAY = 5000;
|
||||
const SHOULD_LIVE_REFRESH = true;
|
||||
|
@ -35,7 +36,6 @@ var LocalStore = Class({
|
|||
|
||||
initialize: function(path) {
|
||||
this.initStore();
|
||||
this.window = Services.appShell.hiddenDOMWindow;
|
||||
this.path = OS.Path.normalize(path);
|
||||
this.rootPath = this.path;
|
||||
this.displayName = this.path;
|
||||
|
@ -46,9 +46,8 @@ var LocalStore = Class({
|
|||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this.window) {
|
||||
this.window.clearTimeout(this._refreshTimeout);
|
||||
}
|
||||
clearTimeout(this._refreshTimeout);
|
||||
|
||||
if (this._refreshDeferred) {
|
||||
this._refreshDeferred.reject("destroy");
|
||||
}
|
||||
|
@ -58,7 +57,6 @@ var LocalStore = Class({
|
|||
|
||||
this._refreshTimeout = null;
|
||||
this._refreshDeferred = null;
|
||||
this.window = null;
|
||||
this.worker = null;
|
||||
|
||||
if (this.root) {
|
||||
|
@ -132,7 +130,7 @@ var LocalStore = Class({
|
|||
// XXX: Once Bug 958280 adds a watch function, will not need to forever loop here.
|
||||
this.refresh().then(() => {
|
||||
if (SHOULD_LIVE_REFRESH) {
|
||||
this._refreshTimeout = this.window.setTimeout(this.refreshLoop,
|
||||
this._refreshTimeout = setTimeout(this.refreshLoop,
|
||||
CHECK_LINKED_DIRECTORY_DELAY);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ function test() {
|
|||
waitForFocus(init, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,browser_css_color.js";
|
||||
content.location = "data:text/html;charset=utf-8,browser_css_color.js";
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
|
|
@ -2822,32 +2822,10 @@ TextPropertyEditor.prototype = {
|
|||
* Validate this property. Does it make sense for this value to be assigned
|
||||
* to this property name? This does not apply the property value
|
||||
*
|
||||
* @param {string} [aValue]
|
||||
* The property value used for validation.
|
||||
* Defaults to the current value for this.prop
|
||||
*
|
||||
* @return {bool} true if the property value is valid, false otherwise.
|
||||
*/
|
||||
isValid: function(aValue) {
|
||||
let name = this.prop.name;
|
||||
let value = typeof aValue == "undefined" ? this.prop.value : aValue;
|
||||
let val = parseSingleValue(value);
|
||||
|
||||
let style = this.doc.createElementNS(HTML_NS, "div").style;
|
||||
let prefs = Services.prefs;
|
||||
|
||||
// We toggle output of errors whilst the user is typing a property value.
|
||||
let prefVal = prefs.getBoolPref("layout.css.report_errors");
|
||||
prefs.setBoolPref("layout.css.report_errors", false);
|
||||
|
||||
let validValue = false;
|
||||
try {
|
||||
style.setProperty(name, val.value, val.priority);
|
||||
validValue = style.getPropertyValue(name) !== "" || val.value === "";
|
||||
} finally {
|
||||
prefs.setBoolPref("layout.css.report_errors", prefVal);
|
||||
}
|
||||
return validValue;
|
||||
isValid: function() {
|
||||
return domUtils.cssPropertyIsValid(this.prop.name, this.prop.value);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1159,6 +1159,7 @@ this.UITour = {
|
|||
let tooltipTitle = document.getElementById("UITourTooltipTitle");
|
||||
let tooltipDesc = document.getElementById("UITourTooltipDescription");
|
||||
let tooltipIcon = document.getElementById("UITourTooltipIcon");
|
||||
let tooltipIconContainer = document.getElementById("UITourTooltipIconContainer");
|
||||
let tooltipButtons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
if (tooltip.state == "showing" || tooltip.state == "open") {
|
||||
|
@ -1168,7 +1169,7 @@ this.UITour = {
|
|||
tooltipTitle.textContent = aTitle || "";
|
||||
tooltipDesc.textContent = aDescription || "";
|
||||
tooltipIcon.src = aIconURL || "";
|
||||
tooltipIcon.hidden = !aIconURL;
|
||||
tooltipIconContainer.hidden = !aIconURL;
|
||||
|
||||
while (tooltipButtons.firstChild)
|
||||
tooltipButtons.firstChild.remove();
|
||||
|
|
|
@ -1,160 +1,221 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let gTestTab;
|
||||
let gContentAPI;
|
||||
let gContentWindow;
|
||||
let loopButton;
|
||||
let loopPanel = document.getElementById("loop-notification-panel");
|
||||
|
||||
Components.utils.import("resource:///modules/UITour.jsm");
|
||||
const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
|
||||
|
||||
function test() {
|
||||
UITourTest();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
taskify(function* test_menu_show_hide() {
|
||||
ise(loopButton.open, false, "Menu should initially be closed");
|
||||
gContentAPI.showMenu("loop");
|
||||
|
||||
yield waitForConditionPromise(() => {
|
||||
return loopButton.open;
|
||||
}, "Menu should be visible after showMenu()");
|
||||
|
||||
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
|
||||
ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
|
||||
is(loopPanel.state, "open", "The panel should be open");
|
||||
ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
|
||||
|
||||
gContentAPI.hideMenu("loop");
|
||||
yield waitForConditionPromise(() => {
|
||||
return !loopButton.open;
|
||||
}, "Menu should be hidden after hideMenu()");
|
||||
|
||||
checkLoopPanelIsHidden();
|
||||
}),
|
||||
// Test the menu was cleaned up in teardown.
|
||||
taskify(function* setup_menu_cleanup() {
|
||||
gContentAPI.showMenu("loop");
|
||||
|
||||
yield waitForConditionPromise(() => {
|
||||
return loopButton.open;
|
||||
}, "Menu should be visible after showMenu()");
|
||||
|
||||
// Leave it open so it gets torn down and we can test below that teardown was succesful.
|
||||
}),
|
||||
taskify(function* test_menu_cleanup() {
|
||||
// Test that the open menu from above was torn down fully.
|
||||
checkLoopPanelIsHidden();
|
||||
}),
|
||||
function test_availableTargets(done) {
|
||||
gContentAPI.showMenu("loop");
|
||||
gContentAPI.getConfiguration("availableTargets", (data) => {
|
||||
for (let targetName of ["loop-newRoom", "loop-roomList", "loop-signInUpLink"]) {
|
||||
isnot(data.targets.indexOf(targetName), -1, targetName + " should exist");
|
||||
}
|
||||
done();
|
||||
});
|
||||
},
|
||||
function test_hideMenuHidesAnnotations(done) {
|
||||
let infoPanel = document.getElementById("UITourTooltip");
|
||||
let highlightPanel = document.getElementById("UITourHighlightContainer");
|
||||
|
||||
gContentAPI.showMenu("loop", function menuCallback() {
|
||||
gContentAPI.showHighlight("loop-roomList");
|
||||
gContentAPI.showInfo("loop-newRoom", "Make a new room", "AKA. conversation");
|
||||
UITour.getTarget(window, "loop-newRoom").then((target) => {
|
||||
waitForPopupAtAnchor(infoPanel, target.node, Task.async(function* checkPanelIsOpen() {
|
||||
isnot(loopPanel.state, "closed", "Loop panel should still be open");
|
||||
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should still be on the loop panel");
|
||||
is(highlightPanel.getAttribute("targetName"), "loop-roomList", "Check highlight @targetname");
|
||||
is(infoPanel.getAttribute("targetName"), "loop-newRoom", "Check info panel @targetname");
|
||||
|
||||
info("Close the loop menu and make sure the annotations inside disappear");
|
||||
let hiddenPromises = [promisePanelElementHidden(window, infoPanel),
|
||||
promisePanelElementHidden(window, highlightPanel)];
|
||||
gContentAPI.hideMenu("loop");
|
||||
yield Promise.all(hiddenPromises);
|
||||
isnot(infoPanel.state, "open", "Info panel should have automatically hid");
|
||||
isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
|
||||
done();
|
||||
}), "Info panel should be anchored to the new room button");
|
||||
});
|
||||
});
|
||||
},
|
||||
function test_notifyLoopChatWindowOpenedClosed(done) {
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
ok(false, "No more notifications should have arrived");
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
document.querySelector("#pinnedchats > chatbox").close();
|
||||
});
|
||||
LoopRooms.open("fakeTourRoom");
|
||||
},
|
||||
taskify(function* test_arrow_panel_position() {
|
||||
ise(loopButton.open, false, "Menu should initially be closed");
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
|
||||
yield showMenuPromise("loop");
|
||||
|
||||
let currentTarget = "loop-newRoom";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
||||
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
||||
|
||||
currentTarget = "loop-roomList";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
||||
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
||||
|
||||
currentTarget = "loop-signInUpLink";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
|
||||
is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
|
||||
}),
|
||||
];
|
||||
|
||||
// End tests
|
||||
|
||||
function checkLoopPanelIsHidden() {
|
||||
ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
|
||||
ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
|
||||
isnot(loopPanel.state, "open", "The panel shouldn't be open");
|
||||
is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("loop.enabled")) {
|
||||
loopButton = window.LoopUI.toolbarButton.node;
|
||||
// The targets to highlight only appear after getting started is launched.
|
||||
Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
|
||||
Services.prefs.setCharPref("loop.server", "http://localhost");
|
||||
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("loop.gettingStarted.seen");
|
||||
Services.prefs.clearUserPref("loop.server");
|
||||
Services.prefs.clearUserPref("services.push.serverURL");
|
||||
|
||||
// Copied from browser/components/loop/test/mochitest/head.js
|
||||
// Remove the iframe after each test. This also avoids mochitest complaining
|
||||
// about leaks on shutdown as we intentionally hold the iframe open for the
|
||||
// life of the application.
|
||||
let frameId = loopButton.getAttribute("notificationFrameId");
|
||||
let frame = document.getElementById(frameId);
|
||||
if (frame) {
|
||||
frame.remove();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ok(true, "Loop is disabled so skip the UITour Loop tests");
|
||||
tests = [];
|
||||
}
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let gTestTab;
|
||||
let gContentAPI;
|
||||
let gContentWindow;
|
||||
let loopButton;
|
||||
let loopPanel = document.getElementById("loop-notification-panel");
|
||||
|
||||
Components.utils.import("resource:///modules/UITour.jsm");
|
||||
const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
|
||||
|
||||
function test() {
|
||||
UITourTest();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
taskify(function* test_menu_show_hide() {
|
||||
ise(loopButton.open, false, "Menu should initially be closed");
|
||||
gContentAPI.showMenu("loop");
|
||||
|
||||
yield waitForConditionPromise(() => {
|
||||
return loopButton.open;
|
||||
}, "Menu should be visible after showMenu()");
|
||||
|
||||
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
|
||||
ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
|
||||
is(loopPanel.state, "open", "The panel should be open");
|
||||
ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
|
||||
|
||||
gContentAPI.hideMenu("loop");
|
||||
yield waitForConditionPromise(() => {
|
||||
return !loopButton.open;
|
||||
}, "Menu should be hidden after hideMenu()");
|
||||
|
||||
checkLoopPanelIsHidden();
|
||||
}),
|
||||
// Test the menu was cleaned up in teardown.
|
||||
taskify(function* setup_menu_cleanup() {
|
||||
gContentAPI.showMenu("loop");
|
||||
|
||||
yield waitForConditionPromise(() => {
|
||||
return loopButton.open;
|
||||
}, "Menu should be visible after showMenu()");
|
||||
|
||||
// Leave it open so it gets torn down and we can test below that teardown was succesful.
|
||||
}),
|
||||
taskify(function* test_menu_cleanup() {
|
||||
// Test that the open menu from above was torn down fully.
|
||||
checkLoopPanelIsHidden();
|
||||
}),
|
||||
function test_availableTargets(done) {
|
||||
gContentAPI.showMenu("loop");
|
||||
gContentAPI.getConfiguration("availableTargets", (data) => {
|
||||
for (let targetName of ["loop-newRoom", "loop-roomList", "loop-signInUpLink"]) {
|
||||
isnot(data.targets.indexOf(targetName), -1, targetName + " should exist");
|
||||
}
|
||||
done();
|
||||
});
|
||||
},
|
||||
function test_hideMenuHidesAnnotations(done) {
|
||||
let infoPanel = document.getElementById("UITourTooltip");
|
||||
let highlightPanel = document.getElementById("UITourHighlightContainer");
|
||||
|
||||
gContentAPI.showMenu("loop", function menuCallback() {
|
||||
gContentAPI.showHighlight("loop-roomList");
|
||||
gContentAPI.showInfo("loop-newRoom", "Make a new room", "AKA. conversation");
|
||||
UITour.getTarget(window, "loop-newRoom").then((target) => {
|
||||
waitForPopupAtAnchor(infoPanel, target.node, Task.async(function* checkPanelIsOpen() {
|
||||
isnot(loopPanel.state, "closed", "Loop panel should still be open");
|
||||
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should still be on the loop panel");
|
||||
is(highlightPanel.getAttribute("targetName"), "loop-roomList", "Check highlight @targetname");
|
||||
is(infoPanel.getAttribute("targetName"), "loop-newRoom", "Check info panel @targetname");
|
||||
|
||||
info("Close the loop menu and make sure the annotations inside disappear");
|
||||
let hiddenPromises = [promisePanelElementHidden(window, infoPanel),
|
||||
promisePanelElementHidden(window, highlightPanel)];
|
||||
gContentAPI.hideMenu("loop");
|
||||
yield Promise.all(hiddenPromises);
|
||||
isnot(infoPanel.state, "open", "Info panel should have automatically hid");
|
||||
isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
|
||||
done();
|
||||
}), "Info panel should be anchored to the new room button");
|
||||
});
|
||||
});
|
||||
},
|
||||
function test_notifyLoopChatWindowOpenedClosed(done) {
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
ok(false, "No more notifications should have arrived");
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
document.querySelector("#pinnedchats > chatbox").close();
|
||||
});
|
||||
LoopRooms.open("fakeTourRoom");
|
||||
},
|
||||
function test_notifyLoopRoomURLCopied(done) {
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
||||
|
||||
let chat = document.querySelector("#pinnedchats > chatbox");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:RoomURLCopied", "Check Loop:RoomURLCopied notification");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
||||
});
|
||||
chat.close();
|
||||
done();
|
||||
});
|
||||
chat.content.contentDocument.querySelector(".btn-copy").click();
|
||||
});
|
||||
});
|
||||
setupFakeRoom();
|
||||
LoopRooms.open("fakeTourRoom");
|
||||
},
|
||||
function test_notifyLoopRoomURLEmailed(done) {
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
||||
|
||||
let chat = document.querySelector("#pinnedchats > chatbox");
|
||||
let composeEmailCalled = false;
|
||||
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:RoomURLEmailed", "Check Loop:RoomURLEmailed notification");
|
||||
ok(composeEmailCalled, "mozLoop.composeEmail should be called");
|
||||
gContentAPI.observe((event, params) => {
|
||||
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
||||
});
|
||||
chat.close();
|
||||
done();
|
||||
});
|
||||
|
||||
let chatWin = chat.content.contentWindow;
|
||||
let oldComposeEmail = chatWin.navigator.wrappedJSObject.mozLoop.composeEmail;
|
||||
chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = function(recipient, subject, body) {
|
||||
ok(recipient, "composeEmail should be invoked with at least a recipient value");
|
||||
composeEmailCalled = true;
|
||||
chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = oldComposeEmail;
|
||||
};
|
||||
chatWin.document.querySelector(".btn-email").click();
|
||||
});
|
||||
});
|
||||
LoopRooms.open("fakeTourRoom");
|
||||
},
|
||||
taskify(function* test_arrow_panel_position() {
|
||||
ise(loopButton.open, false, "Menu should initially be closed");
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
|
||||
yield showMenuPromise("loop");
|
||||
|
||||
let currentTarget = "loop-newRoom";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
||||
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
||||
|
||||
currentTarget = "loop-roomList";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
||||
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
||||
|
||||
currentTarget = "loop-signInUpLink";
|
||||
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
|
||||
is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
|
||||
}),
|
||||
];
|
||||
|
||||
// End tests
|
||||
|
||||
function checkLoopPanelIsHidden() {
|
||||
ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
|
||||
ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
|
||||
isnot(loopPanel.state, "open", "The panel shouldn't be open");
|
||||
is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
|
||||
}
|
||||
|
||||
function setupFakeRoom() {
|
||||
let room = {};
|
||||
for (let prop of ["roomToken", "roomName", "roomOwner", "roomUrl", "participants"])
|
||||
room[prop] = "fakeTourRoom";
|
||||
LoopRooms.stubCache(new Map([
|
||||
[room.roomToken, room]
|
||||
]));
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("loop.enabled")) {
|
||||
loopButton = window.LoopUI.toolbarButton.node;
|
||||
// The targets to highlight only appear after getting started is launched.
|
||||
Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
|
||||
Services.prefs.setCharPref("loop.server", "http://localhost");
|
||||
Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("loop.gettingStarted.seen");
|
||||
Services.prefs.clearUserPref("loop.server");
|
||||
Services.prefs.clearUserPref("services.push.serverURL");
|
||||
|
||||
// Copied from browser/components/loop/test/mochitest/head.js
|
||||
// Remove the iframe after each test. This also avoids mochitest complaining
|
||||
// about leaks on shutdown as we intentionally hold the iframe open for the
|
||||
// life of the application.
|
||||
let frameId = loopButton.getAttribute("notificationFrameId");
|
||||
let frame = document.getElementById(frameId);
|
||||
if (frame) {
|
||||
frame.remove();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ok(true, "Loop is disabled so skip the UITour Loop tests");
|
||||
tests = [];
|
||||
}
|
||||
|
|
|
@ -167,8 +167,12 @@ browser.jar:
|
|||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
|
||||
skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/preferences/search.css (preferences/search.css)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
skin/classic/browser/social/services-64.png (social/services-64.png)
|
||||
skin/classic/browser/social/share-button.png (social/share-button.png)
|
||||
|
|
Двоичные данные
browser/themes/linux/loop/menuPanel.png
До Ширина: | Высота: | Размер: 2.4 KiB После Ширина: | Высота: | Размер: 2.8 KiB |
Двоичные данные
browser/themes/linux/loop/toolbar-inverted.png
До Ширина: | Высота: | Размер: 3.0 KiB После Ширина: | Высота: | Размер: 2.7 KiB |
Двоичные данные
browser/themes/linux/loop/toolbar.png
До Ширина: | Высота: | Размер: 4.7 KiB После Ширина: | Высота: | Размер: 4.3 KiB |
|
@ -0,0 +1,39 @@
|
|||
/* 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/. */
|
||||
|
||||
#defaultEngine > .menulist-label-box > .menulist-icon {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* work around a display: none in Linux's menu.css, see bug 1112310 */
|
||||
.searchengine-menuitem > .menu-iconic-left {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#engineList {
|
||||
margin: .5em 6px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-checkbox(checked) {
|
||||
list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif");
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineName) {
|
||||
-moz-margin-end: 4px;
|
||||
-moz-margin-start: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-row {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-drop-feedback {
|
||||
background-color: Highlight;
|
||||
width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
|
||||
we may have, overflow isn't visible. */
|
||||
height: 2px;
|
||||
-moz-margin-start: 0;
|
||||
}
|
|
@ -271,8 +271,16 @@ browser.jar:
|
|||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
|
||||
skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/preferences/search.css (preferences/search.css)
|
||||
skin/classic/browser/preferences/checkbox.png (preferences/checkbox.png)
|
||||
skin/classic/browser/preferences/checkbox@2x.png (preferences/checkbox@2x.png)
|
||||
skin/classic/browser/yosemite/preferences/checkbox.png (preferences/checkbox-yosemite.png)
|
||||
skin/classic/browser/yosemite/preferences/checkbox@2x.png (preferences/checkbox-yosemite@2x.png)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
skin/classic/browser/social/services-16@2x.png (social/services-16@2x.png)
|
||||
skin/classic/browser/social/services-64.png (social/services-64.png)
|
||||
|
@ -588,6 +596,8 @@ browser.jar:
|
|||
% override chrome://browser/skin/menuPanel-help@2x.png chrome://browser/skin/yosemite/menuPanel-help@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/yosemite/menuPanel-small.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/menuPanel-small@2x.png chrome://browser/skin/yosemite/menuPanel-small@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/yosemite/preferences/checkbox.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/preferences/checkbox@2x.png chrome://browser/skin/yosemite/preferences/checkbox@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/reload-stop-go.png chrome://browser/skin/yosemite/reload-stop-go.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/reload-stop-go@2x.png chrome://browser/skin/yosemite/reload-stop-go@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10
|
||||
|
|
Двоичные данные
browser/themes/osx/loop/menuPanel-yosemite.png
До Ширина: | Высота: | Размер: 12 KiB После Ширина: | Высота: | Размер: 5.7 KiB |
Двоичные данные
browser/themes/osx/loop/menuPanel-yosemite@2x.png
До Ширина: | Высота: | Размер: 26 KiB После Ширина: | Высота: | Размер: 11 KiB |
Двоичные данные
browser/themes/osx/loop/menuPanel.png
До Ширина: | Высота: | Размер: 16 KiB После Ширина: | Высота: | Размер: 9.5 KiB |
Двоичные данные
browser/themes/osx/loop/menuPanel@2x.png
До Ширина: | Высота: | Размер: 37 KiB После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar-inverted.png
До Ширина: | Высота: | Размер: 4.3 KiB После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar-inverted@2x.png
До Ширина: | Высота: | Размер: 11 KiB После Ширина: | Высота: | Размер: 11 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar-yosemite.png
До Ширина: | Высота: | Размер: 2.9 KiB После Ширина: | Высота: | Размер: 2.5 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar-yosemite@2x.png
До Ширина: | Высота: | Размер: 6.2 KiB После Ширина: | Высота: | Размер: 5.9 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar.png
До Ширина: | Высота: | Размер: 4.5 KiB После Ширина: | Высота: | Размер: 4.2 KiB |
Двоичные данные
browser/themes/osx/loop/toolbar@2x.png
До Ширина: | Высота: | Размер: 13 KiB После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 2.4 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 3.6 KiB |
|
@ -0,0 +1,54 @@
|
|||
/* 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/. */
|
||||
|
||||
#defaultEngine > .menulist-label-box > .menulist-icon {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList {
|
||||
margin: .5em 6px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineShown) {
|
||||
list-style-image: url("chrome://browser/skin/preferences/checkbox.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
-moz-margin-start: 4px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineShown, checked) {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#engineList treechildren::-moz-tree-image(engineShown) {
|
||||
list-style-image: url("chrome://browser/skin/preferences/checkbox@2x.png");
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineShown, checked) {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineName) {
|
||||
-moz-margin-end: 4px;
|
||||
-moz-margin-start: 1px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-row {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-drop-feedback {
|
||||
background-color: Highlight;
|
||||
width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
|
||||
we may have, overflow isn't visible. */
|
||||
height: 2px;
|
||||
-moz-margin-start: 0;
|
||||
}
|
После Ширина: | Высота: | Размер: 288 B |
После Ширина: | Высота: | Размер: 471 B |
|
@ -0,0 +1,54 @@
|
|||
/* 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/. */
|
||||
|
||||
#defaultEngine > .menulist-label-box > .menulist-icon {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* work around a display: none in Linux's menu.css, see bug 1112310 */
|
||||
.searchengine-menuitem > .menu-iconic-left {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#engineList {
|
||||
margin: .5em 6px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineShown, checked) {
|
||||
/* Unfortunately check.svg can't be used in XUL trees. */
|
||||
list-style-image: url("check.png");
|
||||
-moz-margin-start: 5px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#engineList treechildren::-moz-tree-image(engineShown, checked) {
|
||||
list-style-image: url("check@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineName) {
|
||||
-moz-margin-end: 10px;
|
||||
-moz-margin-start: 1px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-row {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-cell-text {
|
||||
/* Override to avoid text in the selected row being white on light gray. */
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-drop-feedback {
|
||||
background-color: Highlight;
|
||||
width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
|
||||
we may have, overflow isn't visible. */
|
||||
height: 2px;
|
||||
-moz-margin-start: 0;
|
||||
}
|
|
@ -118,9 +118,9 @@ browser.jar:
|
|||
skin/classic/browser/webRTC-microphone-white-16.png (../shared/webrtc/microphone-white-16.png)
|
||||
skin/classic/browser/webRTC-screen-white-16.png (../shared/webrtc/screen-white-16.png)
|
||||
skin/classic/browser/loop/menuPanel.png (loop/menuPanel.png)
|
||||
skin/classic/browser/loop/toolbar.png (loop/toolbar-XPVista7.png)
|
||||
skin/classic/browser/loop/toolbar-lunaSilver.png (loop/toolbar-lunaSilver.png)
|
||||
skin/classic/browser/loop/toolbar.png (loop/toolbar-XP.png)
|
||||
skin/classic/browser/loop/toolbar-inverted.png (loop/toolbar-inverted.png)
|
||||
skin/classic/browser/loop/toolbar-lunaSilver.png (loop/toolbar-lunaSilver.png)
|
||||
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
|
||||
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
|
||||
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)
|
||||
|
@ -195,8 +195,14 @@ browser.jar:
|
|||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
|
||||
skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/browser/preferences/search.css (preferences/search.css)
|
||||
skin/classic/browser/preferences/checkbox.png (preferences/checkbox-xp.png)
|
||||
skin/classic/browser/preferences/checkbox-classic.png (preferences/checkbox-classic.png)
|
||||
skin/classic/browser/social/services-16.png (social/services-16.png)
|
||||
skin/classic/browser/social/services-64.png (social/services-64.png)
|
||||
skin/classic/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
|
||||
|
@ -564,9 +570,10 @@ browser.jar:
|
|||
skin/classic/aero/browser/webRTC-camera-white-16.png (../shared/webrtc/camera-white-16.png)
|
||||
skin/classic/aero/browser/webRTC-microphone-white-16.png (../shared/webrtc/microphone-white-16.png)
|
||||
skin/classic/aero/browser/webRTC-screen-white-16.png (../shared/webrtc/screen-white-16.png)
|
||||
skin/classic/aero/browser/loop/menuPanel.png (loop/menuPanel-aero.png)
|
||||
skin/classic/aero/browser/loop/menuPanel.png (loop/menuPanel.png)
|
||||
skin/classic/aero/browser/loop/menuPanel-aero.png (loop/menuPanel-aero.png)
|
||||
skin/classic/aero/browser/loop/toolbar.png (loop/toolbar.png)
|
||||
skin/classic/aero/browser/loop/toolbar-XPVista7.png (loop/toolbar-XPVista7.png)
|
||||
skin/classic/aero/browser/loop/toolbar-aero.png (loop/toolbar-aero.png)
|
||||
skin/classic/aero/browser/loop/toolbar-inverted.png (loop/toolbar-inverted.png)
|
||||
skin/classic/aero/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
|
||||
skin/classic/aero/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)
|
||||
|
@ -643,8 +650,15 @@ browser.jar:
|
|||
skin/classic/aero/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/aero/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/aero/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/aero/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/aero/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
|
||||
skin/classic/aero/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
|
||||
skin/classic/aero/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
skin/classic/aero/browser/preferences/search.css (preferences/search.css)
|
||||
skin/classic/aero/browser/preferences/checkbox.png (preferences/checkbox-8.png)
|
||||
skin/classic/aero/browser/preferences/checkbox-aero.png (preferences/checkbox-aero.png)
|
||||
skin/classic/aero/browser/preferences/checkbox-classic.png (preferences/checkbox-classic.png)
|
||||
skin/classic/aero/browser/social/services-16.png (social/services-16.png)
|
||||
skin/classic/aero/browser/social/services-64.png (social/services-64.png)
|
||||
skin/classic/aero/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
|
||||
|
@ -902,6 +916,9 @@ browser.jar:
|
|||
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/preferences/checkbox-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/preferences/checkbox-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/theme-switcher-icon.png chrome://browser/skin/theme-switcher-icon-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/theme-switcher-icon.png chrome://browser/skin/theme-switcher-icon-aero.png os=WINNT osversion=6.1
|
||||
|
||||
|
@ -917,5 +934,8 @@ browser.jar:
|
|||
% override chrome://browser/skin/tabbrowser/tab-arrow-left.png chrome://browser/skin/tabbrowser/tab-arrow-left-XPVista7.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/tabbrowser/tab-arrow-left.png chrome://browser/skin/tabbrowser/tab-arrow-left-XPVista7.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/loop/toolbar-XPVista7.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/loop/toolbar-XPVista7.png os=WINNT osversion=6.1
|
||||
% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/loop/toolbar-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/loop/toolbar-aero.png os=WINNT osversion=6.1
|
||||
|
||||
% override chrome://browser/skin/loop/menuPanel.png chrome://browser/skin/loop/menuPanel-aero.png os=WINNT osversion=6
|
||||
% override chrome://browser/skin/loop/menuPanel.png chrome://browser/skin/loop/menuPanel-aero.png os=WINNT osversion=6.1
|
||||
|
|
Двоичные данные
browser/themes/windows/loop/menuPanel-aero.png
До Ширина: | Высота: | Размер: 16 KiB После Ширина: | Высота: | Размер: 10 KiB |
Двоичные данные
browser/themes/windows/loop/menuPanel.png
До Ширина: | Высота: | Размер: 8.7 KiB После Ширина: | Высота: | Размер: 2.8 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
Двоичные данные
browser/themes/windows/loop/toolbar-XPVista7.png
До Ширина: | Высота: | Размер: 4.6 KiB |
После Ширина: | Высота: | Размер: 4.3 KiB |
Двоичные данные
browser/themes/windows/loop/toolbar-inverted.png
До Ширина: | Высота: | Размер: 3.0 KiB После Ширина: | Высота: | Размер: 2.7 KiB |
Двоичные данные
browser/themes/windows/loop/toolbar-lunaSilver.png
До Ширина: | Высота: | Размер: 4.7 KiB После Ширина: | Высота: | Размер: 4.3 KiB |
Двоичные данные
browser/themes/windows/loop/toolbar.png
До Ширина: | Высота: | Размер: 1.2 KiB После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 705 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 284 B |
После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -0,0 +1,59 @@
|
|||
/* 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/. */
|
||||
|
||||
#defaultEngine > .menulist-label-box > .menulist-icon {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList {
|
||||
margin: .5em 6px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-checkbox {
|
||||
list-style-image: url("chrome://browser/skin/preferences/checkbox.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-checkbox(checked) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
@media (-moz-windows-classic) {
|
||||
#engineList treechildren::-moz-tree-checkbox {
|
||||
list-style-image: url("chrome://browser/skin/preferences/checkbox-classic.png");
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-checkbox(checked) {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
}
|
||||
|
||||
@media not all and (-moz-windows-classic) {
|
||||
#engineList treechildren::-moz-tree-checkbox(hover) {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-checkbox(checked, hover) {
|
||||
-moz-image-region: rect(0, 80px, 16px, 64px);
|
||||
}
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-image(engineName) {
|
||||
-moz-margin-end: 4px;
|
||||
-moz-margin-start: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-row {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
#engineList treechildren::-moz-tree-drop-feedback {
|
||||
background-color: Highlight;
|
||||
width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
|
||||
we may have, overflow isn't visible. */
|
||||
height: 2px;
|
||||
-moz-margin-start: 0;
|
||||
}
|
|
@ -3411,6 +3411,8 @@ TabChild::RecvRequestNotifyAfterRemotePaint()
|
|||
bool
|
||||
TabChild::RecvUIResolutionChanged()
|
||||
{
|
||||
mDPI = 0;
|
||||
mDefaultScale = 0;
|
||||
static_cast<PuppetWidget*>(mWidget.get())->ClearBackingScaleCache();
|
||||
nsCOMPtr<nsIDocument> document(GetDocument());
|
||||
nsCOMPtr<nsIPresShell> presShell = document->GetShell();
|
||||
|
|
|
@ -219,7 +219,6 @@ MediaEngineTabVideoSource::Draw() {
|
|||
IntSize size(mBufW, mBufH);
|
||||
|
||||
nsresult rv;
|
||||
float scale = 1.0;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mWindow);
|
||||
|
||||
|
@ -240,25 +239,14 @@ MediaEngineTabVideoSource::Draw() {
|
|||
return;
|
||||
}
|
||||
|
||||
float left, top, width, height;
|
||||
rect->GetLeft(&left);
|
||||
rect->GetTop(&top);
|
||||
float width, height;
|
||||
rect->GetWidth(&width);
|
||||
rect->GetHeight(&height);
|
||||
|
||||
if (mScrollWithPage) {
|
||||
nsPoint point;
|
||||
utils->GetScrollXY(false, &point.x, &point.y);
|
||||
left += point.x;
|
||||
top += point.y;
|
||||
}
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t srcX = left;
|
||||
int32_t srcY = top;
|
||||
int32_t srcW;
|
||||
int32_t srcH;
|
||||
|
||||
|
@ -279,14 +267,15 @@ MediaEngineTabVideoSource::Draw() {
|
|||
if (!presContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
nscolor bgColor = NS_RGB(255, 255, 255);
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
||||
nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
|
||||
nsPresContext::CSSPixelsToAppUnits(srcY / scale),
|
||||
nsPresContext::CSSPixelsToAppUnits(srcW / scale),
|
||||
nsPresContext::CSSPixelsToAppUnits(srcH / scale));
|
||||
uint32_t renderDocFlags = nsIPresShell::RENDER_DOCUMENT_RELATIVE;
|
||||
if (!mScrollWithPage) {
|
||||
renderDocFlags |= nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
|
||||
}
|
||||
nsRect r(0, 0, nsPresContext::CSSPixelsToAppUnits((float)srcW),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)srcH));
|
||||
|
||||
gfxImageFormat format = gfxImageFormat::RGB24;
|
||||
uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width);
|
||||
|
@ -302,9 +291,9 @@ MediaEngineTabVideoSource::Draw() {
|
|||
return;
|
||||
}
|
||||
nsRefPtr<gfxContext> context = new gfxContext(dt);
|
||||
context->SetMatrix(
|
||||
context->CurrentMatrix().Scale(scale * size.width / srcW,
|
||||
scale * size.height / srcH));
|
||||
context->SetMatrix(context->CurrentMatrix().Scale((float)size.width/srcW,
|
||||
(float)size.height/srcH));
|
||||
|
||||
rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
|
|
@ -280,13 +280,13 @@ pref("browser.search.noCurrentEngine", true);
|
|||
pref("browser.search.official", true);
|
||||
#endif
|
||||
|
||||
// Control media casting feature
|
||||
// Control media casting & mirroring features
|
||||
pref("browser.casting.enabled", true);
|
||||
pref("browser.mirroring.enabled", true);
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("browser.mirroring.enabled", false);
|
||||
// Roku does not yet support mirroring in production
|
||||
pref("browser.mirroring.enabled.roku", false);
|
||||
#else
|
||||
pref("browser.mirroring.enabled", true);
|
||||
pref("browser.mirroring.enabled.roku", true);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -422,19 +422,38 @@ extern int
|
|||
__real_getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
int android_sdk_version;
|
||||
|
||||
#pragma GCC visibility pop
|
||||
|
||||
int android_sdk_version = -1;
|
||||
static int get_android_sdk_version()
|
||||
{
|
||||
char version_str[PROP_VALUE_MAX];
|
||||
memset(version_str, 0, PROP_VALUE_MAX);
|
||||
int len = __system_property_get("ro.build.version.sdk", version_str);
|
||||
if (len < 1) {
|
||||
#ifdef MOZ_GETADDRINFO_LOG_VERBOSE
|
||||
__android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
|
||||
"Failed to get Android SDK version\n");
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
return (int)strtol(version_str, NULL, 10);
|
||||
}
|
||||
|
||||
static int honeycomb_or_later()
|
||||
{
|
||||
static int android_sdk_version = 0;
|
||||
if (android_sdk_version == 0) {
|
||||
android_sdk_version = get_android_sdk_version();
|
||||
}
|
||||
|
||||
#ifdef MOZ_GETADDRINFO_LOG_VERBOSE
|
||||
__android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
|
||||
"I am%s Honeycomb\n",
|
||||
(android_sdk_version >= 11) ? "" : " not");
|
||||
#endif
|
||||
|
||||
return android_sdk_version >= 11;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
|||
const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
|
||||
|
||||
const REGEX_JUST_QUOTES = /^""$/;
|
||||
const REGEX_RGB_3_TUPLE = /^rgb\(([\d.]+),\s*([\d.]+),\s*([\d.]+)\)$/i;
|
||||
const REGEX_RGBA_4_TUPLE = /^rgba\(([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+|1|0)\)$/i;
|
||||
const REGEX_HSL_3_TUPLE = /^\bhsl\(([\d.]+),\s*([\d.]+%),\s*([\d.]+%)\)$/i;
|
||||
|
||||
/**
|
||||
|
@ -106,7 +104,7 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get valid() {
|
||||
return this._validateColor(this.authored);
|
||||
return DOMUtils.isValidCSSColor(this.authored);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -126,11 +124,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get name() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -147,11 +143,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get hex() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (this.hasAlpha) {
|
||||
return this.rgba;
|
||||
|
@ -167,11 +161,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get longHex() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (this.hasAlpha) {
|
||||
return this.rgba;
|
||||
|
@ -182,11 +174,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get rgb() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (!this.hasAlpha) {
|
||||
if (this.authored.startsWith("rgb(")) {
|
||||
|
@ -200,11 +190,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get rgba() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (this.authored.startsWith("rgba(")) {
|
||||
// The color is valid and begins with rgba(. Return the authored value.
|
||||
|
@ -218,11 +206,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get hsl() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (this.authored.startsWith("hsl(")) {
|
||||
// The color is valid and begins with hsl(. Return the authored value.
|
||||
|
@ -235,11 +221,9 @@ CssColor.prototype = {
|
|||
},
|
||||
|
||||
get hsla() {
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
|
||||
if (invalidOrSpecialValue !== false) {
|
||||
return invalidOrSpecialValue;
|
||||
}
|
||||
if (this.authored.startsWith("hsla(")) {
|
||||
// The color is valid and begins with hsla(. Return the authored value.
|
||||
|
@ -252,6 +236,27 @@ CssColor.prototype = {
|
|||
return this._hslNoAlpha().replace("hsl", "hsla").replace(")", ", 1)");
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the current color value is in the special list e.g.
|
||||
* transparent or invalid.
|
||||
*
|
||||
* @return {String|Boolean}
|
||||
* - If the current color is a special value e.g. "transparent" then
|
||||
* return the color.
|
||||
* - If the color is invalid return an empty string.
|
||||
* - If the color is a regular color e.g. #F06 so we return false
|
||||
* to indicate that the color is neither invalid or special.
|
||||
*/
|
||||
_getInvalidOrSpecialValue: function() {
|
||||
if (this.specialValue) {
|
||||
return this.specialValue;
|
||||
}
|
||||
if (!this.valid) {
|
||||
return "";
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Change color
|
||||
*
|
||||
|
@ -298,27 +303,11 @@ CssColor.prototype = {
|
|||
* appropriate.
|
||||
*/
|
||||
_getRGBATuple: function() {
|
||||
let win = Services.appShell.hiddenDOMWindow;
|
||||
let doc = win.document;
|
||||
let span = doc.createElement("span");
|
||||
span.style.color = this.authored;
|
||||
let computed = win.getComputedStyle(span).color;
|
||||
let tuple = DOMUtils.colorToRGBA(this.authored);
|
||||
|
||||
if (computed === "transparent") {
|
||||
return {r: 0, g: 0, b: 0, a: 0};
|
||||
}
|
||||
tuple.a = parseFloat(tuple.a.toFixed(1));
|
||||
|
||||
let rgba = computed.match(REGEX_RGBA_4_TUPLE);
|
||||
|
||||
if (rgba) {
|
||||
let [, r, g, b, a] = rgba;
|
||||
return {r: r, g: g, b: b, a: a};
|
||||
} else {
|
||||
let rgb = computed.match(REGEX_RGB_3_TUPLE);
|
||||
let [, r, g, b] = rgb;
|
||||
|
||||
return {r: r, g: g, b: b, a: 1};
|
||||
}
|
||||
return tuple;
|
||||
},
|
||||
|
||||
_hslNoAlpha: function() {
|
||||
|
@ -342,33 +331,6 @@ CssColor.prototype = {
|
|||
valueOf: function() {
|
||||
return this.rgba;
|
||||
},
|
||||
|
||||
_validateColor: function(color) {
|
||||
if (typeof color !== "string" || color === "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let win = Services.appShell.hiddenDOMWindow;
|
||||
let doc = win.document;
|
||||
|
||||
// Create a black span in a hidden window.
|
||||
let span = doc.createElement("span");
|
||||
span.style.color = "rgb(0, 0, 0)";
|
||||
|
||||
// Attempt to set the color. If the color is no longer black we know that
|
||||
// color is valid.
|
||||
span.style.color = color;
|
||||
if (span.style.color !== "rgb(0, 0, 0)") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the color is black then the above check will have failed. We change
|
||||
// the span to white and attempt to reapply the color. If the span is not
|
||||
// white then we know that the color is valid otherwise we return invalid.
|
||||
span.style.color = "rgb(255, 255, 255)";
|
||||
span.style.color = color;
|
||||
return span.style.color !== "rgb(255, 255, 255)";
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -337,15 +337,7 @@ OutputParser.prototype = {
|
|||
* CSS Property value to check
|
||||
*/
|
||||
_cssPropertySupportsValue: function(name, value) {
|
||||
let win = Services.appShell.hiddenDOMWindow;
|
||||
let doc = win.document;
|
||||
|
||||
value = value.replace("!important", "");
|
||||
|
||||
let div = doc.createElement("div");
|
||||
div.style.setProperty(name, value);
|
||||
|
||||
return !!div.style.getPropertyValue(name);
|
||||
return DOMUtils.cssPropertyIsValid(name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -285,23 +285,24 @@ function RemoteMirror(url, win, viewport, mirrorStartedCallback, contentWindow)
|
|||
this._iceCandidates = [];
|
||||
this.mirrorStarted = mirrorStartedCallback;
|
||||
|
||||
// This code insures the generated tab mirror is not wider than 800 nor taller than 600
|
||||
// This code insures the generated tab mirror is not wider than 1280 nor taller than 720
|
||||
// Better dimensions should be chosen after the Roku Channel is working.
|
||||
let windowId = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||
let cWidth = Math.max(viewport.cssWidth, viewport.width);
|
||||
let cHeight = Math.max(viewport.cssHeight, viewport.height);
|
||||
|
||||
const MAX_WIDTH = 800;
|
||||
const MAX_HEIGHT = 600;
|
||||
const MAX_WIDTH = 1280;
|
||||
const MAX_HEIGHT = 720;
|
||||
|
||||
let tWidth = 0;
|
||||
let tHeight = 0;
|
||||
|
||||
// division and multiplication by 4 to ensure dimensions are multiples of 4
|
||||
if ((cWidth / MAX_WIDTH) > (cHeight / MAX_HEIGHT)) {
|
||||
tHeight = Math.ceil((MAX_WIDTH / cWidth) * cHeight);
|
||||
tHeight = Math.ceil((MAX_WIDTH / (4* cWidth)) * cHeight) * 4;
|
||||
tWidth = MAX_WIDTH;
|
||||
} else {
|
||||
tWidth = Math.ceil((MAX_HEIGHT / cHeight) * cWidth);
|
||||
tWidth = Math.ceil((MAX_HEIGHT / (4 * cHeight)) * cWidth) * 4;
|
||||
tHeight = MAX_HEIGHT;
|
||||
}
|
||||
|
||||
|
|