зеркало из https://github.com/mozilla/gecko-dev.git
392 строки
11 KiB
JavaScript
392 строки
11 KiB
JavaScript
/* 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 _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() {
|
|
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() {
|
|
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");
|
|
row.setAttribute("hidden", aValue != "");
|
|
|
|
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;
|
|
}
|
|
},
|
|
|
|
_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);
|
|
},
|
|
|
|
_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");
|
|
}
|
|
};
|
|
|