mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-07 05:15:09 +00:00
7a41cf6cbc
--HG-- rename : mobile/chrome/content/bindings/setting.xml => toolkit/mozapps/extensions/content/setting.xml
422 lines
13 KiB
JavaScript
422 lines
13 KiB
JavaScript
/* ***** 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) 2010
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* 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 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");
|
|
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));
|
|
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).QueryInterface(Ci.nsIPrefBranch2);
|
|
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");
|
|
}
|
|
};
|
|
|