--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -352,16 +352,24 @@
}
]]>
</handler>
</handlers>
</binding>
<binding id="place-base">
<content/>
+
+ <handlers>
+ <handler event="click" button="0">
+ if (this.control)
+ this.control._fireOpen(event, this);
+ </handler>
+ </handlers>
+
<implementation>
<field name="_uri">null</field>
<field name="_control">null</field>
<field name="_isEditing">false</field>
<field name="_ioService">
Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
@@ -632,27 +640,36 @@
document.getAnonymousElementByAttribute(this, "anonid", "bookmark-manage").hidden = !this._isEditing;
]]>
</body>
</method>
</implementation>
</binding>
<binding id="place-label" extends="chrome://browser/content/bindings.xml#place-base">
+ <handlers>
+ <handler event="click" button="0">
+ <![CDATA[
+ if (this.control)
+ this.control.openFolder(this.previousSibling.itemId);
+ ]]>
+ </handler>
+ </handlers>
+
<content align="center">
<xul:spacer xbl:inherits="width=indent"/>
<xul:image anonid="favicon" class="bookmark-folder-image"/>
<xul:label anonid="name" crop="end" flex="1" xbl:inherits="value=title"/>
</content>
</binding>
<binding id="place-list">
<content orient="vertical" flex="1">
<xul:vbox anonid="parent-items" class="place-list-parents" />
- <xul:richlistbox anonid="child-items" class="place-list-children" flex="1"/>
+ <xul:richlistbox anonid="child-items" class="place-list-children" flex="1" batch="25"/>
</content>
<implementation>
<constructor>
<![CDATA[
this._type = this.getAttribute("type");
this._mode = this.getAttribute("mode");
this._folderParents = {};
@@ -704,22 +721,16 @@
<field name="_parents">
document.getAnonymousElementByAttribute(this, "anonid", "parent-items");
</field>
<field name="_children">
document.getAnonymousElementByAttribute(this, "anonid", "child-items");
</field>
<field name="scrollBoxObject">this._children.scrollBoxObject</field>
- <!-- This won't be updated when the window size changes, but that's OK,
- since we don't need an exact value - we just use it to get an
- approximate scroll position for deciding whether to append additional
- items (see batchSize/_insertItems()).
- -->
- <field name="_childrenHeight">this.scrollBoxObject.height;</field>
<property name="items" readonly="true" onget="return this._children.childNodes"/>
<field name="mobileRoot"><![CDATA[
PlacesUtils.annotations.getItemsWithAnnotation("mobile/bookmarksRoot", {})[0];
]]></field>
<property name="isRootFolder" readonly="true">
@@ -856,24 +867,16 @@
}
}
rootNode.containerOpen = false;
return items;
]]>
</body>
</method>
- <!-- Number of elements to add to the list initially. If there are more
- than this many bookmarks to display, only add them to the list once
- the user has scrolled towards them. This is a performance
- optimization to avoid locking up while attempting to append hundreds
- of bookmarks to our richlistbox.
- -->
- <field name="batchSize">25</field>
-
<method name="openFolder">
<parameter name="aRootFolder"/>
<body>
<![CDATA[
aRootFolder = aRootFolder || this.mobileRoot;
this._activeItem = null;
@@ -894,117 +897,32 @@
let parent = document.createElementNS(XULNS, "placelabel");
parent.setAttribute("class", "bookmark-folder");
parent.setAttribute("itemid", folderId);
parent.setAttribute("indent", 0);
parent.setAttribute("title", title);
parents.insertBefore(parent, parents.firstChild);
- // XXX Fix me - use <handler>?
- parent.addEventListener("click", function(e) { self.openFolder(e.target.previousSibling.itemId); }, false);
-
folderId = this._folderParents[folderId] || PlacesUtils.bookmarks.getFolderIdForItem(folderId);
} while (folderId != PlacesUtils.bookmarks.placesRoot)
let children = this._children;
while (children.firstChild)
children.removeChild(children.firstChild);
children.scrollBoxObject.scrollTo(0, 0);
- this._childItems = (aRootFolder == this._fakeDesktopFolderId) ? this._desktopChildren.concat()
- : this._getChildren(aRootFolder);
+ let items = (aRootFolder == this._fakeDesktopFolderId) ? this._desktopChildren.concat()
+ : this._getChildren(aRootFolder);
if (aRootFolder == this.mobileRoot && !this.isDesktopFolderEmpty())
- this._childItems.unshift(this._desktopFolder);
-
- this._insertItems();
- ]]>
- </body>
- </method>
-
- <method name="close">
- <body>
- <![CDATA[
- // Clear out references to child items, and remove event listener
- // if needed
- this._childItems = null;
- if (this._scrollListenerAdded) {
- this._children.removeEventListener("scroll", this._scrollListener, false);
- this._scrollListenerAdded = false;
- }
- ]]>
- </body>
- </method>
-
- <method name="_insertItems">
- <body>
- <![CDATA[
- let items = this._childItems.splice(0, this.batchSize);
-
- if (!items.length)
- return; // no items to insert
-
- let children = this._children;
- let itemsRemaining = this._childItems.length > 0;
- if (itemsRemaining && !this._scrollListenerAdded) {
- // We're not going to insert all items, so add a scroll listener
- // to know when to add them.
- this._children.addEventListener("scroll", this._scrollListener, false);
- this._scrollListenerAdded = true;
- }
+ items.unshift(this._desktopFolder);
- if (!itemsRemaining && this._scrollListenerAdded) {
- // Can get rid of the scroll listener now that all items are added.
- this._children.removeEventListener("scroll", this._scrollListener, false);
- this._scrollListenerAdded = false;
- }
-
- let fragment = document.createDocumentFragment();
- let count = items.length;
- for (let i=0; i<count; i++)
- fragment.appendChild(this.createItem(items[i]));
- children.appendChild(fragment);
-
- // make sure we recalculate the scrollHeight of the children
- this._childrenScrollHeight = -1;
- ]]>
- </body>
- </method>
-
- <field name="_scrollListener"><![CDATA[
- ({
- self: this,
- handleEvent: function () {
- this.self._checkForInsert();
- }
- })
- ]]></field>
-
- <method name="_checkForInsert">
- <body>
- <![CDATA[
- if (this._childrenScrollHeight == -1) {
- // Need to force a reflow to get the right value here since we may
- // have just added children.
- Browser.forceChromeReflow();
- let scrollheight = {};
- this.scrollBoxObject.getScrolledSize({}, scrollheight);
- this._childrenScrollHeight = scrollheight.value;
- }
-
- let y = {};
- this.scrollBoxObject.getPosition({}, y);
- let scrollRatio = (y.value + this._childrenHeight) / this._childrenScrollHeight;
-
- // If we're scrolled 80% to the bottom of the list, append the next
- // set of items
- if (scrollRatio > 0.8)
- this._insertItems();
+ children.setItems(items.map(this.createItem));
]]>
</body>
</method>
<method name="createItem">
<parameter name="aItem"/>
<body>
<![CDATA[
@@ -1016,20 +934,16 @@
child.setAttribute("title", aItem.title);
child.setAttribute("uri", aItem.uri);
child.setAttribute("tags", aItem.tags);
if (aItem.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER)
child.setAttribute("type", "folder");
else
child.setAttribute("src", aItem.icon);
- // XXX make a <handler>
- let self = this;
- child.addEventListener("click", function(e) { self._fireOpen(e, child); }, false);
-
return child;
]]>
</body>
</method>
<method name="removeItem">
<parameter name="aItem"/>
<body>
@@ -1068,16 +982,79 @@
func.call(this, event);
}
]]>
</body>
</method>
</implementation>
</binding>
+ <binding id="richlistbox-batch" extends="chrome://global/content/bindings/richlistbox.xml#richlistbox">
+ <handlers>
+ <handler event="scroll">
+ <![CDATA[
+ // if there no more items to insert, just return early
+ if (this._items.length == 0)
+ return;
+
+ if (this._contentScrollHeight == -1) {
+ let scrollheight = {};
+ this.scrollBoxObject.getScrolledSize({}, scrollheight);
+ this._contentScrollHeight = scrollheight.value;
+ }
+
+ let y = {};
+ this.scrollBoxObject.getPosition({}, y);
+ let scrollRatio = (y.value + this._childrenHeight) / this._contentScrollHeight;
+
+ // If we're scrolled 80% to the bottom of the list, append the next
+ // set of items
+ if (scrollRatio > 0.8)
+ this._insertItems();
+ ]]>
+ </handler>
+ </handlers>
+ <implementation>
+ <!-- Number of elements to add to the list initially. If there are more
+ than this many elements to display, only add them to the list once
+ the user has scrolled towards them. This is a performance
+ optimization to avoid locking up while attempting to append hundreds
+ of nodes to our richlistbox.
+ -->
+ <property name="batchSize" readonly="true" onget="return this.getAttribute('batch')"/>
+
+ <field name="_childrenHeight">this.scrollBoxObject.height;</field>
+ <field name="_items">[]</field>
+
+ <method name="setItems">
+ <parameter name="aItems"/>
+ <body><![CDATA[
+ this._items = aItems;
+ this._insertItems();
+ ]]></body>
+ </method>
+
+ <method name="_insertItems">
+ <body><![CDATA[
+ let items = this._items.splice(0, this.batchSize);
+ if (!items.length)
+ return; // no items to insert
+
+ let count = items.length;
+ for (let i = 0; i<count; i++)
+ this.appendChild(items[i]);
+
+
+ // make sure we recalculate the scrollHeight of the content
+ this._contentScrollHeight = -1;
+ ]]></body>
+ </method>
+ </implementation>
+ </binding>
+
<binding id="richlistitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<handlers>
<handler event="mousedown" phase="capturing">
<![CDATA[
event.stopPropagation();
]]>
</handler>
</handlers>
--- a/mobile/chrome/content/bindings/setting.xml
+++ b/mobile/chrome/content/bindings/setting.xml
@@ -179,17 +179,17 @@
<xul:box flex="1" class="prefbox">
<xul:vbox flex="1">
<xul:label class="preftitle" xbl:inherits="value=title" crop="end" flex="1"/>
<xul:label class="prefdesc" xbl:inherits="value=desc" crop="end" flex="1">
<children/>
</xul:label>
</xul:vbox>
<xul:hbox anonid="input-container">
- <xul:checkbox anonid="input" xbl:inherits="disabled" oncommand="inputChanged();"/>
+ <xul:checkbox anonid="input" xbl:inherits="disabled,onlabel,offlabel" oncommand="inputChanged();"/>
</xul:hbox>
</xul:box>
</content>
<implementation>
<method name="valueFromPreference">
<body>
<![CDATA[
@@ -332,17 +332,16 @@
</method>
<method name="valueToPreference">
<body>
<![CDATA[
let iss = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
iss.data = this.value;
- Components.reportError(this.value)
this._prefs
.setComplexValue(this.pref, Components.interfaces.nsISupportsString, iss);
]]>
</body>
</method>
<property name="value" onget="return this.input.value;" onset="return this.input.value=val;"/>
</implementation>
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -1044,18 +1044,16 @@ var BookmarkList = {
this._manageButton = document.getElementById("tool-bookmarks-manage");
this._manageButton.disabled = (this._bookmarks.items.length == 0);
},
close: function() {
BrowserUI.updateStar();
- this._bookmarks.close();
-
if (this._bookmarks.manageUI)
this.toggleManage();
this._bookmarks.blur();
this._bookmarks.removeEventListener("BookmarkRemove", this, true);
this._panel.hidden = true;
BrowserUI.popDialog();
},
--- a/mobile/chrome/content/browser.css
+++ b/mobile/chrome/content/browser.css
@@ -93,16 +93,20 @@ menulist {
-moz-binding: url("chrome://browser/content/bindings.xml#menulist");
}
#select-list > option {
-moz-binding: url("chrome://browser/content/bindings.xml#chrome-select-option");
}
/* richlist defaults ------------------------------------------------------- */
+richlistbox[batch] {
+ -moz-binding: url("chrome://browser/content/bindings.xml#richlistbox-batch");
+}
+
richlistitem {
-moz-binding: url("chrome://browser/content/bindings.xml#richlistitem");
}
richlistitem[typeName="local"] {
-moz-binding: url("chrome://browser/content/bindings/extensions.xml#extension-local");
}
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -1350,18 +1350,20 @@ Browser.MainDragger.prototype = {
let elem = this.draggedFrame;
let doffset = new Point(dx, dy);
let render = false;
// First calculate any panning to take sidebars out of view
let panOffset = this._panControlsAwayOffset(doffset);
// do HTML overflow or XUL panning
- if (this.contentScrollbox && !doffset.isZero())
+ if (this.contentScrollbox && !doffset.isZero()) {
this._panScrollbox(this.contentScrollbox, doffset);
+ render = true;
+ }
// Do all iframe panning
if (elem) {
while (elem.frameElement && !doffset.isZero()) {
this._panFrame(elem, doffset);
elem = elem.frameElement;
render = true;
}
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/content/config.js
@@ -0,0 +1,410 @@
+/* ***** 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) 2008
+ * 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 Cc = Components.classes;
+let Ci = Components.interfaces;
+
+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("");
+ },
+
+ 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 nameField = document.getElementById("editor-name");
+ nameField.value = "";
+
+ 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);
+ 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").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.outerHeight - 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;
+ }
+
+ // add 1 because of the new pref row
+ let item = this._container.childNodes[aIndex + 1];
+ 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("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 = 0;
+ while (aValue > 10) {
+ aValue /= 10;
+ count++;
+ }
+
+ return Math.max(1, count * 10);
+ }
+};
+
+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;
+ let prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
+ this._branch = prefService.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");
+ }
+};
+
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/content/config.xul
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+
+<!-- ***** 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) 2008
+ - 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 LGPL or the GPL. 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 ***** -->
+
+<?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.edit(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(Components.interfaces.nsIPrefBranch.PREF_INT)"/>
+ <button label="&boolean.label;" oncommand="ViewConfig.open(Components.interfaces.nsIPrefBranch.PREF_BOOL)"/>
+ <button label="&string.label;" oncommand="ViewConfig.open(Components.interfaces.nsIPrefBranch.PREF_STRING)"/>
+ </hbox>
+ </hbox>
+
+ <vbox id="editor" hidden="true">
+ <hbox align="center">
+ <textbox id="editor-name" flex="1"/>
+ <setting id="editor-setting" 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>
+
--- a/mobile/chrome/jar.mn
+++ b/mobile/chrome/jar.mn
@@ -1,13 +1,15 @@
#filter substitution
chrome.jar:
% content browser %content/
* content/about.xhtml (content/about.xhtml)
+ content/config.xul (content/config.xul)
+ content/config.js (content/config.js)
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
content/aboutCertError.css (content/aboutCertError.css)
content/languages.properties (content/languages.properties)
* content/browser.xul (content/browser.xul)
* content/browser.js (content/browser.js)
* content/browser-ui.js (content/browser-ui.js)
content/commandUtil.js (content/commandUtil.js)
content/bindings.xml (content/bindings.xml)
@@ -38,8 +40,10 @@ chrome.jar:
content/downloads.js (content/downloads.js)
content/console.js (content/console.js)
content/prompt/alert.xul (content/prompt/alert.xul)
content/prompt/confirm.xul (content/prompt/confirm.xul)
content/prompt/prompt.xul (content/prompt/prompt.xul)
content/prompt/promptPassword.xul (content/prompt/promptPassword.xul)
content/prompt/select.xul (content/prompt/select.xul)
content/prompt/prompt.js (content/prompt/prompt.js)
+
+% override chrome://global/content/config.xul chrome://browser/content/config.xul
new file mode 100644
--- /dev/null
+++ b/mobile/locales/en-US/chrome/config.dtd
@@ -0,0 +1,10 @@
+<!ENTITY empty.label "Search">
+<!ENTITY newpref.label "Add a new preference">
+
+<!ENTITY cancel.label "Cancel">
+<!ENTITY reset.label "Reset">
+<!ENTITY done.label "Done">
+
+<!ENTITY integer.label "Integer">
+<!ENTITY string.label "String">
+<!ENTITY boolean.label "Boolean">
--- a/mobile/locales/jar.mn
+++ b/mobile/locales/jar.mn
@@ -1,16 +1,17 @@
#filter substitution
@AB_CD@.jar:
% locale browser @AB_CD@ %locale/@AB_CD@/browser/
locale/@AB_CD@/browser/about.dtd (%chrome/about.dtd)
locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd)
locale/@AB_CD@/browser/browser.dtd (%chrome/browser.dtd)
locale/@AB_CD@/browser/browser.properties (%chrome/browser.properties)
+ locale/@AB_CD@/browser/config.dtd (%chrome/config.dtd)
locale/@AB_CD@/browser/firstrun.dtd (%chrome/firstrun.dtd)
locale/@AB_CD@/browser/region.properties (%chrome/region.properties)
locale/@AB_CD@/browser/preferences.dtd (%chrome/preferences.dtd)
locale/@AB_CD@/browser/checkbox.dtd (%chrome/checkbox.dtd)
locale/@AB_CD@/browser/notification.dtd (%chrome/notification.dtd)
locale/@AB_CD@/browser/prompt.dtd (%chrome/prompt.dtd)
locale/@AB_CD@/browser/bookmarks.json (bookmarks.json)
locale/@AB_CD@/browser/searchplugins/list.txt (%searchplugins/list.txt)
new file mode 100644
--- /dev/null
+++ b/mobile/themes/hildon/config.css
@@ -0,0 +1,108 @@
+/* ***** 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) 2008
+ * 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 ***** */
+
+richlistitem {
+ -moz-box-align: center;
+}
+
+richlistitem .preftitle {
+ min-width: 200px;
+ -moz-box-flex: 1;
+ margin-right: 8px;
+}
+
+/* XXX look + sync */
+richlistitem[default="false"] .preftitle {
+ font-weight: bold;
+}
+
+richlistitem .prefvalue {
+ min-width: 200px;
+ -moz-box-flex: 4;
+ text-align: right;
+ color: grey;
+}
+
+/* Editor */
+#editor-row {
+ padding: 0;
+ background: #E9E9E9;
+}
+
+#editor {
+ border-bottom: 1px solid rgb(207,207,207);
+}
+
+#editor > hbox > #editor-name,
+#editor > hbox > #editor-cancel,
+#editor > hbox > #editor-done {
+ display: none;
+}
+
+#editor-container > #editor > hbox > #editor-name,
+#editor-container > #editor > hbox > #editor-cancel,
+#editor-container > #editor > hbox > #editor-done {
+ display: block;
+}
+
+#editor-container > #editor > hbox > #editor-reset {
+ display: none;
+}
+
+#editor + richlistitem {
+ display: none;
+}
+
+#editor[default="false"] .preftitle {
+ font-weight: bold;
+}
+
+#editor-setting .prefbox {
+ border-color: transparent !important;
+}
+
+#editor-setting[type="string"] [anonid="input-container"] {
+ -moz-box-flex: 4;
+}
+
+#editor-setting[type="string"] [anonid="input-container"] > textbox {
+ -moz-box-flex: 1;
+}
+
+#editor-buttons {
+ margin: 2px;
+}
+
--- a/mobile/themes/hildon/jar.mn
+++ b/mobile/themes/hildon/jar.mn
@@ -1,15 +1,16 @@
#filter substitution
chrome.jar:
% skin browser classic/1.0 %
aboutCertError.css (aboutCertError.css)
aboutPage.css (aboutPage.css)
about.css (about.css)
+ config.css (config.css)
firstRun.css (firstRun.css)
header.css (header.css)
platform.css (platform.css)
browser.css (browser.css)
notification.css (notification.css)
% override chrome://global/skin/about.css chrome://browser/skin/about.css
images/addons.png (images/addons.png)
new file mode 100644
--- /dev/null
+++ b/mobile/themes/wince/config.css
@@ -0,0 +1,108 @@
+/* ***** 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) 2008
+ * 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 ***** */
+
+richlistitem {
+ -moz-box-align: center;
+}
+
+richlistitem .preftitle {
+ min-width: 100px;
+ -moz-box-flex: 1;
+ margin-right: 1.1mm;
+}
+
+/* XXX look + sync */
+richlistitem[default="false"] .preftitle {
+ font-weight: bold;
+}
+
+richlistitem .prefvalue {
+ min-width: 100px;
+ -moz-box-flex: 4;
+ text-align: right;
+ color: grey;
+}
+
+/* Editor */
+#editor-row {
+ padding: 0;
+ background: #E9E9E9;
+}
+
+#editor {
+ border-bottom: 0.05mm solid rgb(207,207,207);
+}
+
+#editor > hbox > #editor-name,
+#editor > hbox > #editor-cancel,
+#editor > hbox > #editor-done {
+ display: none;
+}
+
+#editor-container > #editor > hbox > #editor-name,
+#editor-container > #editor > hbox > #editor-cancel,
+#editor-container > #editor > hbox > #editor-done {
+ display: block;
+}
+
+#editor-container > #editor > hbox > #editor-reset {
+ display: none;
+}
+
+#editor + richlistitem {
+ display: none;
+}
+
+#editor[default="false"] .preftitle {
+ font-weight: bold;
+}
+
+#editor-setting .prefbox {
+ border-bottom: 0 solid transparent !important;
+}
+
+#editor-setting[type="string"] [anonid="input-container"] {
+ -moz-box-flex: 4;
+}
+
+#editor-setting[type="string"] [anonid="input-container"] > textbox {
+ -moz-box-flex: 1;
+}
+
+#editor-buttons {
+ margin: 0.5mm;
+}
+
--- a/mobile/themes/wince/jar.mn
+++ b/mobile/themes/wince/jar.mn
@@ -1,14 +1,15 @@
#filter substitution
chrome.jar:
% skin browser classic/1.0 %
aboutCertError.css (aboutCertError.css)
aboutPage.css (aboutPage.css)
+ config.css (config.css)
firstRun.css (firstRun.css)
header.css (header.css)
platform.css (platform.css)
browser.css (browser.css)
browser-high.css (browser-high.css)
browser-low.css (browser-low.css)
notification.css (notification.css)