зеркало из https://github.com/mozilla/gecko-dev.git
Bug config - Make Metro about:config better, r=mbrubeck
* * * Bug 959031 - Make Metro about:config better -- Nits, r=mbrubeck * * * Bug 959031 - Make Metro about:config better -- Retro Fit Strings, r=mbrubeck --HG-- rename : mobile/android/chrome/content/config.js => browser/metro/base/content/pages/config.js rename : mobile/android/chrome/content/config.xhtml => browser/metro/base/content/pages/config.xhtml
This commit is contained in:
Родитель
196e368400
Коммит
5f0e931495
|
@ -1,407 +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/. */
|
||||
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var ViewConfig = {
|
||||
get _main() {
|
||||
delete this._main;
|
||||
return this._main = document.getElementById("main-container");
|
||||
},
|
||||
|
||||
get _container() {
|
||||
delete this._container;
|
||||
return this._container = document.getElementById("prefs-container");
|
||||
},
|
||||
|
||||
get _editor() {
|
||||
delete this._editor;
|
||||
return this._editor = document.getElementById("editor");
|
||||
},
|
||||
|
||||
init: function init() {
|
||||
this._main.addEventListener("click", this, false);
|
||||
window.addEventListener("resize", this, false);
|
||||
window.addEventListener("prefchange", this, false);
|
||||
window.addEventListener("prefnew", this, false);
|
||||
|
||||
this._handleWindowResize();
|
||||
this.filter("");
|
||||
|
||||
document.getElementById("textbox").focus();
|
||||
},
|
||||
|
||||
uninit: function uninit() {
|
||||
this._main.removeEventListener("click", this, false);
|
||||
window.removeEventListener("resize", this, false);
|
||||
window.removeEventListener("prefchange", this, false);
|
||||
window.removeEventListener("prefnew", this, false);
|
||||
},
|
||||
|
||||
filter: function filter(aValue) {
|
||||
let row = document.getElementById("editor-row");
|
||||
|
||||
let container = this._container;
|
||||
container.scrollBoxObject.scrollTo(0, 0);
|
||||
// Clear the list by replacing with a shallow copy
|
||||
let empty = container.cloneNode(false);
|
||||
empty.appendChild(row);
|
||||
container.parentNode.replaceChild(empty, container);
|
||||
this._container = empty;
|
||||
|
||||
let result = Utils.getPrefs(aValue);
|
||||
this._container.setItems(result.map(this._createItem, this));
|
||||
},
|
||||
|
||||
open: function open(aType) {
|
||||
let buttons = document.getElementById("editor-buttons-add");
|
||||
buttons.setAttribute("hidden", "true");
|
||||
|
||||
let shouldFocus = false;
|
||||
let setting = document.getElementById("editor-setting");
|
||||
switch (aType) {
|
||||
case Ci.nsIPrefBranch.PREF_INT:
|
||||
setting.setAttribute("type", "integer");
|
||||
setting.setAttribute("min", -Infinity);
|
||||
break;
|
||||
case Ci.nsIPrefBranch.PREF_BOOL:
|
||||
setting.setAttribute("type", "bool");
|
||||
break;
|
||||
case Ci.nsIPrefBranch.PREF_STRING:
|
||||
setting.setAttribute("type", "string");
|
||||
break;
|
||||
}
|
||||
|
||||
setting.removeAttribute("title");
|
||||
setting.removeAttribute("pref");
|
||||
if (setting.input)
|
||||
setting.input.value = "";
|
||||
|
||||
document.getElementById("editor-container").appendChild(this._editor);
|
||||
let nameField = document.getElementById("editor-name");
|
||||
nameField.value = "";
|
||||
|
||||
this._editor.setAttribute("hidden", "false");
|
||||
this._currentItem = null;
|
||||
nameField.focus();
|
||||
},
|
||||
|
||||
close: function close(aValid) {
|
||||
this._editor.setAttribute("hidden", "true");
|
||||
let buttons = document.getElementById("editor-buttons-add");
|
||||
buttons.setAttribute("hidden", "false");
|
||||
|
||||
if (aValid) {
|
||||
let name = document.getElementById("editor-name").inputField.value;
|
||||
if (name != "") {
|
||||
let setting = document.getElementById("editor-setting");
|
||||
setting.setAttribute("pref", name);
|
||||
setting.valueToPreference();
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("editor-container").appendChild(this._editor);
|
||||
},
|
||||
|
||||
_currentItem: null,
|
||||
|
||||
delayEdit: function(aItem) {
|
||||
setTimeout(this.edit.bind(this), 0, aItem);
|
||||
},
|
||||
|
||||
edit: function(aItem) {
|
||||
if (!aItem)
|
||||
return;
|
||||
|
||||
let pref = Utils.getPref(aItem.getAttribute("name"));
|
||||
if (pref.lock || !pref.name || aItem == this._currentItem)
|
||||
return;
|
||||
|
||||
this.close(false);
|
||||
this._currentItem = aItem;
|
||||
|
||||
let setting = document.getElementById("editor-setting");
|
||||
let shouldFocus = false;
|
||||
switch (pref.type) {
|
||||
case Ci.nsIPrefBranch.PREF_BOOL:
|
||||
setting.setAttribute("type", "bool");
|
||||
break;
|
||||
|
||||
case Ci.nsIPrefBranch.PREF_INT:
|
||||
setting.setAttribute("type", "integer");
|
||||
setting.setAttribute("increment", this.getIncrementForValue(pref.value));
|
||||
setting.setAttribute("min", -Infinity);
|
||||
shouldFocus = true;
|
||||
break;
|
||||
|
||||
case Ci.nsIPrefBranch.PREF_STRING:
|
||||
setting.setAttribute("type", "string");
|
||||
shouldFocus = true;
|
||||
break;
|
||||
}
|
||||
|
||||
setting.setAttribute("title", pref.name);
|
||||
setting.setAttribute("pref", pref.name);
|
||||
|
||||
this._container.insertBefore(this._editor, aItem);
|
||||
|
||||
let resetButton = document.getElementById("editor-reset");
|
||||
resetButton.setAttribute("disabled", pref.default);
|
||||
|
||||
this._editor.setAttribute("default", pref.default);
|
||||
this._editor.setAttribute("hidden", "false");
|
||||
|
||||
if (shouldFocus && setting.input)
|
||||
setting.input.focus();
|
||||
},
|
||||
|
||||
reset: function reset(aItem) {
|
||||
let setting = document.getElementById("editor-setting");
|
||||
let pref = Utils.getPref(setting.getAttribute("pref"));
|
||||
if (!pref.default)
|
||||
Utils.resetPref(pref.name);
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "resize":
|
||||
this._handleWindowResize();
|
||||
break;
|
||||
|
||||
case "prefchange":
|
||||
case "prefnew":
|
||||
this._handlePrefChange(aEvent.detail, aEvent.type == "prefnew");
|
||||
break;
|
||||
|
||||
case "click":
|
||||
this._onClick();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_handleWindowResize: function _handleWindowResize() {
|
||||
let mainBox = document.getElementById("main-container");
|
||||
let textbox = document.getElementById("textbox");
|
||||
let height = window.innerHeight - textbox.getBoundingClientRect().height;
|
||||
|
||||
mainBox.setAttribute("height", height);
|
||||
},
|
||||
|
||||
_onClick: function () {
|
||||
// Blur the search box when tapping anywhere else in the content
|
||||
// in order to close the soft keyboard.
|
||||
document.getElementById("textbox").blur();
|
||||
},
|
||||
|
||||
_handlePrefChange: function _handlePrefChange(aIndex, aNew) {
|
||||
let isEditing = !this._editor.hidden;
|
||||
let shouldUpdateEditor = false;
|
||||
if (isEditing) {
|
||||
let setting = document.getElementById("editor-setting");
|
||||
let editorIndex = Utils.getPrefIndex(setting.getAttribute("pref"));
|
||||
shouldUpdateEditor = (aIndex == editorIndex);
|
||||
if(shouldUpdateEditor || aIndex > editorIndex)
|
||||
aIndex += 1;
|
||||
}
|
||||
|
||||
// XXX An item display value will probably fail if a pref is changed in the
|
||||
// background while there is a filter on the pref
|
||||
let item = shouldUpdateEditor ? this._editor.nextSibling
|
||||
: this._container.childNodes[aIndex + 1];// add 1 because of the new pref row
|
||||
if (!item) // the pref is not viewable
|
||||
return;
|
||||
|
||||
if (aNew) {
|
||||
let pref = Utils.getPrefByIndex(aIndex);
|
||||
let row = this._createItem(pref);
|
||||
this._container.insertBefore(row, item);
|
||||
return;
|
||||
}
|
||||
|
||||
let pref = Utils.getPref(item.getAttribute("name"));
|
||||
if (shouldUpdateEditor) {
|
||||
this._editor.setAttribute("default", pref.default);
|
||||
|
||||
let resetButton = document.getElementById("editor-reset");
|
||||
resetButton.disabled = pref.default;
|
||||
}
|
||||
|
||||
item.setAttribute("default", pref.default);
|
||||
item.lastChild.setAttribute("value", pref.value);
|
||||
},
|
||||
|
||||
_createItem: function _createItem(aPref) {
|
||||
let row = document.createElement("richlistitem");
|
||||
|
||||
row.setAttribute("name", aPref.name);
|
||||
row.setAttribute("type", aPref.type);
|
||||
row.setAttribute("role", "button");
|
||||
row.setAttribute("default", aPref.default);
|
||||
|
||||
let label = document.createElement("label");
|
||||
label.setAttribute("class", "preferences-title");
|
||||
label.setAttribute("value", aPref.name);
|
||||
label.setAttribute("crop", "end");
|
||||
row.appendChild(label);
|
||||
|
||||
label = document.createElement("label");
|
||||
label.setAttribute("class", "preferences-value");
|
||||
label.setAttribute("value", aPref.value);
|
||||
label.setAttribute("crop", "end");
|
||||
row.appendChild(label);
|
||||
|
||||
return row;
|
||||
},
|
||||
|
||||
getIncrementForValue: function getIncrementForValue(aValue) {
|
||||
let count = 1;
|
||||
while (aValue >= 100) {
|
||||
aValue /= 10;
|
||||
count *= 10;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
var Utils = {
|
||||
QueryInterface: function(aIID) {
|
||||
if (!aIID.equals(Ci.nsIObserver) && !aIID.equals(Ci.nsISupportsWeakReference))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
|
||||
get _branch() {
|
||||
delete this._branch;
|
||||
this._branch = Services.prefs.getBranch(null);
|
||||
this._branch.addObserver("", this, true);
|
||||
return this._branch;
|
||||
},
|
||||
|
||||
get _preferences() {
|
||||
delete this._preferences;
|
||||
let list = this._branch.getChildList("", {}).filter(function(element) {
|
||||
return !(/^capability\./.test(element));
|
||||
});
|
||||
return this._preferences = list.sort().map(this.getPref, this);
|
||||
},
|
||||
|
||||
getPrefs: function getPrefs(aValue) {
|
||||
let result = this._preferences.slice();;
|
||||
if (aValue != "") {
|
||||
let reg = this._generateRegexp(aValue);
|
||||
if (!reg)
|
||||
return [];
|
||||
|
||||
result = this._preferences.filter(function(element, index, array) {
|
||||
return reg.test(element.name + ";" + element.value);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getPref: function getPref(aPrefName) {
|
||||
let branch = this._branch;
|
||||
let pref = {
|
||||
name: aPrefName,
|
||||
value: "",
|
||||
default: !branch.prefHasUserValue(aPrefName),
|
||||
lock: branch.prefIsLocked(aPrefName),
|
||||
type: branch.getPrefType(aPrefName)
|
||||
};
|
||||
|
||||
try {
|
||||
switch (pref.type) {
|
||||
case Ci.nsIPrefBranch.PREF_BOOL:
|
||||
pref.value = branch.getBoolPref(aPrefName).toString();
|
||||
break;
|
||||
case Ci.nsIPrefBranch.PREF_INT:
|
||||
pref.value = branch.getIntPref(aPrefName).toString();
|
||||
break;
|
||||
default:
|
||||
case Ci.nsIPrefBranch.PREF_STRING:
|
||||
pref.value = branch.getComplexValue(aPrefName, Ci.nsISupportsString).data;
|
||||
// Try in case it's a localized string (will throw an exception if not)
|
||||
if (pref.default && /^chrome:\/\/.+\/locale\/.+\.properties/.test(pref.value))
|
||||
pref.value = branch.getComplexValue(aPrefName, Ci.nsIPrefLocalizedString).data;
|
||||
break;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return pref;
|
||||
},
|
||||
|
||||
getPrefByIndex: function getPrefByIndex(aIndex) {
|
||||
return this._preferences[aIndex];
|
||||
},
|
||||
|
||||
getPrefIndex: function getPrefIndex(aPrefName) {
|
||||
let prefs = this._preferences;
|
||||
let high = prefs.length - 1;
|
||||
let low = 0, middle, element;
|
||||
|
||||
while (low <= high) {
|
||||
middle = parseInt((low + high) / 2);
|
||||
element = prefs[middle];
|
||||
|
||||
if (element.name > aPrefName)
|
||||
high = middle - 1;
|
||||
else if (element.name < aPrefName)
|
||||
low = middle + 1;
|
||||
else
|
||||
return middle;
|
||||
}
|
||||
|
||||
return -1;
|
||||
},
|
||||
|
||||
resetPref: function resetPref(aPrefName) {
|
||||
this._branch.clearUserPref(aPrefName);
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aPrefName) {
|
||||
if (aTopic != "nsPref:changed" || /^capability\./.test(aPrefName)) // avoid displaying "private" preferences
|
||||
return;
|
||||
|
||||
let type = "prefchange";
|
||||
let index = this.getPrefIndex(aPrefName);
|
||||
if (index != - 1) {
|
||||
// update the inner array
|
||||
let pref = this.getPref(aPrefName);
|
||||
this._preferences[index].value = pref.value;
|
||||
}
|
||||
else {
|
||||
// XXX we could do better here
|
||||
let list = this._branch.getChildList("", {}).filter(function(element, index, array) {
|
||||
return !(/^capability\./.test(element));
|
||||
});
|
||||
this._preferences = list.sort().map(this.getPref, this);
|
||||
|
||||
type = "prefnew";
|
||||
index = this.getPrefIndex(aPrefName);
|
||||
}
|
||||
|
||||
let evt = document.createEvent("UIEvents");
|
||||
evt.initUIEvent(type, true, true, window, index);
|
||||
window.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
_generateRegexp: function _generateRegexp(aValue) {
|
||||
if (aValue.charAt(0) == "/") {
|
||||
try {
|
||||
let rv = aValue.match(/^\/(.*)\/(i?)$/);
|
||||
return RegExp(rv[1], rv[2]);
|
||||
}
|
||||
catch (e) {
|
||||
return null; // Do nothing on incomplete or bad RegExp
|
||||
}
|
||||
}
|
||||
|
||||
return RegExp(aValue.replace(/([^* \w])/g, "\\$1").replace(/^\*+/, "")
|
||||
.replace(/\*+/g, ".*"), "i");
|
||||
}
|
||||
};
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/config.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % configDTD SYSTEM "chrome://browser/locale/config.dtd">
|
||||
%configDTD;
|
||||
]>
|
||||
|
||||
<window id="about:config"
|
||||
onload="ViewConfig.init();"
|
||||
onunload="ViewConfig.uninit();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/x-javascript" src="chrome://browser/content/config.js"/>
|
||||
|
||||
<vbox class="panel-dark" flex="1">
|
||||
<textbox id="textbox"
|
||||
oncommand="ViewConfig.filter(this.value)"
|
||||
type="search"
|
||||
timeout="400"
|
||||
emptytext="&empty.label;"/>
|
||||
|
||||
<hbox id="main-container" class="panel-dark">
|
||||
<richlistbox id="prefs-container" flex="1" onselect="ViewConfig.delayEdit(this.selectedItem)" batch="25">
|
||||
<richlistitem id="editor-row">
|
||||
<vbox id="editor-container" flex="1">
|
||||
|
||||
<hbox align="center" flex="1">
|
||||
<label value="&newpref.label;" flex="1"/>
|
||||
<spacer flex="1" />
|
||||
<hbox id="editor-buttons-add">
|
||||
<button label="&integer.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_INT)"/>
|
||||
<button label="&boolean.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_BOOL)"/>
|
||||
<button label="&string.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_STRING)"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
<vbox id="editor" hidden="true">
|
||||
<hbox align="center">
|
||||
<textbox id="editor-name" emptytext="&addpref.name;" flex="1"/>
|
||||
<setting id="editor-setting" emptytext="&addpref.value;" onlabel="true" offlabel="false" flex="1"/>
|
||||
</hbox>
|
||||
<hbox id="editor-buttons">
|
||||
<button id="editor-cancel" label="&cancel.label;" oncommand="ViewConfig.close(false)"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="editor-reset" label="&reset.label;" oncommand="ViewConfig.reset(this.parentNode.parentNode.nextSibling)"/>
|
||||
<button id="editor-done" label="&done.label;" oncommand="ViewConfig.close(true)"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
</vbox>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</window>
|
||||
|
|
@ -0,0 +1,642 @@
|
|||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, manager: Cm, utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const PRIVATE_PREF_PREFIX = "capability."; // Tag to prevent exposing private preferences
|
||||
const INITIAL_PAGE_DELAY = 500; // Initial pause on program start for scroll alignment
|
||||
const PREFS_BUFFER_MAX = 100; // Max prefs buffer size for getPrefsBuffer()
|
||||
const PAGE_SCROLL_TRIGGER = 200; // Triggers additional getPrefsBuffer() on user scroll-to-bottom
|
||||
const FILTER_CHANGE_TRIGGER = 200; // Delay between responses to filterInput changes
|
||||
const INNERHTML_VALUE_DELAY = 100; // Delay before providing prefs innerHTML value
|
||||
|
||||
let gStringBundle = Services.strings.createBundle("chrome://browser/locale/config.properties");
|
||||
let gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||
|
||||
|
||||
/* ============================== NewPrefDialog ==============================
|
||||
*
|
||||
* New Preference Dialog Object and methods
|
||||
*
|
||||
* Implements User Interfaces for creation of a single(new) Preference setting
|
||||
*
|
||||
*/
|
||||
var NewPrefDialog = {
|
||||
|
||||
_prefsShield: null,
|
||||
|
||||
_newPrefsDialog: null,
|
||||
_newPrefItem: null,
|
||||
_prefNameInputElt: null,
|
||||
_prefTypeSelectElt: null,
|
||||
|
||||
_booleanValue: null,
|
||||
_booleanToggle: null,
|
||||
_stringValue: null,
|
||||
_intValue: null,
|
||||
|
||||
_positiveButton: null,
|
||||
|
||||
get type() {
|
||||
return this._prefTypeSelectElt.value;
|
||||
},
|
||||
|
||||
set type(aType) {
|
||||
this._prefTypeSelectElt.value = aType;
|
||||
switch(this._prefTypeSelectElt.value) {
|
||||
case "boolean":
|
||||
this._prefTypeSelectElt.selectedIndex = 0;
|
||||
break;
|
||||
case "string":
|
||||
this._prefTypeSelectElt.selectedIndex = 1;
|
||||
break;
|
||||
case "int":
|
||||
this._prefTypeSelectElt.selectedIndex = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
this._newPrefItem.setAttribute("typestyle", aType);
|
||||
},
|
||||
|
||||
// Init the NewPrefDialog
|
||||
init: function AC_init() {
|
||||
this._prefsShield = document.getElementById("prefs-shield");
|
||||
|
||||
this._newPrefsDialog = document.getElementById("new-pref-container");
|
||||
this._newPrefItem = document.getElementById("new-pref-item");
|
||||
this._prefNameInputElt = document.getElementById("new-pref-name");
|
||||
this._prefTypeSelectElt = document.getElementById("new-pref-type");
|
||||
|
||||
this._booleanValue = document.getElementById("new-pref-value-boolean");
|
||||
this._stringValue = document.getElementById("new-pref-value-string");
|
||||
this._intValue = document.getElementById("new-pref-value-int");
|
||||
|
||||
this._positiveButton = document.getElementById("positive-button");
|
||||
},
|
||||
|
||||
// Called to update positive button to display text ("Create"/"Change), and enabled/disabled status
|
||||
// As new pref name is initially displayed, re-focused, or modifed during user input
|
||||
_updatePositiveButton: function AC_updatePositiveButton(aPrefName) {
|
||||
this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.createButton");
|
||||
this._positiveButton.setAttribute("disabled", true);
|
||||
if (aPrefName == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent addition of new "private" preferences
|
||||
if (aPrefName.startsWith(PRIVATE_PREF_PREFIX)) {
|
||||
this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.privateButton");
|
||||
return;
|
||||
}
|
||||
|
||||
// If item already in list, it's being changed, else added
|
||||
let item = document.querySelector(".pref-item[name=" + aPrefName.quote() + "]");
|
||||
if (item) {
|
||||
this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.changeButton");
|
||||
} else {
|
||||
this._positiveButton.removeAttribute("disabled");
|
||||
}
|
||||
},
|
||||
|
||||
// When we want to cancel/hide an existing, or show a new pref dialog
|
||||
toggleShowHide: function AC_toggleShowHide() {
|
||||
if (this._newPrefsDialog.classList.contains("show")) {
|
||||
this.hide();
|
||||
} else {
|
||||
this._show();
|
||||
}
|
||||
},
|
||||
|
||||
// When we want to show the new pref dialog / shield the prefs list
|
||||
_show: function AC_show() {
|
||||
this._newPrefsDialog.classList.add("show");
|
||||
this._prefsShield.setAttribute("shown", true);
|
||||
|
||||
// Initial default field values
|
||||
this._prefNameInputElt.value = "";
|
||||
this._updatePositiveButton(this._prefNameInputElt.value);
|
||||
|
||||
this.type = "boolean";
|
||||
this._booleanValue.value = "false";
|
||||
this._stringValue.value = "";
|
||||
this._intValue.value = "";
|
||||
|
||||
this._prefNameInputElt.focus();
|
||||
|
||||
window.addEventListener("keypress", this.handleKeypress, false);
|
||||
},
|
||||
|
||||
// When we want to cancel/hide the new pref dialog / un-shield the prefs list
|
||||
hide: function AC_hide() {
|
||||
this._newPrefsDialog.classList.remove("show");
|
||||
this._prefsShield.removeAttribute("shown");
|
||||
|
||||
window.removeEventListener("keypress", this.handleKeypress, false);
|
||||
},
|
||||
|
||||
// Watch user key input so we can provide Enter key action, commit input values
|
||||
handleKeypress: function AC_handleKeypress(aEvent) {
|
||||
// Close our VKB on new pref enter key press
|
||||
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
|
||||
aEvent.target.blur();
|
||||
},
|
||||
|
||||
// New prefs create dialog only allows creating a non-existing preference, doesn't allow for
|
||||
// Changing an existing one on-the-fly, tap existing/displayed line item pref for that
|
||||
create: function AC_create(aEvent) {
|
||||
if (this._positiveButton.getAttribute("disabled") == "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(this.type) {
|
||||
case "boolean":
|
||||
Services.prefs.setBoolPref(this._prefNameInputElt.value, (this._booleanValue.value == "true") ? true : false);
|
||||
break;
|
||||
case "string":
|
||||
Services.prefs.setCharPref(this._prefNameInputElt.value, this._stringValue.value);
|
||||
break;
|
||||
case "int":
|
||||
Services.prefs.setIntPref(this._prefNameInputElt.value, this._intValue.value);
|
||||
break;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
},
|
||||
|
||||
// Display proper positive button text/state on new prefs name input focus
|
||||
focusName: function AC_focusName(aEvent) {
|
||||
this._updatePositiveButton(aEvent.target.value);
|
||||
},
|
||||
|
||||
// Display proper positive button text/state as user changes new prefs name
|
||||
updateName: function AC_updateName(aEvent) {
|
||||
this._updatePositiveButton(aEvent.target.value);
|
||||
},
|
||||
|
||||
// In new prefs dialog, bool prefs are <input type="text">, as they aren't yet tied to an
|
||||
// Actual Services.prefs.*etBoolPref()
|
||||
toggleBoolValue: function AC_toggleBoolValue() {
|
||||
this._booleanValue.value = (this._booleanValue.value == "true" ? "false" : "true");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ============================== AboutConfig ==============================
|
||||
*
|
||||
* Main AboutConfig object and methods
|
||||
*
|
||||
* Implements User Interfaces for maintenance of a list of Preference settings
|
||||
*
|
||||
*/
|
||||
var AboutConfig = {
|
||||
|
||||
filterInput: null,
|
||||
_filterPrevInput: null,
|
||||
_filterChangeTimer: null,
|
||||
_prefsContainer: null,
|
||||
_loadingContainer: null,
|
||||
_list: null,
|
||||
|
||||
// Init the main AboutConfig dialog
|
||||
init: function AC_init() {
|
||||
this.filterInput = document.getElementById("filter-input");
|
||||
this._prefsContainer = document.getElementById("prefs-container");
|
||||
this._loadingContainer = document.getElementById("loading-container");
|
||||
|
||||
let list = Services.prefs.getChildList("", {}).filter(function(aElement) {
|
||||
// Prevent display of "private" preferences
|
||||
return !aElement.startsWith(PRIVATE_PREF_PREFIX);
|
||||
});
|
||||
this._list = list.sort().map( function AC_getMapPref(aPref) {
|
||||
return new Pref(aPref);
|
||||
}, this);
|
||||
|
||||
// Display the current prefs list (retains searchFilter value)
|
||||
this.bufferFilterInput();
|
||||
|
||||
// Setup the prefs observers
|
||||
Services.prefs.addObserver("", this, false);
|
||||
},
|
||||
|
||||
// Uninit the main AboutConfig dialog
|
||||
uninit: function AC_uninit() {
|
||||
// Remove the prefs observer
|
||||
Services.prefs.removeObserver("", this);
|
||||
},
|
||||
|
||||
// Clear the filterInput value, to display the entire list
|
||||
clearFilterInput: function AC_clearFilterInput() {
|
||||
this.filterInput.value = "";
|
||||
this.bufferFilterInput();
|
||||
},
|
||||
|
||||
// Buffer down rapid changes in filterInput value from keyboard
|
||||
bufferFilterInput: function AC_bufferFilterInput() {
|
||||
if (this._filterChangeTimer) {
|
||||
clearTimeout(this._filterChangeTimer);
|
||||
}
|
||||
|
||||
this._filterChangeTimer = setTimeout((function() {
|
||||
this._filterChangeTimer = null;
|
||||
// Display updated prefs list when filterInput value settles
|
||||
this._displayNewList();
|
||||
}).bind(this), FILTER_CHANGE_TRIGGER);
|
||||
},
|
||||
|
||||
// Update displayed list when filterInput value changes
|
||||
_displayNewList: function AC_displayNewList() {
|
||||
// This survives the search filter value past a page refresh
|
||||
this.filterInput.setAttribute("value", this.filterInput.value);
|
||||
|
||||
// Don't start new filter search if same as last
|
||||
if (this.filterInput.value == this._filterPrevInput) {
|
||||
return;
|
||||
}
|
||||
this._filterPrevInput = this.filterInput.value;
|
||||
|
||||
// Clear list item selection and prefs list, get first buffer, set scrolling on
|
||||
this.selected = "";
|
||||
this._clearPrefsContainer();
|
||||
this._addMorePrefsToContainer();
|
||||
window.onscroll = this.onScroll.bind(this);
|
||||
|
||||
// Pause for screen to settle, then ensure at top
|
||||
setTimeout((function() {
|
||||
window.scrollTo(0, 0);
|
||||
}).bind(this), INITIAL_PAGE_DELAY);
|
||||
},
|
||||
|
||||
// Clear the displayed preferences list
|
||||
_clearPrefsContainer: function AC_clearPrefsContainer() {
|
||||
// Quick clear the prefsContainer list
|
||||
let empty = this._prefsContainer.cloneNode(false);
|
||||
this._prefsContainer.parentNode.replaceChild(empty, this._prefsContainer);
|
||||
this._prefsContainer = empty;
|
||||
|
||||
// Quick clear the prefs li.HTML list
|
||||
this._list.forEach(function(item) {
|
||||
delete item.li;
|
||||
});
|
||||
},
|
||||
|
||||
// Get a small manageable block of prefs items, and add them to the displayed list
|
||||
_addMorePrefsToContainer: function AC_addMorePrefsToContainer() {
|
||||
// Create filter regex
|
||||
let filterExp = this.filterInput.value ?
|
||||
new RegExp(this.filterInput.value, "i") : null;
|
||||
|
||||
// Get a new block for the display list
|
||||
let prefsBuffer = [];
|
||||
for (let i = 0; i < this._list.length && prefsBuffer.length < PREFS_BUFFER_MAX; i++) {
|
||||
if (!this._list[i].li && this._list[i].test(filterExp)) {
|
||||
prefsBuffer.push(this._list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new block to the displayed list
|
||||
for (let i = 0; i < prefsBuffer.length; i++) {
|
||||
this._prefsContainer.appendChild(prefsBuffer[i].getOrCreateNewLINode());
|
||||
}
|
||||
|
||||
// Determine if anything left to add later by scrolling
|
||||
let anotherPrefsBufferRemains = false;
|
||||
for (let i = 0; i < this._list.length; i++) {
|
||||
if (!this._list[i].li && this._list[i].test(filterExp)) {
|
||||
anotherPrefsBufferRemains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (anotherPrefsBufferRemains) {
|
||||
// If still more could be displayed, show the throbber
|
||||
this._loadingContainer.style.display = "block";
|
||||
} else {
|
||||
// If no more could be displayed, hide the throbber, and stop noticing scroll events
|
||||
this._loadingContainer.style.display = "none";
|
||||
window.onscroll = null;
|
||||
}
|
||||
},
|
||||
|
||||
// If scrolling at the bottom, maybe add some more entries
|
||||
onScroll: function AC_onScroll(aEvent) {
|
||||
if (this._prefsContainer.scrollHeight - (window.pageYOffset + window.innerHeight) < PAGE_SCROLL_TRIGGER) {
|
||||
if (!this._filterChangeTimer) {
|
||||
this._addMorePrefsToContainer();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Return currently selected list item node
|
||||
get selected() {
|
||||
return document.querySelector(".pref-item.selected");
|
||||
},
|
||||
|
||||
// Set list item node as selected
|
||||
set selected(aSelection) {
|
||||
let currentSelection = this.selected;
|
||||
if (aSelection == currentSelection) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear any previous selection
|
||||
if (currentSelection) {
|
||||
currentSelection.classList.remove("selected");
|
||||
currentSelection.removeEventListener("keypress", this.handleKeypress, false);
|
||||
}
|
||||
|
||||
// Set any current selection
|
||||
if (aSelection) {
|
||||
aSelection.classList.add("selected");
|
||||
aSelection.addEventListener("keypress", this.handleKeypress, false);
|
||||
}
|
||||
},
|
||||
|
||||
// Watch user key input so we can provide Enter key action, commit input values
|
||||
handleKeypress: function AC_handleKeypress(aEvent) {
|
||||
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
|
||||
aEvent.target.blur();
|
||||
},
|
||||
|
||||
// Return the target list item node of an action event
|
||||
getLINodeForEvent: function AC_getLINodeForEvent(aEvent) {
|
||||
let node = aEvent.target;
|
||||
while (node && node.nodeName != "li") {
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
return node;
|
||||
},
|
||||
|
||||
// Return a pref of a list item node
|
||||
_getPrefForNode: function AC_getPrefForNode(aNode) {
|
||||
let pref = aNode.getAttribute("name");
|
||||
|
||||
return new Pref(pref);
|
||||
},
|
||||
|
||||
// When list item name or value are tapped
|
||||
selectOrToggleBoolPref: function AC_selectOrToggleBoolPref(aEvent) {
|
||||
let node = this.getLINodeForEvent(aEvent);
|
||||
|
||||
// If not already selected, just do so
|
||||
if (this.selected != node) {
|
||||
this.selected = node;
|
||||
return;
|
||||
}
|
||||
|
||||
// If already selected, and value is boolean, toggle it
|
||||
let pref = this._getPrefForNode(node);
|
||||
if (pref.type != Services.prefs.PREF_BOOL) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleBoolPref(aEvent);
|
||||
},
|
||||
|
||||
// When finalizing list input values due to blur
|
||||
setIntOrStringPref: function AC_setIntOrStringPref(aEvent) {
|
||||
let node = this.getLINodeForEvent(aEvent);
|
||||
|
||||
// Skip if locked
|
||||
let pref = this._getPrefForNode(node);
|
||||
if (pref.locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Boolean inputs blur to remove focus from "button"
|
||||
if (pref.type == Services.prefs.PREF_BOOL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// String and Int inputs change / commit on blur
|
||||
pref.value = aEvent.target.value;
|
||||
},
|
||||
|
||||
// When we reset a pref to it's default value (note resetting a user created pref will delete it)
|
||||
resetDefaultPref: function AC_resetDefaultPref(aEvent) {
|
||||
let node = this.getLINodeForEvent(aEvent);
|
||||
|
||||
// If not already selected, do so
|
||||
if (this.selected != node) {
|
||||
this.selected = node;
|
||||
}
|
||||
|
||||
// Reset will handle any locked condition
|
||||
let pref = this._getPrefForNode(node);
|
||||
pref.reset();
|
||||
},
|
||||
|
||||
// When we want to toggle a bool pref
|
||||
toggleBoolPref: function AC_toggleBoolPref(aEvent) {
|
||||
let node = this.getLINodeForEvent(aEvent);
|
||||
|
||||
// Skip if locked, or not boolean
|
||||
let pref = this._getPrefForNode(node);
|
||||
if (pref.locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle, and blur to remove field focus
|
||||
pref.value = !pref.value;
|
||||
aEvent.target.blur();
|
||||
},
|
||||
|
||||
// When Int inputs have their Up or Down arrows toggled
|
||||
incrOrDecrIntPref: function AC_incrOrDecrIntPref(aEvent, aInt) {
|
||||
let node = this.getLINodeForEvent(aEvent);
|
||||
|
||||
// Skip if locked
|
||||
let pref = this._getPrefForNode(node);
|
||||
if (pref.locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
pref.value += aInt;
|
||||
},
|
||||
|
||||
// Observe preference changes
|
||||
observe: function AC_observe(aSubject, aTopic, aPrefName) {
|
||||
let pref = new Pref(aPrefName);
|
||||
|
||||
// Ignore uninteresting preference changes, and external changes to "private" preferences
|
||||
if ((aTopic != "nsPref:changed") || pref.name.startsWith(PRIVATE_PREF_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If pref type invalid, refresh display as user reset/removed an item from the list
|
||||
if (pref.type == Services.prefs.PREF_INVALID) {
|
||||
document.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
// If pref not already in list, refresh display as it's being added
|
||||
let item = document.querySelector(".pref-item[name=" + pref.name.quote() + "]");
|
||||
if (!item) {
|
||||
document.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
// Else we're modifying a pref
|
||||
item.setAttribute("value", pref.value);
|
||||
let input = item.querySelector("input");
|
||||
input.setAttribute("value", pref.value);
|
||||
input.value = pref.value;
|
||||
|
||||
pref.default ?
|
||||
item.querySelector(".reset").setAttribute("disabled", "true") :
|
||||
item.querySelector(".reset").removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ============================== Pref ==============================
|
||||
*
|
||||
* Individual Preference object / methods
|
||||
*
|
||||
* Defines a Pref object, a document list item tied to Preferences Services
|
||||
* And the methods by which they interact.
|
||||
*
|
||||
*/
|
||||
function Pref(aName) {
|
||||
this.name = aName;
|
||||
}
|
||||
|
||||
Pref.prototype = {
|
||||
get type() {
|
||||
return Services.prefs.getPrefType(this.name);
|
||||
},
|
||||
|
||||
get value() {
|
||||
switch (this.type) {
|
||||
case Services.prefs.PREF_BOOL:
|
||||
return Services.prefs.getBoolPref(this.name);
|
||||
case Services.prefs.PREF_INT:
|
||||
return Services.prefs.getIntPref(this.name);
|
||||
case Services.prefs.PREF_STRING:
|
||||
default:
|
||||
return Services.prefs.getCharPref(this.name);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
set value(aPrefValue) {
|
||||
switch (this.type) {
|
||||
case Services.prefs.PREF_BOOL:
|
||||
Services.prefs.setBoolPref(this.name, aPrefValue);
|
||||
break;
|
||||
case Services.prefs.PREF_INT:
|
||||
Services.prefs.setIntPref(this.name, aPrefValue);
|
||||
break;
|
||||
case Services.prefs.PREF_STRING:
|
||||
default:
|
||||
Services.prefs.setCharPref(this.name, aPrefValue);
|
||||
}
|
||||
},
|
||||
|
||||
get default() {
|
||||
return !Services.prefs.prefHasUserValue(this.name);
|
||||
},
|
||||
|
||||
get locked() {
|
||||
return Services.prefs.prefIsLocked(this.name);
|
||||
},
|
||||
|
||||
reset: function AC_reset() {
|
||||
Services.prefs.clearUserPref(this.name);
|
||||
},
|
||||
|
||||
test: function AC_test(aValue) {
|
||||
return aValue ? aValue.test(this.name) : true;
|
||||
},
|
||||
|
||||
// Get existing or create new LI node for the pref
|
||||
getOrCreateNewLINode: function AC_getOrCreateNewLINode() {
|
||||
if (!this.li) {
|
||||
this.li = document.createElement("li");
|
||||
|
||||
this.li.className = "pref-item";
|
||||
this.li.setAttribute("name", this.name);
|
||||
|
||||
// Click callback to ensure list item selected even on no-action tap events
|
||||
this.li.addEventListener("click",
|
||||
function(aEvent) {
|
||||
AboutConfig.selected = AboutConfig.getLINodeForEvent(aEvent);
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Create list item outline, bind to object actions
|
||||
this.li.innerHTML =
|
||||
"<div class='pref-name' " +
|
||||
"onclick='AboutConfig.selectOrToggleBoolPref(event);'>" +
|
||||
this.name +
|
||||
"</div>" +
|
||||
"<div class='pref-item-line'>" +
|
||||
"<input class='pref-value' value='' " +
|
||||
"onblur='AboutConfig.setIntOrStringPref(event);' " +
|
||||
"onclick='AboutConfig.selectOrToggleBoolPref(event);'>" +
|
||||
"</input>" +
|
||||
"<div class='pref-button reset' " +
|
||||
"onclick='AboutConfig.resetDefaultPref(event);'>" +
|
||||
gStringBundle.GetStringFromName("pref.resetButton") +
|
||||
"</div>" +
|
||||
"<div class='pref-button toggle' " +
|
||||
"onclick='AboutConfig.toggleBoolPref(event);'>" +
|
||||
gStringBundle.GetStringFromName("pref.toggleButton") +
|
||||
"</div>" +
|
||||
"<div class='pref-button up' " +
|
||||
"onclick='AboutConfig.incrOrDecrIntPref(event, 1);'>" +
|
||||
"</div>" +
|
||||
"<div class='pref-button down' " +
|
||||
"onclick='AboutConfig.incrOrDecrIntPref(event, -1);'>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
// Delay providing the list item values, until the LI is returned and added to the document
|
||||
setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY);
|
||||
}
|
||||
|
||||
return this.li;
|
||||
},
|
||||
|
||||
// Initialize list item object values
|
||||
_valueSetup: function AC_valueSetup() {
|
||||
|
||||
this.li.setAttribute("type", this.type);
|
||||
this.li.setAttribute("value", this.value);
|
||||
|
||||
let valDiv = this.li.querySelector(".pref-value");
|
||||
valDiv.value = this.value;
|
||||
|
||||
switch(this.type) {
|
||||
case Services.prefs.PREF_BOOL:
|
||||
valDiv.setAttribute("type", "button");
|
||||
this.li.querySelector(".up").setAttribute("disabled", true);
|
||||
this.li.querySelector(".down").setAttribute("disabled", true);
|
||||
break;
|
||||
case Services.prefs.PREF_STRING:
|
||||
valDiv.setAttribute("type", "text");
|
||||
this.li.querySelector(".up").setAttribute("disabled", true);
|
||||
this.li.querySelector(".down").setAttribute("disabled", true);
|
||||
this.li.querySelector(".toggle").setAttribute("disabled", true);
|
||||
break;
|
||||
case Services.prefs.PREF_INT:
|
||||
valDiv.setAttribute("type", "number");
|
||||
this.li.querySelector(".toggle").setAttribute("disabled", true);
|
||||
break;
|
||||
}
|
||||
|
||||
this.li.setAttribute("default", this.default);
|
||||
if (this.default) {
|
||||
this.li.querySelector(".reset").setAttribute("disabled", true);
|
||||
}
|
||||
|
||||
if (this.locked) {
|
||||
valDiv.setAttribute("disabled", this.locked);
|
||||
this.li.querySelector(".pref-name").setAttribute("locked", true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.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/. -->
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
<!ENTITY % configDTD SYSTEM "chrome://browser/locale/config.dtd">
|
||||
%configDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width; user-scalable=false" />
|
||||
|
||||
<link rel="stylesheet" href="chrome://browser/skin/config.css" type="text/css"/>
|
||||
<script type="text/javascript;version=1.8" src="chrome://browser/content/pages/config.js"/>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;" onload="NewPrefDialog.init(); AboutConfig.init();"
|
||||
onunload="AboutConfig.uninit();">
|
||||
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-container">
|
||||
<div id="new-pref-toggle-button" onclick="NewPrefDialog.toggleShowHide();"/>
|
||||
|
||||
<div class="toolbar-item" id="filter-container">
|
||||
<div id="filter-search-button"/>
|
||||
<input id="filter-input" type="search" placeholder="&empty.label;" value=""
|
||||
oninput="AboutConfig.bufferFilterInput();"/>
|
||||
<div id="filter-input-clear-button" onclick="AboutConfig.clearFilterInput();"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" ontouchstart="AboutConfig.filterInput.blur();">
|
||||
|
||||
<div id="new-pref-container">
|
||||
<li class="pref-item" id="new-pref-item">
|
||||
<div class="pref-item-line">
|
||||
<input class="pref-name" id="new-pref-name" type="text" placeholder="&addpref.name;"
|
||||
onfocus="NewPrefDialog.focusName(event);"
|
||||
oninput="NewPrefDialog.updateName(event);"/>
|
||||
<select class="pref-value" id="new-pref-type" onchange="NewPrefDialog.type = event.target.value;">
|
||||
<option value="boolean">&boolean.label;</option>
|
||||
<option value="string">&string.label;</option>
|
||||
<option value="int">&integer.label;</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pref-item-line" id="new-pref-line-boolean">
|
||||
<input class="pref-value" id="new-pref-value-boolean" disabled="disabled"/>
|
||||
<div class="pref-button toggle" onclick="NewPrefDialog.toggleBoolValue();">&toggle.label;</div>
|
||||
</div>
|
||||
|
||||
<div class="pref-item-line">
|
||||
<input class="pref-value" id="new-pref-value-string" placeholder="&string.placeholder;"/>
|
||||
<input class="pref-value" id="new-pref-value-int" placeholder="&number.placeholder;" type="number"/>
|
||||
</div>
|
||||
|
||||
<div class="pref-item-line">
|
||||
<div class="pref-button cancel" id="negative-button" onclick="NewPrefDialog.hide();">&cancel.label;</div>
|
||||
<div class="pref-button create" id="positive-button" onclick="NewPrefDialog.create(event);"></div>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div id="prefs-shield"></div>
|
||||
|
||||
<ul id="prefs-container"/>
|
||||
|
||||
<ul id="loading-container"><li></li></ul>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -6,11 +6,12 @@
|
|||
chrome.jar:
|
||||
% content browser %content/
|
||||
|
||||
content/aboutAddons.xhtml (content/pages/aboutAddons.xhtml)
|
||||
content/aboutCertError.xhtml (content/pages/aboutCertError.xhtml)
|
||||
content/aboutRights.xhtml (content/pages/aboutRights.xhtml)
|
||||
content/blockedSite.xhtml (content/pages/blockedSite.xhtml)
|
||||
content/config.xhtml (content/pages/config.xhtml)
|
||||
content/netError.xhtml (content/pages/netError.xhtml)
|
||||
content/aboutAddons.xhtml (content/pages/aboutAddons.xhtml)
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
content/crashprompt.xhtml (content/pages/crashprompt.xhtml)
|
||||
#endif
|
||||
|
@ -64,8 +65,7 @@ chrome.jar:
|
|||
content/ContentAreaObserver.js (content/ContentAreaObserver.js)
|
||||
content/BrowserTouchHandler.js (content/BrowserTouchHandler.js)
|
||||
* content/WebProgress.js (content/WebProgress.js)
|
||||
content/config.xul (content/config.xul)
|
||||
content/config.js (content/config.js)
|
||||
content/pages/config.js (content/pages/config.js)
|
||||
* content/browser.xul (content/browser.xul)
|
||||
content/browser.js (content/browser.js)
|
||||
* content/browser-ui.js (content/browser-ui.js)
|
||||
|
@ -103,6 +103,6 @@ chrome.jar:
|
|||
content/RemoteTabsView.js (content/startui/RemoteTabsView.js)
|
||||
#endif
|
||||
|
||||
% override chrome://global/content/config.xul chrome://browser/content/config.xul
|
||||
% override chrome://global/content/config.xul chrome://browser/content/config.xhtml
|
||||
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
||||
% override chrome://mozapps/content/extensions/extensions.xul chrome://browser/content/aboutAddons.xhtml
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY empty.label "Search">
|
||||
<!ENTITY newpref.label "Add a New Preference">
|
||||
<!ENTITY addpref.name "Name">
|
||||
<!ENTITY addpref.value "Value">
|
||||
|
||||
<!ENTITY cancel.label "Cancel">
|
||||
<!ENTITY reset.label "Reset">
|
||||
<!ENTITY done.label "Done">
|
||||
<!ENTITY toggle.label "Toggle">
|
||||
|
||||
<!ENTITY integer.label "Integer">
|
||||
<!ENTITY string.label "String">
|
||||
<!ENTITY boolean.label "Boolean">
|
||||
|
||||
<!ENTITY string.placeholder "Enter a string">
|
||||
<!ENTITY number.placeholder "Enter a number">
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# 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/.
|
||||
|
||||
newPref.createButton=Create
|
||||
newPref.privateButton=Private
|
||||
newPref.changeButton=Change
|
||||
|
||||
pref.toggleButton=Toggle
|
||||
pref.resetButton=Reset
|
|
@ -12,8 +12,9 @@
|
|||
locale/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd)
|
||||
locale/browser/browser.dtd (%chrome/browser.dtd)
|
||||
locale/browser/browser.properties (%chrome/browser.properties)
|
||||
locale/browser/region.properties (%chrome/region.properties)
|
||||
locale/browser/config.dtd (%chrome/config.dtd)
|
||||
locale/browser/config.properties (%chrome/config.properties)
|
||||
locale/browser/region.properties (%chrome/region.properties)
|
||||
locale/browser/preferences.dtd (%chrome/preferences.dtd)
|
||||
locale/browser/aboutPanel.dtd (%chrome/aboutPanel.dtd)
|
||||
locale/browser/searchPanel.dtd (%chrome/searchPanel.dtd)
|
||||
|
|
|
@ -2,96 +2,344 @@
|
|||
* 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/. */
|
||||
|
||||
@media (max-width: 499px) {
|
||||
#editor-container > hbox {
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #ced7de;
|
||||
-moz-user-select: none;
|
||||
font-family: "Segoe UI", sans-serif;
|
||||
-moz-text-size-adjust: none;
|
||||
}
|
||||
|
||||
richlistitem {
|
||||
-moz-box-align: center;
|
||||
.toolbar {
|
||||
width: 100%;
|
||||
height: 3em;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
box-shadow: 0 0 3px #444;
|
||||
background-color: #ced7de;
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid;
|
||||
-moz-border-bottom-colors: #ff9100 #f27900;
|
||||
}
|
||||
|
||||
richlistitem .preferences-title {
|
||||
pointer-events: none;
|
||||
min-width: 200px;
|
||||
-moz-box-flex: 1;
|
||||
margin-right: 8px;
|
||||
.toolbar-container {
|
||||
max-width: 40em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/* XXX look + sync */
|
||||
richlistitem[default="false"] .preferences-title {
|
||||
font-weight: bold;
|
||||
#filter-container {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
height: 2em;
|
||||
border: 1px solid transparent;
|
||||
border-image-source: url("chrome://browser/skin/images/textfield.png");
|
||||
border-image-slice: 1 1 3 1;
|
||||
border-image-width: 1px 1px 3px 1px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
richlistitem .preferences-value {
|
||||
min-width: 200px;
|
||||
pointer-events: none;
|
||||
-moz-box-flex: 4;
|
||||
text-align: end;
|
||||
color: grey;
|
||||
#filter-input {
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
display: inline-block;
|
||||
width: 12em;
|
||||
min-width: 0;
|
||||
color: #000000;
|
||||
opacity: 1;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
/* Editor */
|
||||
#editor-row {
|
||||
padding: 0;
|
||||
background: #E9E9E9;
|
||||
#filter-input:-moz-placeholder {
|
||||
color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
#editor {
|
||||
border-bottom: 1px solid rgb(207,207,207);
|
||||
.toolbar input {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
min-width: 3em;
|
||||
-moz-box-sizing: border-box;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
#editor > hbox > #editor-name,
|
||||
#editor > hbox > #editor-cancel,
|
||||
#editor > hbox > #editor-done {
|
||||
display: none;
|
||||
#new-pref-toggle-button {
|
||||
background-position: center center;
|
||||
background-image: url("chrome://browser/skin/images/reader-plus-icon-xhdpi.png");
|
||||
background-size: 48px 48px;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
display: inline-block;
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
#editor-container > #editor > hbox > #editor-name,
|
||||
#editor-container > #editor > hbox > #editor-cancel,
|
||||
#editor-container > #editor > hbox > #editor-done {
|
||||
display: -moz-box;
|
||||
#filter-search-button {
|
||||
background-image: url("chrome://browser/skin/images/search.png");
|
||||
background-size: 32px 32px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
display: inline-block;
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
#editor-container > #editor > hbox > #editor-reset {
|
||||
display: none;
|
||||
#filter-input-clear-button {
|
||||
background-image: url("chrome://browser/skin/images/search-clear-30.png");
|
||||
background-size: 32px 32px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
display: inline-block;
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
#editor-container > hbox > label {
|
||||
pointer-events: none;
|
||||
color: black;
|
||||
#filter-input[value=""] + #filter-input-clear-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#editor + richlistitem {
|
||||
display: none;
|
||||
.toolbar-item {
|
||||
display: inline-block;
|
||||
height: 3em;
|
||||
min-width: 3em;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#editor[default="false"] .preferences-title {
|
||||
font-weight: bold;
|
||||
#content {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-top: 3em;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
min-height: 100%;
|
||||
max-width: 40em;
|
||||
}
|
||||
|
||||
#editor-setting setting {
|
||||
border-color: transparent !important;
|
||||
ul {
|
||||
list-style-position: inside;
|
||||
border: 1px solid #808080;
|
||||
background-color: #ffffff;
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
padding-top: 0;
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-shadow: 0 0 5px #000000;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#editor-setting[type="string"] .setting-input {
|
||||
-moz-box-flex: 4;
|
||||
#new-pref-container {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background-color: #ffffff;
|
||||
-moz-box-sizing: border-box;
|
||||
box-shadow: 0 0 5px #000000;
|
||||
overflow-x: hidden;
|
||||
max-width: 40em;
|
||||
max-height: 100%;
|
||||
position: fixed;
|
||||
top: 3em;
|
||||
left: auto;
|
||||
display: none;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#editor-setting[type="string"] .setting-input > textbox {
|
||||
-moz-box-flex: 1;
|
||||
#new-pref-container input,
|
||||
#new-pref-container select {
|
||||
border: none;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* bug 647650: keep 'text-align: right' here instead of using start/end since
|
||||
* the field should looks like ltr as much as possible
|
||||
*/
|
||||
#editor-setting[type="string"] .setting-input > textbox:-moz-locale-dir(rtl) {
|
||||
direction: ltr;
|
||||
text-align: right;
|
||||
#new-pref-container.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#editor-buttons {
|
||||
margin: 2px;
|
||||
li {
|
||||
list-style-type: none;
|
||||
border-bottom: 1px solid #d3d3d3;
|
||||
opacity: 1;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#new-pref-line-boolean,
|
||||
#new-pref-value-string,
|
||||
#new-pref-value-int {
|
||||
display: none;
|
||||
}
|
||||
#new-pref-item[typestyle="boolean"] #new-pref-line-boolean,
|
||||
#new-pref-item[typestyle="string"] #new-pref-value-string,
|
||||
#new-pref-item[typestyle="int"] #new-pref-value-int {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pref-name,
|
||||
.pref-value {
|
||||
padding: 15px 10px;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.pref-value {
|
||||
color: rgba(0,0,0,0.5);
|
||||
flex: 1 1 auto;
|
||||
border: none;
|
||||
-moz-appearance: none;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.pref-name[locked] {
|
||||
padding-right: 20px;
|
||||
background-image: url("chrome://browser/skin/images/lock.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 50%;
|
||||
background-size: auto 60%;
|
||||
}
|
||||
|
||||
#new-pref-name {
|
||||
width: 30em;
|
||||
}
|
||||
|
||||
#new-pref-type {
|
||||
display: inline-block !important;
|
||||
border-left: 1px solid #d3d3d3;
|
||||
width: 10em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.pref-item-line {
|
||||
border-top: 1px solid rgba(0,0,0,0.05);
|
||||
color: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#new-pref-value-boolean {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
/* Disable newPref dialog spinbuttons, use custom version from Android */
|
||||
/* Filed Bug 962359 to enhance the default spinbutton style to be touch-friendly */
|
||||
#new-pref-value-int {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
#new-pref-container .pref-button.toggle {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
flex: 0 1 auto;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#new-pref-container .pref-button.cancel,
|
||||
#new-pref-container .pref-button.create {
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.pref-item-line {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#new-pref-container .pref-item-line,
|
||||
.pref-item.selected .pref-item-line,
|
||||
.pref-item:not(.selected) .pref-button.reset {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#new-pref-container .pref-button.create[disabled] {
|
||||
color: #d3d3d3;
|
||||
}
|
||||
|
||||
.pref-item.selected {
|
||||
background-color: rgba(0,0,255,0.05);
|
||||
}
|
||||
|
||||
.pref-button {
|
||||
display: inline-block;
|
||||
-moz-box-sizing: border-box;
|
||||
text-align: center;
|
||||
padding: 10px 1em;
|
||||
border-left: 1px solid rgba(0,0,0,0.1);
|
||||
opacity: 0;
|
||||
transition-property: opacity;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
.pref-item.selected .pref-item-line .pref-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pref-item:not(.selected) .pref-item-line .pref-button:not(.reset) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pref-item:not(.selected) .pref-button.reset {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Disable detail list item spinbuttons, use custom version from Android */
|
||||
/* Filed Bug 962359 to enhance the default spinbutton style to be touch-friendly */
|
||||
.pref-item input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.pref-button:active {
|
||||
background-color: rgba(0,0,255,0.2);
|
||||
}
|
||||
|
||||
.pref-button[disabled] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pref-button.up {
|
||||
background-image: url("chrome://browser/skin/images/arrowup-16.png");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.pref-button.down {
|
||||
background-image: url("chrome://browser/skin/images/arrowdown-16.png");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#prefs-shield {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
transition-property: opacity;
|
||||
transition-duration: 500ms;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#prefs-shield[shown] {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#loading-container > li {
|
||||
background-image: url(chrome://global/skin/media/throbber.png);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 40px;
|
||||
height: 3em;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 636 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 274 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 476 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 858 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 166 B |
|
@ -150,3 +150,10 @@ chrome.jar:
|
|||
skin/images/arrow-left.png (images/arrow-left.png)
|
||||
skin/images/arrow-left@1.4x.png (images/arrow-left@1.4x.png)
|
||||
skin/images/arrow-left@1.8x.png (images/arrow-left@1.8x.png)
|
||||
|
||||
# AboutConfig specific:
|
||||
skin/images/textfield.png (images/textfield.png)
|
||||
skin/images/reader-plus-icon-xhdpi.png (images/reader-plus-icon-xhdpi.png)
|
||||
skin/images/search.png (images/search.png)
|
||||
skin/images/search-clear-30.png (images/search-clear-30.png)
|
||||
skin/images/lock.png (images/lock.png)
|
||||
|
|
Загрузка…
Ссылка в новой задаче