Bug 653141 - Allow language choice on first-run. r=mfinkle

This commit is contained in:
Wes Johnston 2011-06-07 12:11:37 -07:00
Родитель 179177d1fa
Коммит 1d363880de
22 изменённых файлов: 988 добавлений и 17 удалений

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

@ -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@;