/* ***** 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, 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", "preftitle"); label.setAttribute("value", aPref.name); label.setAttribute("crop", "end"); row.appendChild(label); label = document.createElement("label"); label.setAttribute("class", "prefvalue"); 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"); } };