зеркало из https://github.com/mozilla/gecko-dev.git
Bug 653141 - Allow language choice on first-run. r=mfinkle
This commit is contained in:
Родитель
179177d1fa
Коммит
1d363880de
|
@ -334,6 +334,7 @@ class Automation(object):
|
|||
part = """\
|
||||
user_pref("browser.console.showInPanel", true);
|
||||
user_pref("browser.dom.window.dump.enabled", true);
|
||||
user_pref("browser.firstrun.show.localepicker", false);
|
||||
user_pref("dom.allow_scripts_to_close_windows", true);
|
||||
user_pref("dom.disable_open_during_load", false);
|
||||
user_pref("dom.max_script_run_time", 0); // no slow script dialogs
|
||||
|
|
|
@ -215,6 +215,9 @@ pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LO
|
|||
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
|
||||
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
|
||||
|
||||
/* preference for the locale picker */
|
||||
pref("extensions.getLocales.get.url", "");
|
||||
|
||||
/* blocklist preferences */
|
||||
pref("extensions.blocklist.enabled", true);
|
||||
pref("extensions.blocklist.interval", 86400);
|
||||
|
@ -643,6 +646,9 @@ pref("urlclassifier.updatecachemax", 4194304);
|
|||
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
#endif
|
||||
|
||||
// prevent focus to show/hide the virtual keyboard if the action is not
|
||||
// True if this is the first time we are showing about:firstrun
|
||||
pref("browser.firstrun.show.uidiscovery", true);
|
||||
pref("browser.firstrun.show.localepicker", true);
|
||||
|
||||
// initiated by a user
|
||||
pref("content.ime.strict_policy", true);
|
||||
|
|
|
@ -266,7 +266,7 @@ var Browser = {
|
|||
ViewableAreaObserver.update();
|
||||
|
||||
// Restore the previous scroll position
|
||||
let restorePosition = Browser.controlsPosition;
|
||||
let restorePosition = Browser.controlsPosition || { hideSidebars: true };
|
||||
if (restorePosition.hideSidebars) {
|
||||
restorePosition.hideSidebars = false;
|
||||
Browser.hideSidebars();
|
||||
|
@ -378,6 +378,11 @@ var Browser = {
|
|||
let event = document.createEvent("Events");
|
||||
event.initEvent("UIReady", true, false);
|
||||
window.dispatchEvent(event);
|
||||
|
||||
// if we have an opener this was not the first window opened and will not
|
||||
// receive an initial resize event. instead we fire the resize handler manually
|
||||
if (window.opener)
|
||||
resizeHandler({ target: window });
|
||||
},
|
||||
|
||||
_alertShown: function _alertShown() {
|
||||
|
|
|
@ -536,7 +536,7 @@
|
|||
<vbox id="syncsetup-simple" class="syncsetup-page" flex="1">
|
||||
<scrollbox id="sync-message" class="prompt-message" orient="vertical" flex="1">
|
||||
<description class="syncsetup-desc syncsetup-center" flex="1">&sync.setup.jpake;</description>
|
||||
<description class="syncsetup-center syncsetup-link" flex="1" onclick="WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
|
||||
<description class="syncsetup-center link" flex="1" onclick="WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
|
||||
<separator/>
|
||||
<vbox align="center" flex="1">
|
||||
<description id="syncsetup-code1" class="syncsetup-code">....</description>
|
||||
|
@ -544,7 +544,7 @@
|
|||
<description id="syncsetup-code3" class="syncsetup-code">....</description>
|
||||
</vbox>
|
||||
<separator/>
|
||||
<description class="syncsetup-center syncsetup-link" flex="1" onclick="WeaveGlue.openManual();">&sync.fallback;</description>
|
||||
<description class="syncsetup-center link" flex="1" onclick="WeaveGlue.openManual();">&sync.fallback;</description>
|
||||
<separator flex="1"/>
|
||||
</scrollbox>
|
||||
<hbox class="prompt-buttons" pack="center">
|
||||
|
|
|
@ -117,8 +117,14 @@
|
|||
}
|
||||
|
||||
function init() {
|
||||
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).QueryInterface(Ci.nsIPrefBranch2);
|
||||
if (prefs.getBoolPref("browser.firstrun.show.uidiscovery")) {
|
||||
startDiscovery();
|
||||
prefs.setBoolPref("browser.firstrun.show.uidiscovery", false);
|
||||
} else {
|
||||
endDiscovery();
|
||||
}
|
||||
setupLinks();
|
||||
startDiscovery();
|
||||
}
|
||||
|
||||
function startDiscovery() {
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Geometry.jsm");
|
||||
|
||||
// Maximum delay in ms between the two taps of a double-tap
|
||||
const kDoubleClickInterval = 400;
|
||||
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
Cu.import("resource:///modules/LocaleRepository.jsm");
|
||||
|
||||
let stringPrefs = [
|
||||
{ selector: "#continue-in-button", pref: "continueIn", data: ["CURRENT_LANGUAGE"] },
|
||||
{ selector: "#change-language", pref: "choose", data: null },
|
||||
{ selector: "#picker-title", pref: "chooseLanguage", data: null },
|
||||
{ selector: "#continue-button", pref: "continue", data: null },
|
||||
{ selector: "#cancel-button", pref: "cancel", data: null },
|
||||
{ selector: "#intalling-message", pref: "installing", data: ["CURRENT_LANGUAGE"] },
|
||||
{ selector: "#cancel-install-button", pref: "cancel", data: null },
|
||||
{ selector: "#installing-error", pref: "installerror", data: null },
|
||||
{ selector: "#install-continue", pref: "continue", data: null }
|
||||
];
|
||||
|
||||
let LocaleUI = {
|
||||
_strings: null,
|
||||
|
||||
get strings() {
|
||||
if (!this._strings)
|
||||
this._strings = Services.strings.createBundle("chrome://browser/locale/localepicker.properties");
|
||||
return this._strings;
|
||||
},
|
||||
|
||||
set strings(aVal) {
|
||||
this._strings = aVal;
|
||||
},
|
||||
|
||||
get _mainPage() {
|
||||
delete this._mainPage;
|
||||
return this._mainPage = document.getElementById("main-page");
|
||||
},
|
||||
|
||||
get _pickerPage() {
|
||||
delete this._pickerPage;
|
||||
return this._pickerPage = document.getElementById("picker-page");
|
||||
},
|
||||
|
||||
get _installerPage() {
|
||||
delete this._installerPage;
|
||||
return this._installerPage = document.getElementById("installer-page");
|
||||
},
|
||||
|
||||
get _deck() {
|
||||
delete this._deck;
|
||||
return this._deck = document.getElementById("language-deck");
|
||||
},
|
||||
|
||||
_currentInstall: null, // used to cancel an install
|
||||
|
||||
get selectedPanel() {
|
||||
return this._deck.selectedPanel;
|
||||
},
|
||||
|
||||
set selectedPanel(aPanel) {
|
||||
this._deck.selectedPanel = aPanel;
|
||||
},
|
||||
|
||||
get list() {
|
||||
delete this.list;
|
||||
return this.list = document.getElementById("language-list");
|
||||
},
|
||||
|
||||
_createItem: function(aId, aText, aLocale) {
|
||||
let item = document.createElement("richlistitem");
|
||||
item.setAttribute("id", aId);
|
||||
|
||||
let description = document.createElement("description");
|
||||
description.appendChild(document.createTextNode(aText));
|
||||
description.setAttribute('flex', 1);
|
||||
item.appendChild(description);
|
||||
item.setAttribute("locale", getTargetLanguage(aLocale.addon));
|
||||
|
||||
if (aLocale) {
|
||||
item.locale = aLocale.addon;
|
||||
let checkbox = document.createElement("image");
|
||||
checkbox.classList.add("checkbox");
|
||||
item.appendChild(checkbox);
|
||||
} else {
|
||||
item.classList.add("message");
|
||||
}
|
||||
return item;
|
||||
},
|
||||
|
||||
addLocales: function(aLocales) {
|
||||
let fragment = document.createDocumentFragment();
|
||||
let selectedItem = null;
|
||||
let bestMatch = NO_MATCH;
|
||||
|
||||
for each (let locale in aLocales) {
|
||||
let targetLang = getTargetLanguage(locale.addon);
|
||||
if (document.querySelector('[locale="' + targetLang + '"]'))
|
||||
continue;
|
||||
|
||||
let item = this._createItem(targetLang, locale.addon.name, locale);
|
||||
let match = localesMatch(targetLang, this.language);
|
||||
if (match > bestMatch) {
|
||||
bestMatch = match;
|
||||
selectedItem = item;
|
||||
}
|
||||
fragment.appendChild(item);
|
||||
}
|
||||
this.list.appendChild(fragment);
|
||||
if (selectedItem && !this.list.selectedItem);
|
||||
this.list.selectedItem = selectedItem;
|
||||
},
|
||||
|
||||
loadLocales: function() {
|
||||
while (this.list.firstChild)
|
||||
this.list.removeChild(this.list.firstChild);
|
||||
this.addLocales(this.availableLocales);
|
||||
LocaleRepository.getLocales(this.addLocales.bind(this));
|
||||
},
|
||||
|
||||
showPicker: function() {
|
||||
LocaleUI.selectedPanel = LocaleUI._pickerPage;
|
||||
LocaleUI.loadLocales();
|
||||
},
|
||||
|
||||
closePicker: function() {
|
||||
if (this._currentInstall) {
|
||||
Services.prefs.setBoolPref("intl.locale.matchOS", false);
|
||||
Services.prefs.setCharPref("general.useragent.locale", getTargetLanguage(this._currentInstall));
|
||||
}
|
||||
this.selectedPanel = this._mainPage;
|
||||
},
|
||||
|
||||
_language: "",
|
||||
|
||||
set language(aVal) {
|
||||
if (aVal == this._language)
|
||||
return;
|
||||
|
||||
Services.prefs.setBoolPref("intl.locale.matchOS", false);
|
||||
Services.prefs.setCharPref("general.useragent.locale", aVal);
|
||||
this._language = aVal;
|
||||
|
||||
this.strings = null;
|
||||
this.updateStrings();
|
||||
},
|
||||
|
||||
get language() {
|
||||
return this._language;
|
||||
},
|
||||
|
||||
set installStatus(aVal) {
|
||||
this._installerPage.selectedPanel = document.getElementById("installer-page-" + aVal);
|
||||
},
|
||||
|
||||
clearInstallError: function() {
|
||||
this.installStatus = "installing";
|
||||
this.selectedPanel = this._pickerPage;
|
||||
},
|
||||
|
||||
selectLanguage: function(aEvent) {
|
||||
let locale = this.list.selectedItem.locale;
|
||||
if (locale.install)
|
||||
this.updateStrings(locale);
|
||||
else {
|
||||
this.language = getTargetLanguage(locale);
|
||||
if (this._currentInstall)
|
||||
this._currentInstall = null;
|
||||
}
|
||||
},
|
||||
|
||||
installAddon: function() {
|
||||
let locale = LocaleUI.list.selectedItem.locale;
|
||||
LocaleUI._currentInstall = locale;
|
||||
|
||||
if (locale.install) {
|
||||
LocaleUI.selectedPanel = LocaleUI._installerPage;
|
||||
locale.install.addListener(installListener);
|
||||
locale.install.install();
|
||||
} else {
|
||||
this.closePicker();
|
||||
}
|
||||
},
|
||||
|
||||
cancelPicker: function() {
|
||||
if (this._currentInstall)
|
||||
this._currentInstall = null;
|
||||
// restore the last known "good" locale
|
||||
this.language = this.defaultLanguage;
|
||||
this.updateStrings();
|
||||
this.closePicker();
|
||||
},
|
||||
|
||||
closeWindow : function() {
|
||||
// Trying to close this window and open a new one results in a corrupt UI.
|
||||
if (false && LocaleUI._currentInstall) {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
|
||||
if (cancelQuit.data == false) {
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eForceQuit);
|
||||
Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", false);
|
||||
}
|
||||
} else {
|
||||
let argString = null;
|
||||
if (window.arguments) {
|
||||
argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
argString.data = window.arguments.join(",");
|
||||
}
|
||||
let win = Services.ww.openWindow(window, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", argString);
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
|
||||
cancelInstall: function () {
|
||||
if (LocaleUI._currentInstall) {
|
||||
let addonInstall = LocaleUI._currentInstall.install;
|
||||
try { addonInstall.cancel(); }
|
||||
catch(ex) { }
|
||||
LocaleUI._currentInstall = null;
|
||||
|
||||
this.language = this.defaultLanguage;
|
||||
}
|
||||
},
|
||||
|
||||
updateStrings: function (aAddon) {
|
||||
stringPrefs.forEach(function(aPref) {
|
||||
if (!aPref.element)
|
||||
aPref.element = document.querySelector(aPref.selector);
|
||||
|
||||
let string = "";
|
||||
try {
|
||||
string = getString(aPref.pref, aPref.data, aAddon);
|
||||
} catch(ex) { }
|
||||
aPref.element.textContent = string;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the target language for a locale addon
|
||||
// For now this returns the targetLocale, although if and addon doesn't
|
||||
// specify a targetLocale we could attempt to guess the locale from the addon's name
|
||||
function getTargetLanguage(aAddon) {
|
||||
return aAddon.targetLocale;
|
||||
}
|
||||
|
||||
// Gets a particular string for the passed in locale
|
||||
// Parameters: aStringName - The name of the string property to get
|
||||
// aDataset - an array of properties to use in a formatted string
|
||||
// aAddon - An addon to attempt to get dataset properties from
|
||||
function getString(aStringName, aDataSet, aAddon) {
|
||||
if (aDataSet) {
|
||||
let databundle = aDataSet.map(function(aData) {
|
||||
switch (aData) {
|
||||
case "CURRENT_LANGUAGE" :
|
||||
if (aAddon)
|
||||
return aAddon.name;
|
||||
try { return LocaleUI.strings.GetStringFromName("name"); }
|
||||
catch(ex) { return null; }
|
||||
break;
|
||||
default :
|
||||
}
|
||||
return "";
|
||||
});
|
||||
if (databundle.some(function(aItem) aItem === null))
|
||||
throw("String not found");
|
||||
return LocaleUI.strings.formatStringFromName(aStringName, databundle, databundle.length);
|
||||
}
|
||||
|
||||
return LocaleUI.strings.GetStringFromName(aStringName);
|
||||
}
|
||||
|
||||
let installListener = {
|
||||
onNewInstall: function(install) { },
|
||||
onDownloadStarted: function(install) { },
|
||||
onDownloadProgress: function(install) { },
|
||||
onDownloadEnded: function(install) { },
|
||||
onDownloadCancelled: function(install) {
|
||||
LocaleUI.cancelInstall();
|
||||
LocaleUI.showPicker();
|
||||
},
|
||||
onDownloadFailed: function(install) {
|
||||
LocaleUI.cancelInstall();
|
||||
LocaleUI.installStatus = "error";
|
||||
},
|
||||
onInstallStarted: function(install) { },
|
||||
onInstallEnded: function(install, addon) {
|
||||
LocaleUI.updateStrings(LocaleUI._currentInstall);
|
||||
LocaleUI.closePicker();
|
||||
},
|
||||
onInstallCancelled: function(install) {
|
||||
LocaleUI.cancelInstall();
|
||||
LocaleUI.showPicker();
|
||||
},
|
||||
onInstallFailed: function(install) {
|
||||
LocaleUI.cancelInstall();
|
||||
LocaleUI.installStatus = "error";
|
||||
},
|
||||
onExternalInstall: function(install, existingAddon, needsRestart) { }
|
||||
}
|
||||
|
||||
const PERFECT_MATCH = 2;
|
||||
const GOOD_MATCH = 1;
|
||||
const NO_MATCH = 0;
|
||||
//Compares two locales of the form AB or AB-CD
|
||||
//returns GOOD_MATCH if AB == AB in both locales, PERFECT_MATCH if AB-CD == AB-CD
|
||||
function localesMatch(aLocale1, aLocale2) {
|
||||
if (aLocale1 == aLocale2)
|
||||
return PERFECT_MATCH;
|
||||
|
||||
let short1 = aLocale1.split("-")[0];
|
||||
let short2 = aLocale2.split("-")[0];
|
||||
return (short1 == short2) ? GOOD_MATCH : NO_MATCH;
|
||||
}
|
||||
|
||||
function start() {
|
||||
let mouseModule = new MouseModule();
|
||||
|
||||
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
|
||||
chrome.QueryInterface(Ci.nsIToolkitChromeRegistry);
|
||||
let availableLocales = chrome.getLocalesForPackage("browser");
|
||||
|
||||
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
|
||||
let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE");
|
||||
let matchingLocale = "";
|
||||
|
||||
let bestMatch = NO_MATCH;
|
||||
|
||||
let strings = Services.strings.createBundle("chrome://browser/content/languages.properties");
|
||||
LocaleUI.availableLocales = [];
|
||||
while (availableLocales.hasMore()) {
|
||||
let locale = availableLocales.getNext();
|
||||
|
||||
let label = locale;
|
||||
try { label = strings.GetStringFromName(locale); }
|
||||
catch (e) { }
|
||||
LocaleUI.availableLocales.push({addon: { id: locale, name: label, targetLocale: locale }});
|
||||
|
||||
// see if we have a locale that looks like the system locale
|
||||
// if it is not the current locale, switch to it
|
||||
let match = localesMatch(systemLocale, locale);
|
||||
if (match > bestMatch) {
|
||||
bestMatch = match;
|
||||
matchingLocale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingLocale != chrome.getSelectedLocale("browser"))
|
||||
LocaleUI.language = matchingLocale;
|
||||
else {
|
||||
LocaleUI._language = chrome.getSelectedLocale("browser");
|
||||
LocaleUI.updateStrings();
|
||||
}
|
||||
|
||||
// update the page strings and show the correct page
|
||||
LocaleUI.defaultLanguage = LocaleUI._language;
|
||||
window.addEventListener("resize", resizeHandler, false);
|
||||
}
|
||||
|
||||
function resizeHandler() {
|
||||
let elements = document.getElementsByClassName("window-width");
|
||||
for (let i = 0; i < elements.length; i++)
|
||||
elements[i].setAttribute("width", Math.min(800, window.innerWidth));
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/localePicker.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="start();"
|
||||
width="480"
|
||||
height="800">
|
||||
<script src="chrome://browser/content/Util.js" type="application/javascript;version=1.8"/>
|
||||
<script src="chrome://browser/content/input.js" type="application/javascript;version=1.8"/>
|
||||
<script src="chrome://browser/content/localePicker.js" type="application/javascript;version=1.8"/>
|
||||
<deck id="language-deck" flex="1">
|
||||
<vbox id="main-page" class="pane" flex="1">
|
||||
<spacer flex="1"/>
|
||||
<button class="continue" id="continue-in-button" onclick="LocaleUI.closeWindow();" crop="center"/>
|
||||
<description id="change-language" class="link" onclick="LocaleUI.showPicker();" role="button"/>
|
||||
</vbox>
|
||||
|
||||
<vbox id="picker-page" class="pane" flex="1">
|
||||
<description id="picker-title"/>
|
||||
<richlistbox id="language-list" onclick="LocaleUI.selectLanguage(event);" flex="1" class="window-width"/>
|
||||
<hbox class="footer">
|
||||
<button id="cancel-button" class="cancel" onclick="LocaleUI.cancelPicker();" crop="center"/>
|
||||
<button id="continue-button" class="continue" onclick="LocaleUI.installAddon();" crop="center"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<deck id="installer-page" class="pane" flex="1">
|
||||
<vbox id="installer-page-installing" flex="1" pack="center" align="center">
|
||||
<description id="intalling-message" class="install-message"/>
|
||||
<button id="cancel-install-button" class="cancel" onclick="LocaleUI.cancelInstall();" crop="center"/>
|
||||
</vbox>
|
||||
<vbox id="installer-page-error" flex="1" pack="center" align="center">
|
||||
<description id="installing-error" class="install-message"/>
|
||||
<button id="install-continue" class="continue" onclick="LocaleUI.clearInstallError();" crop="center"/>
|
||||
</vbox>
|
||||
</deck>
|
||||
|
||||
</deck>
|
||||
</window>
|
|
@ -15,6 +15,8 @@ chrome.jar:
|
|||
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
|
||||
content/aboutCertError.css (content/aboutCertError.css)
|
||||
content/aboutHome.xhtml (content/aboutHome.xhtml)
|
||||
content/localePicker.xul (content/localePicker.xul)
|
||||
content/localePicker.js (content/localePicker.js)
|
||||
* content/aboutRights.xhtml (content/aboutRights.xhtml)
|
||||
content/blockedSite.xhtml (content/blockedSite.xhtml)
|
||||
content/languages.properties (content/languages.properties)
|
||||
|
|
|
@ -194,16 +194,19 @@ BrowserCLH.prototype = {
|
|||
// Default to the saved homepage
|
||||
let defaultURL = getHomePage();
|
||||
|
||||
// Override the default if we have a new profile
|
||||
if (needHomepageOverride() == "new profile")
|
||||
defaultURL = "about:firstrun";
|
||||
|
||||
// Override the default if we have a URL passed on command line
|
||||
if (uris.length > 0) {
|
||||
defaultURL = uris[0].spec;
|
||||
uris = uris.slice(1);
|
||||
}
|
||||
|
||||
// Show the locale selector if we have a new profile
|
||||
if (needHomepageOverride() == "new profile" && Services.prefs.getBoolPref("browser.firstrun.show.localepicker")) {
|
||||
win = openWindow(null, "chrome://browser/content/localePicker.xul", "_blank", "chrome,dialog=no,all", defaultURL);
|
||||
aCmdLine.preventDefault = true;
|
||||
return;
|
||||
}
|
||||
|
||||
win = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", defaultURL);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
title=Select a language
|
||||
continueIn=Continue in %S
|
||||
name=English
|
||||
choose=Choose a different language
|
||||
chooseLanguage=Choose a Language
|
||||
cancel=Cancel
|
||||
continue=Continue
|
||||
installing=Installing %S
|
||||
installerror=Error installing language
|
||||
list.loading=Loading...
|
|
@ -9,6 +9,7 @@
|
|||
locale/@AB_CD@/browser/browser.properties (%chrome/browser.properties)
|
||||
locale/@AB_CD@/browser/config.dtd (%chrome/config.dtd)
|
||||
locale/@AB_CD@/browser/firstrun.dtd (%chrome/firstrun.dtd)
|
||||
locale/@AB_CD@/browser/localepicker.properties (%chrome/localepicker.properties)
|
||||
locale/@AB_CD@/browser/region.properties (%chrome/region.properties)
|
||||
locale/@AB_CD@/browser/preferences.dtd (%chrome/preferences.dtd)
|
||||
locale/@AB_CD@/browser/checkbox.dtd (%chrome/checkbox.dtd)
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Mobile Browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mark Finkle <mfinkle@mozilla.com>
|
||||
* Wes Johnston <wjohnston@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let EXPORTED_SYMBOLS = ["LocaleRepository"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var gServiceURL = Services.prefs.getCharPref("extensions.getLocales.get.url");
|
||||
|
||||
// A map between XML keys to LocaleSearchResult keys for string values
|
||||
// that require no extra parsing from XML
|
||||
const STRING_KEY_MAP = {
|
||||
name: "name",
|
||||
target_locale: "targetLocale",
|
||||
version: "version",
|
||||
icon: "iconURL",
|
||||
homepage: "homepageURL",
|
||||
support: "supportURL"
|
||||
};
|
||||
|
||||
var LocaleRepository = {
|
||||
loggingEnabled: false,
|
||||
|
||||
log: function(aMessage) {
|
||||
if (this.loggingEnabled)
|
||||
dump(aMessage + "\n");
|
||||
},
|
||||
|
||||
_getUniqueDescendant: function _getUniqueDescendant(aElement, aTagName) {
|
||||
let elementsList = aElement.getElementsByTagName(aTagName);
|
||||
return (elementsList.length == 1) ? elementsList[0] : null;
|
||||
},
|
||||
|
||||
_getTextContent: function _getTextContent(aElement) {
|
||||
let textContent = aElement.textContent.trim();
|
||||
return (textContent.length > 0) ? textContent : null;
|
||||
},
|
||||
|
||||
_getDescendantTextContent: function _getDescendantTextContent(aElement, aTagName) {
|
||||
let descendant = this._getUniqueDescendant(aElement, aTagName);
|
||||
return (descendant != null) ? this._getTextContent(descendant) : null;
|
||||
},
|
||||
|
||||
getLocales: function getLocales(aCallback) {
|
||||
if (!gServiceURL) {
|
||||
aCallback([]);
|
||||
return;
|
||||
}
|
||||
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
|
||||
request.mozBackgroundRequest = true;
|
||||
request.open("GET", gServiceURL, true);
|
||||
request.overrideMimeType("text/xml");
|
||||
|
||||
let self = this;
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
if (request.status == 200) {
|
||||
self.log("---- got response")
|
||||
let documentElement = request.responseXML.documentElement;
|
||||
let elements = documentElement.getElementsByTagName("addon");
|
||||
let totalResults = elements.length;
|
||||
let parsedTotalResults = parseInt(documentElement.getAttribute("total_results"));
|
||||
if (parsedTotalResults >= totalResults)
|
||||
totalResults = parsedTotalResults;
|
||||
|
||||
// TODO: Create a real Skip object from installed locales
|
||||
self._parseLocales(elements, totalResults, { ids: [], sourceURIs: [] }, aCallback);
|
||||
} else {
|
||||
Cu.reportError("Locale Repository: Error getting locale from AMO [" + request.status + "]");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.send(null);
|
||||
},
|
||||
|
||||
_parseLocale: function _parseLocale(aElement, aSkip) {
|
||||
let skipIDs = (aSkip && aSkip.ids) ? aSkip.ids : [];
|
||||
let skipSourceURIs = (aSkip && aSkip.sourceURIs) ? aSkip.sourceURIs : [];
|
||||
|
||||
let guid = this._getDescendantTextContent(aElement, "guid");
|
||||
if (guid == null || skipIDs.indexOf(guid) != -1)
|
||||
return null;
|
||||
|
||||
let addon = new LocaleSearchResult(guid);
|
||||
let result = {
|
||||
addon: addon,
|
||||
xpiURL: null,
|
||||
xpiHash: null
|
||||
};
|
||||
|
||||
let self = this;
|
||||
for (let node = aElement.firstChild; node; node = node.nextSibling) {
|
||||
if (!(node instanceof Ci.nsIDOMElement))
|
||||
continue;
|
||||
|
||||
let localName = node.localName;
|
||||
|
||||
// Handle case where the wanted string value is located in text content
|
||||
// but only if the content is not empty
|
||||
if (localName in STRING_KEY_MAP) {
|
||||
addon[STRING_KEY_MAP[localName]] = this._getTextContent(node) || addon[STRING_KEY_MAP[localName]];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle cases that aren't as simple as grabbing the text content
|
||||
switch (localName) {
|
||||
case "type":
|
||||
// Map AMO's type id to corresponding string
|
||||
let id = parseInt(node.getAttribute("id"));
|
||||
switch (id) {
|
||||
case 5:
|
||||
addon.type = "language";
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown type id when parsing addon: " + id);
|
||||
}
|
||||
break;
|
||||
case "authors":
|
||||
let authorNodes = node.getElementsByTagName("author");
|
||||
Array.forEach(authorNodes, function(aAuthorNode) {
|
||||
let name = self._getDescendantTextContent(aAuthorNode, "name");
|
||||
if (name == null)
|
||||
name = self._getTextContent(aAuthorNode);
|
||||
let link = self._getDescendantTextContent(aAuthorNode, "link");
|
||||
if (name == null && link == null)
|
||||
return;
|
||||
|
||||
let author = { name: name, link: link };
|
||||
if (addon.creator == null) {
|
||||
addon.creator = author;
|
||||
} else {
|
||||
if (addon.developers == null)
|
||||
addon.developers = [];
|
||||
|
||||
addon.developers.push(author);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "status":
|
||||
let repositoryStatus = parseInt(node.getAttribute("id"));
|
||||
if (!isNaN(repositoryStatus))
|
||||
addon.repositoryStatus = repositoryStatus;
|
||||
break;
|
||||
case "all_compatible_os":
|
||||
let nodes = node.getElementsByTagName("os");
|
||||
addon.isPlatformCompatible = Array.some(nodes, function(aNode) {
|
||||
let text = aNode.textContent.toLowerCase().trim();
|
||||
return text == "all" || text == Services.appinfo.OS.toLowerCase();
|
||||
});
|
||||
break;
|
||||
case "install":
|
||||
// No os attribute means the xpi is compatible with any os
|
||||
if (node.hasAttribute("os") && node.getAttribute("os")) {
|
||||
let os = node.getAttribute("os").trim().toLowerCase();
|
||||
// If the os is not ALL and not the current OS then ignore this xpi
|
||||
if (os != "all" && os != Services.appinfo.OS.toLowerCase())
|
||||
break;
|
||||
}
|
||||
|
||||
let xpiURL = this._getTextContent(node);
|
||||
if (xpiURL == null)
|
||||
break;
|
||||
|
||||
if (skipSourceURIs.indexOf(xpiURL) != -1)
|
||||
return null;
|
||||
|
||||
result.xpiURL = xpiURL;
|
||||
addon.sourceURI = NetUtil.newURI(xpiURL);
|
||||
|
||||
let size = parseInt(node.getAttribute("size"));
|
||||
addon.size = (size >= 0) ? size : null;
|
||||
|
||||
let xpiHash = node.getAttribute("hash");
|
||||
if (xpiHash != null)
|
||||
xpiHash = xpiHash.trim();
|
||||
result.xpiHash = xpiHash ? xpiHash : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
_parseLocales: function _parseLocales(aElements, aTotalResults, aSkip, aCallback) {
|
||||
let self = this;
|
||||
let results = [];
|
||||
for (let i = 0; i < aElements.length; i++) {
|
||||
let element = aElements[i];
|
||||
|
||||
// Ignore add-ons not compatible with this Application
|
||||
let tags = this._getUniqueDescendant(element, "compatible_applications");
|
||||
if (tags == null)
|
||||
continue;
|
||||
|
||||
let applications = tags.getElementsByTagName("appID");
|
||||
let compatible = Array.some(applications, function(aAppNode) {
|
||||
if (self._getTextContent(aAppNode) != Services.appinfo.ID)
|
||||
return false;
|
||||
|
||||
let parent = aAppNode.parentNode;
|
||||
let minVersion = self._getDescendantTextContent(parent, "min_version");
|
||||
let maxVersion = self._getDescendantTextContent(parent, "max_version");
|
||||
if (minVersion == null || maxVersion == null)
|
||||
return false;
|
||||
|
||||
let currentVersion = Services.appinfo.version;
|
||||
return (Services.vc.compare(minVersion, currentVersion) <= 0 && Services.vc.compare(currentVersion, maxVersion) <= 0);
|
||||
});
|
||||
|
||||
if (!compatible)
|
||||
continue;
|
||||
|
||||
// Add-on meets all requirements, so parse out data
|
||||
let result = this._parseLocale(element, aSkip);
|
||||
if (result == null)
|
||||
continue;
|
||||
|
||||
// Ignore add-on missing a required attribute
|
||||
let requiredAttributes = ["id", "name", "version", "type", "targetLocale"];
|
||||
if (requiredAttributes.some(function(aAttribute) !result.addon[aAttribute]))
|
||||
continue;
|
||||
|
||||
// Add only if the add-on is compatible with the platform
|
||||
if (!result.addon.isPlatformCompatible)
|
||||
continue;
|
||||
|
||||
// Add only if there was an xpi compatible with this OS
|
||||
if (!result.xpiURL)
|
||||
continue;
|
||||
|
||||
results.push(result);
|
||||
|
||||
// Ignore this add-on from now on by adding it to the skip array
|
||||
aSkip.ids.push(result.addon.id);
|
||||
}
|
||||
|
||||
// Immediately report success if no AddonInstall instances to create
|
||||
let pendingResults = results.length;
|
||||
if (pendingResults == 0) {
|
||||
aCallback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an AddonInstall for each result
|
||||
let self = this;
|
||||
results.forEach(function(aResult) {
|
||||
let addon = aResult.addon;
|
||||
let callback = function(aInstall) {
|
||||
aResult.addon.install = aInstall;
|
||||
pendingResults--;
|
||||
if (pendingResults == 0)
|
||||
aCallback(results);
|
||||
}
|
||||
|
||||
if (aResult.xpiURL) {
|
||||
AddonManager.getInstallForURL(aResult.xpiURL, callback,
|
||||
"application/x-xpinstall", aResult.xpiHash,
|
||||
addon.name, addon.iconURL, addon.version);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function LocaleSearchResult(aId) {
|
||||
this.id = aId;
|
||||
}
|
||||
|
||||
LocaleSearchResult.prototype = {
|
||||
id: null,
|
||||
type: null,
|
||||
targetLocale: null,
|
||||
name: null,
|
||||
addon: null,
|
||||
version: null,
|
||||
iconURL: null,
|
||||
install: null,
|
||||
sourceURI: null,
|
||||
repositoryStatus: null,
|
||||
size: null,
|
||||
updateDate: null,
|
||||
isCompatible: true,
|
||||
isPlatformCompatible: true,
|
||||
providesUpdatesSecurely: true,
|
||||
blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
|
||||
appDisabled: false,
|
||||
userDisabled: false,
|
||||
scope: AddonManager.SCOPE_PROFILE,
|
||||
isActive: true,
|
||||
pendingOperations: AddonManager.PENDING_NONE,
|
||||
permissions: 0
|
||||
};
|
|
@ -43,6 +43,7 @@ VPATH = @srcdir@
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
LocaleRepository.jsm \
|
||||
linuxTypes.jsm \
|
||||
video.jsm \
|
||||
$(NULL)
|
||||
|
|
|
@ -1453,10 +1453,6 @@ setting {
|
|||
min-width: 5.5em;
|
||||
}
|
||||
|
||||
.syncsetup-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.syncsetup-label {
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
@ -1430,10 +1430,6 @@ setting {
|
|||
min-width: 5.5em;
|
||||
}
|
||||
|
||||
.syncsetup-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.syncsetup-label {
|
||||
color: @color_text_default@;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
%define color_text_button #000
|
||||
%define color_text_disabled #808080
|
||||
%define color_text_placeholder #808080
|
||||
%define color_text_as_link #febc2b
|
||||
|
||||
%define color_background_highlight #febc2b
|
||||
%define color_background_highlight_overlay rgba(254, 188, 43, 0.8)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Mobile Browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Wes Johnston <wjohnston@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
%filter substitution
|
||||
%include defines.inc
|
||||
|
||||
.pane {
|
||||
-moz-box-pack: center;
|
||||
-moz-box-align: center;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#main-page {
|
||||
background-image: url("chrome://branding/content/logo.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
#picker-title {
|
||||
font-weight: bold;
|
||||
font-size: @font_normal@;
|
||||
}
|
||||
|
||||
.link {
|
||||
padding: @padding_xlarge@ 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
richlistbox {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#installer-page {
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
height: @touch_row@;
|
||||
font-size: @font_normal@;
|
||||
border-bottom: @border_width_tiny@ solid gray;
|
||||
padding: 0px @padding_normal@;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
richlistitem .checkbox {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
list-style-image: url("chrome://browser/skin/images/radio-unselected-hdpi.png");
|
||||
}
|
||||
|
||||
richlistitem[selected] .checkbox {
|
||||
list-style-image: url("chrome://browser/skin/images/radio-selected-hdpi.png");
|
||||
}
|
|
@ -45,6 +45,8 @@
|
|||
:root {
|
||||
font-family: "Nokia Sans", Tahoma, sans-serif !important;
|
||||
font-size: @font_normal@ !important;
|
||||
background-color: @color_background_default@; /* force */
|
||||
color: @color_text_default@; /* force */
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
|
@ -96,6 +98,11 @@ textbox[disabled="true"] {
|
|||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: @color_text_as_link@;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* sidebars spacer --------------------------------------------------------- */
|
||||
.sidebar-spacer {
|
||||
background-color: #767973;
|
||||
|
|
|
@ -18,6 +18,7 @@ chrome.jar:
|
|||
* skin/notification.css (notification.css)
|
||||
* skin/platform.css (platform.css)
|
||||
skin/touchcontrols.css (touchcontrols.css)
|
||||
* skin/localePicker.css (localePicker.css)
|
||||
% override chrome://global/skin/about.css chrome://browser/skin/about.css
|
||||
% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css
|
||||
|
||||
|
@ -138,6 +139,7 @@ chrome.jar:
|
|||
* skin/gingerbread/notification.css (notification.css)
|
||||
* skin/gingerbread/platform.css (gingerbread/platform.css)
|
||||
skin/gingerbread/touchcontrols.css (touchcontrols.css)
|
||||
* skin/gingerbread/localePicker.css (gingerbread/localePicker.css)
|
||||
% override chrome://global/skin/about.css chrome://browser/skin/about.css
|
||||
% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css
|
||||
|
||||
|
@ -255,6 +257,7 @@ chrome.jar:
|
|||
* skin/honeycomb/notification.css (notification.css)
|
||||
* skin/honeycomb/platform.css (platform.css)
|
||||
skin/honeycomb/touchcontrols.css (touchcontrols.css)
|
||||
* skin/honeycomb/localePicker.css (localePicker.css)
|
||||
% override chrome://global/skin/about.css chrome://browser/skin/about.css
|
||||
% override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Mobile Browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Wes Johnston <wjohnston@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
%filter substitution
|
||||
%include defines.inc
|
||||
|
||||
.pane {
|
||||
-moz-box-pack: center;
|
||||
-moz-box-align: center;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#main-page {
|
||||
background-image: url("chrome://branding/content/logo.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
#picker-title {
|
||||
font-weight: bold;
|
||||
font-size: @font_normal@;
|
||||
}
|
||||
|
||||
.link {
|
||||
padding: @padding_xlarge@ 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
richlistbox {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#installer-page {
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
height: @touch_row@;
|
||||
font-size: @font_normal@;
|
||||
border-bottom: @border_width_tiny@ solid gray;
|
||||
padding: 0px @padding_normal@;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
richlistitem .checkbox {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
list-style-image: url("chrome://browser/skin/images/check-unselected-30.png");
|
||||
}
|
||||
|
||||
richlistitem[selected] .checkbox {
|
||||
list-style-image: url("chrome://browser/skin/images/check-selected-30.png");
|
||||
}
|
|
@ -45,6 +45,8 @@
|
|||
:root {
|
||||
font-family: "Nokia Sans", Tahoma, sans-serif !important;
|
||||
font-size: @font_normal@ !important;
|
||||
background-color: white; /* force */
|
||||
color: black; /* force */
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
|
@ -98,6 +100,11 @@ textbox[disabled="true"] {
|
|||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* sidebars spacer --------------------------------------------------------- */
|
||||
.sidebar-spacer {
|
||||
background-color: #767973;
|
||||
|
@ -581,6 +588,10 @@ dialog {
|
|||
margin: @padding_normal@;
|
||||
}
|
||||
|
||||
.prompt-message .link {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.prompt-title {
|
||||
text-align: center;
|
||||
font-size: @font_xnormal@;
|
||||
|
|
Загрузка…
Ссылка в новой задаче