2007-03-22 10:30:00 -07:00
|
|
|
<?xml version="1.0"?>
|
|
|
|
|
|
|
|
<!DOCTYPE bindings SYSTEM "chrome://global/locale/preferences.dtd">
|
|
|
|
|
|
|
|
<bindings id="preferencesBindings"
|
|
|
|
xmlns="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xbl="http://www.mozilla.org/xbl"
|
|
|
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
|
|
|
|
|
|
#
|
|
|
|
# = Preferences Window Framework
|
|
|
|
#
|
|
|
|
# The syntax for use looks something like:
|
|
|
|
#
|
|
|
|
# <prefwindow>
|
|
|
|
# <prefpane id="prefPaneA">
|
|
|
|
# <preferences>
|
|
|
|
# <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
|
|
|
|
# <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
|
|
|
|
# </preferences>
|
|
|
|
# <checkbox label="Preference" preference="preference1"/>
|
|
|
|
# </prefpane>
|
|
|
|
# </prefwindow>
|
|
|
|
#
|
|
|
|
|
|
|
|
<binding id="preferences">
|
|
|
|
<implementation implements="nsIObserver">
|
|
|
|
<method name="observe">
|
|
|
|
<parameter name="aSubject"/>
|
|
|
|
<parameter name="aTopic"/>
|
|
|
|
<parameter name="aData"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
for (var i = 0; i < this.childNodes.length; ++i) {
|
|
|
|
var preference = this.childNodes[i];
|
|
|
|
if (preference.name == aData) {
|
|
|
|
preference.value = preference.valueFromPreferences;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="fireChangedEvent">
|
|
|
|
<parameter name="aPreference"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Value changed, synthesize an event
|
|
|
|
try {
|
|
|
|
var event = document.createEvent("Events");
|
|
|
|
event.initEvent("change", true, true);
|
|
|
|
aPreference.dispatchEvent(event);
|
|
|
|
}
|
|
|
|
catch (e) {
|
2007-09-22 12:51:10 -07:00
|
|
|
Components.utils.reportError(e);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<field name="service">
|
|
|
|
Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefService);
|
|
|
|
</field>
|
|
|
|
<field name="rootBranch">
|
|
|
|
Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefBranch);
|
|
|
|
</field>
|
|
|
|
<field name="defaultBranch">
|
|
|
|
this.service.getDefaultBranch("");
|
|
|
|
</field>
|
|
|
|
<field name="rootBranchInternal">
|
|
|
|
Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefBranchInternal);
|
|
|
|
</field>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
<binding id="preference">
|
|
|
|
<implementation>
|
|
|
|
<constructor>
|
|
|
|
<![CDATA[
|
|
|
|
this.preferences.rootBranchInternal
|
|
|
|
.addObserver(this.name, this.preferences, false);
|
|
|
|
// In non-instant apply mode, we must try and use the last saved state
|
|
|
|
// from any previous opens of a child dialog instead of the value from
|
|
|
|
// preferences, to pick up any edits a user may have made.
|
|
|
|
if (document.documentElement.type == "child" &&
|
|
|
|
!this.instantApply && window.opener) {
|
|
|
|
var pdoc = window.opener.document;
|
|
|
|
|
|
|
|
// Try to find a preference element for the same preference.
|
|
|
|
var preference = null;
|
|
|
|
var parentPreferences = pdoc.getElementsByTagName("preferences");
|
|
|
|
for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
|
|
|
|
var parentPrefs = parentPreferences[k]
|
|
|
|
.getElementsByAttribute("name", this.name);
|
|
|
|
for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
|
|
|
|
if (parentPrefs[l].localName == "preference")
|
|
|
|
preference = parentPrefs[l];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._setValue(preference ? preference.value
|
|
|
|
: this.valueFromPreferences, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this._setValue(this.valueFromPreferences, false);
|
|
|
|
]]>
|
|
|
|
</constructor>
|
|
|
|
<destructor>
|
|
|
|
this.preferences.rootBranchInternal
|
|
|
|
.removeObserver(this.name, this.preferences);
|
|
|
|
</destructor>
|
|
|
|
|
|
|
|
<property name="instantApply">
|
|
|
|
<getter>
|
|
|
|
return this.getAttribute("instantApply") == "true" || document.documentElement.instantApply;
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="preferences" onget="return this.parentNode"/>
|
|
|
|
<property name="name" onget="return this.getAttribute('name');">
|
|
|
|
<setter>
|
|
|
|
if (val == this.name)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
this.preferences.rootBranchInternal
|
|
|
|
.removeObserver(this.name, this.preferences);
|
|
|
|
this.setAttribute('name', val);
|
|
|
|
this.preferences.rootBranchInternal
|
|
|
|
.addObserver(val, this.preferences, false);
|
|
|
|
|
|
|
|
return val;
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
<property name="type" onget="return this.getAttribute('type');"
|
|
|
|
onset="this.setAttribute('type', val); return val;"/>
|
|
|
|
<property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
|
|
|
|
onset="this.setAttribute('inverted', val); return val;"/>
|
|
|
|
<property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
|
|
|
|
onset="this.setAttribute('readonly', val); return val;"/>
|
|
|
|
|
|
|
|
<field name="_value">null</field>
|
|
|
|
<method name="_setValue">
|
|
|
|
<parameter name="aValue"/>
|
|
|
|
<parameter name="aUpdate"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (aUpdate && this.value != aValue) {
|
|
|
|
this._value = aValue;
|
|
|
|
if (this.instantApply)
|
|
|
|
this.valueFromPreferences = aValue;
|
|
|
|
this.preferences.fireChangedEvent(this);
|
|
|
|
}
|
|
|
|
else if (!aUpdate) {
|
|
|
|
this._value = aValue;
|
|
|
|
this.updateElements();
|
|
|
|
}
|
|
|
|
return aValue;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
<property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
|
|
|
|
|
|
|
|
<property name="locked">
|
|
|
|
<getter>
|
|
|
|
return this.preferences.rootBranch.prefIsLocked(this.name);
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="disabled">
|
|
|
|
<getter>
|
|
|
|
return this.getAttribute("disabled") == "true";
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (val)
|
|
|
|
this.setAttribute("disabled", "true");
|
|
|
|
else
|
|
|
|
this.removeAttribute("disabled");
|
|
|
|
|
|
|
|
if (!this.id)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
var elements = document.getElementsByAttribute("preference", this.id);
|
|
|
|
for (var i = 0; i < elements.length; ++i) {
|
|
|
|
elements[i].disabled = val;
|
|
|
|
|
|
|
|
var labels = document.getElementsByAttribute("control", elements[i].id);
|
|
|
|
for (var j = 0; j < labels.length; ++j)
|
|
|
|
labels[j].disabled = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="tabIndex">
|
|
|
|
<getter>
|
|
|
|
return parseInt(this.getAttribute("tabindex"));
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (val)
|
|
|
|
this.setAttribute("tabindex", val);
|
|
|
|
else
|
|
|
|
this.removeAttribute("tabindex");
|
|
|
|
|
|
|
|
if (!this.id)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
var elements = document.getElementsByAttribute("preference", this.id);
|
|
|
|
for (var i = 0; i < elements.length; ++i) {
|
|
|
|
elements[i].tabIndex = val;
|
|
|
|
|
|
|
|
var labels = document.getElementsByAttribute("control", elements[i].id);
|
|
|
|
for (var j = 0; j < labels.length; ++j)
|
|
|
|
labels[j].tabIndex = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="hasUserValue">
|
|
|
|
<getter>
|
|
|
|
return this.preferences.rootBranch.prefHasUserValue(this.name);
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="reset">
|
|
|
|
<body>
|
|
|
|
this.preferences.rootBranch.clearUserPref(this.name);
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<field name="_useDefault">false</field>
|
|
|
|
<property name="defaultValue">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
this._useDefault = true;
|
|
|
|
var val = this.valueFromPreferences;
|
|
|
|
this._useDefault = false;
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<property name="_branch">
|
|
|
|
<getter>
|
|
|
|
return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<field name="batching">false</field>
|
|
|
|
|
|
|
|
<method name="_reportUnknownType">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
|
|
|
|
.getService(Components.interfaces.nsIConsoleService);
|
|
|
|
var msg = "<preference> with id='" + this.id + "' and name='" +
|
|
|
|
this.name + "' has unknown type '" + this.type + "'.";
|
|
|
|
consoleService.logStringMessage(msg);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<property name="valueFromPreferences">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
try {
|
|
|
|
// Force a resync of value with preferences.
|
|
|
|
switch (this.type) {
|
|
|
|
case "int":
|
|
|
|
return this._branch.getIntPref(this.name);
|
|
|
|
case "bool":
|
|
|
|
var val = this._branch.getBoolPref(this.name);
|
|
|
|
return this.inverted ? !val : val;
|
|
|
|
case "wstring":
|
|
|
|
return this._branch
|
|
|
|
.getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
|
|
|
|
.data;
|
|
|
|
case "string":
|
|
|
|
case "unichar":
|
|
|
|
return this._branch
|
|
|
|
.getComplexValue(this.name, Components.interfaces.nsISupportsString)
|
|
|
|
.data;
|
|
|
|
case "file":
|
|
|
|
var f = this._branch
|
|
|
|
.getComplexValue(this.name, Components.interfaces.nsILocalFile);
|
|
|
|
return f;
|
|
|
|
default:
|
|
|
|
this._reportUnknownType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) { }
|
|
|
|
return null;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
<setter>
|
|
|
|
<![CDATA[
|
|
|
|
if (this.readonly || this.valueFromPreferences == val)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
// Force a resync of preferences with value.
|
|
|
|
switch (this.type) {
|
|
|
|
case "int":
|
|
|
|
this.preferences.rootBranch.setIntPref(this.name, val);
|
|
|
|
break;
|
|
|
|
case "bool":
|
|
|
|
this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
|
|
|
|
break;
|
|
|
|
case "wstring":
|
|
|
|
var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIPrefLocalizedString);
|
|
|
|
pls.data = val;
|
|
|
|
this.preferences.rootBranch
|
|
|
|
.setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
|
|
|
|
break;
|
|
|
|
case "string":
|
|
|
|
case "unichar":
|
|
|
|
var iss = Components.classes["@mozilla.org/supports-string;1"]
|
|
|
|
.createInstance(Components.interfaces.nsISupportsString);
|
|
|
|
iss.data = val;
|
|
|
|
this.preferences.rootBranch
|
|
|
|
.setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
|
|
|
|
break;
|
|
|
|
case "file":
|
|
|
|
var lf;
|
|
|
|
if (typeof(val) == "string") {
|
|
|
|
lf = Components.classes["@mozilla.org/file/local;1"]
|
|
|
|
.createInstance(Components.interfaces.nsILocalFile);
|
|
|
|
lf.persistentDescriptor = val;
|
|
|
|
if (!lf.exists())
|
|
|
|
lf.initWithPath(val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lf = val.QueryInterface(Components.interfaces.nsILocalFile);
|
|
|
|
this.preferences.rootBranch
|
|
|
|
.setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this._reportUnknownType();
|
|
|
|
}
|
|
|
|
if (!this.batching)
|
|
|
|
this.preferences.service.savePrefFile(null);
|
|
|
|
return val;
|
|
|
|
]]>
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="setElementValue">
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (this.locked)
|
|
|
|
aElement.disabled = true;
|
|
|
|
|
|
|
|
if (!this.isElementEditable(aElement))
|
|
|
|
return;
|
|
|
|
|
|
|
|
var rv = undefined;
|
|
|
|
if (aElement.hasAttribute("onsyncfrompreference")) {
|
|
|
|
// Value changed, synthesize an event
|
|
|
|
try {
|
|
|
|
var event = document.createEvent("Events");
|
|
|
|
event.initEvent("syncfrompreference", true, true);
|
|
|
|
var f = new Function ("event",
|
|
|
|
aElement.getAttribute("onsyncfrompreference"));
|
|
|
|
rv = f(event);
|
|
|
|
}
|
|
|
|
catch (e) {
|
2007-09-22 12:51:10 -07:00
|
|
|
Components.utils.reportError(e);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
var val = rv !== undefined ? rv : (this.instantApply ? this.valueFromPreferences : this.value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize a UI element property with a value. Handles the case
|
|
|
|
* where an element has not yet had a XBL binding attached for it and
|
|
|
|
* the property setter does not yet exist by setting the same attribute
|
|
|
|
* on the XUL element using DOM apis and assuming the element's
|
|
|
|
* constructor or property getters appropriately handle this state.
|
|
|
|
*/
|
|
|
|
function setValue(element, attribute, value) {
|
|
|
|
if (attribute in element)
|
|
|
|
element[attribute] = value;
|
|
|
|
else
|
|
|
|
element.setAttribute(attribute, value);
|
|
|
|
}
|
|
|
|
if (aElement.localName == "checkbox")
|
|
|
|
setValue(aElement, "checked", val);
|
|
|
|
else if (aElement.localName == "colorpicker")
|
|
|
|
setValue(aElement, "color", val);
|
|
|
|
else if (aElement.localName == "textbox") {
|
|
|
|
// XXXmano Bug 303998: Avoid a caret placement issue if either the
|
|
|
|
// preference observer or its setter calls updateElements as a result
|
|
|
|
// of the input event handler.
|
|
|
|
if (aElement.value !== val)
|
|
|
|
setValue(aElement, "value", val);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
setValue(aElement, "value", val);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="getElementValue">
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (aElement.hasAttribute("onsynctopreference")) {
|
|
|
|
// Value changed, synthesize an event
|
|
|
|
try {
|
|
|
|
var event = document.createEvent("Events");
|
|
|
|
event.initEvent("synctopreference", true, true);
|
|
|
|
var f = new Function ("event",
|
|
|
|
aElement.getAttribute("onsynctopreference"));
|
|
|
|
var rv = f(event);
|
|
|
|
if (rv !== undefined)
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
catch (e) {
|
2007-09-22 12:51:10 -07:00
|
|
|
Components.utils.reportError(e);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read the value of an attribute from an element, assuming the
|
|
|
|
* attribute is a property on the element's node API. If the property
|
|
|
|
* is not present in the API, then assume its value is contained in
|
|
|
|
* an attribute, as is the case before a binding has been attached.
|
|
|
|
*/
|
|
|
|
function getValue(element, attribute) {
|
|
|
|
if (attribute in element)
|
|
|
|
return element[attribute];
|
|
|
|
return element.getAttribute(attribute);
|
|
|
|
}
|
|
|
|
if (aElement.localName == "checkbox")
|
|
|
|
var value = getValue(aElement, "checked");
|
|
|
|
else if (aElement.localName == "colorpicker")
|
|
|
|
value = getValue(aElement, "color");
|
|
|
|
else
|
|
|
|
value = getValue(aElement, "value");
|
|
|
|
|
|
|
|
switch (this.type) {
|
|
|
|
case "int":
|
|
|
|
var intValue = parseInt(value, 10) + '';
|
|
|
|
return intValue != "NaN" ? intValue : 0;
|
|
|
|
case "bool":
|
|
|
|
return typeof(value) == "boolean" ? value : value == "true";
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="isElementEditable">
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
switch (aElement.localName) {
|
|
|
|
case "checkbox":
|
|
|
|
case "colorpicker":
|
|
|
|
case "radiogroup":
|
|
|
|
case "textbox":
|
|
|
|
case "listitem":
|
|
|
|
case "listbox":
|
|
|
|
case "menulist":
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return aElement.getAttribute("preference-editable") == "true";
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="updateElements">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (!this.id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// This "change" event handler tracks changes made to preferences by
|
|
|
|
// sources other than the user in this window.
|
|
|
|
var elements = document.getElementsByAttribute("preference", this.id);
|
|
|
|
for (var i = 0; i < elements.length; ++i)
|
|
|
|
this.setElementValue(elements[i]);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
|
|
|
|
<handlers>
|
|
|
|
<handler event="change">
|
|
|
|
this.updateElements();
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
<binding id="prefwindow"
|
|
|
|
extends="chrome://global/content/bindings/dialog.xml#dialog">
|
|
|
|
<resources>
|
|
|
|
<stylesheet src="chrome://global/skin/preferences.css"/>
|
|
|
|
</resources>
|
|
|
|
<content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
|
|
|
|
closebuttonlabel="&preferencesCloseButton.label;"
|
|
|
|
closebuttonaccesskey="&preferencesCloseButton.accesskey;"
|
|
|
|
xmlns:xhtml2="http://www.w3.org/TR/xhtml2"
|
|
|
|
xmlns:wairole="http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#"
|
|
|
|
xhtml2:role="wairole:dialog"
|
|
|
|
#ifdef XP_WIN
|
|
|
|
title="&preferencesDefaultTitleWin.title;">
|
|
|
|
#else
|
|
|
|
title="&preferencesDefaultTitleMac.title;">
|
|
|
|
#endif
|
|
|
|
<xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
|
|
|
|
xhtml2:role="wairole:list"/> <!-- Expose to accessibility APIs as a list -->
|
|
|
|
<xul:hbox flex="1" class="paneDeckContainer">
|
|
|
|
<xul:deck anonid="paneDeck" flex="1">
|
|
|
|
<children includes="prefpane"/>
|
|
|
|
</xul:deck>
|
|
|
|
</xul:hbox>
|
|
|
|
<xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons"
|
|
|
|
#ifdef XP_UNIX
|
|
|
|
>
|
|
|
|
<xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
|
|
<xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
|
|
|
|
<xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
|
|
<xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
|
|
<xul:spacer anonid="spacer" flex="1"/>
|
|
|
|
<xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
|
|
|
|
<xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
|
|
|
|
#else
|
|
|
|
pack="end">
|
|
|
|
<xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
|
|
|
|
<xul:spacer anonid="spacer" flex="1"/>
|
|
|
|
<xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
|
|
|
|
<xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
|
|
|
|
<xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
|
|
|
|
<xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
|
|
|
|
<xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
|
|
|
|
#endif
|
|
|
|
</xul:hbox>
|
|
|
|
<xul:hbox>
|
|
|
|
<children/>
|
|
|
|
</xul:hbox>
|
|
|
|
</content>
|
|
|
|
<implementation implements="nsITimerCallback">
|
|
|
|
<constructor>
|
|
|
|
<![CDATA[
|
|
|
|
if (this.type != "child") {
|
|
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefBranch);
|
|
|
|
this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
|
|
|
|
if (this.instantApply) {
|
|
|
|
var docElt = document.documentElement;
|
|
|
|
var acceptButton = docElt.getButton("accept");
|
|
|
|
acceptButton.hidden = true;
|
|
|
|
var cancelButton = docElt.getButton("cancel");
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// no buttons on Mac except Help
|
|
|
|
cancelButton.hidden = true;
|
|
|
|
// Also, don't fire onDialogAccept on enter
|
|
|
|
acceptButton.disabled = true;
|
|
|
|
#else
|
|
|
|
// morph the Cancel button into the Close button
|
|
|
|
cancelButton.setAttribute ("icon", "close");
|
|
|
|
cancelButton.label = docElt.getAttribute("closebuttonlabel");
|
|
|
|
cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2007-09-21 16:12:21 -07:00
|
|
|
this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
|
2007-03-22 10:30:00 -07:00
|
|
|
var panes = this.preferencePanes;
|
|
|
|
|
|
|
|
var lastPane = null;
|
|
|
|
if (this.lastSelected) {
|
|
|
|
lastPane = document.getElementById(this.lastSelected);
|
|
|
|
if (!lastPane) {
|
|
|
|
this.lastSelected = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var paneToLoad;
|
|
|
|
if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
|
|
|
|
paneToLoad = document.getElementById(window.arguments[0]);
|
|
|
|
this.lastSelected = paneToLoad.id;
|
|
|
|
}
|
|
|
|
else if (lastPane)
|
|
|
|
paneToLoad = lastPane;
|
|
|
|
else
|
|
|
|
paneToLoad = panes[0];
|
|
|
|
|
|
|
|
for (var i = 0; i < panes.length; ++i) {
|
|
|
|
this._makePaneButton(panes[i]);
|
|
|
|
if (panes[i].loaded) {
|
|
|
|
// Inline pane content, fire load event to force initialization.
|
|
|
|
this._fireEvent("paneload", panes[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.showPane(paneToLoad);
|
|
|
|
|
|
|
|
if (panes.length == 1)
|
|
|
|
this._selector.setAttribute("collapsed", "true");
|
|
|
|
]]>
|
|
|
|
</constructor>
|
|
|
|
|
|
|
|
<destructor>
|
|
|
|
<![CDATA[
|
|
|
|
// Release timers to avoid reference cycles.
|
|
|
|
if (this._animateTimer) {
|
|
|
|
this._animateTimer.cancel();
|
|
|
|
this._animateTimer = null;
|
|
|
|
}
|
|
|
|
if (this._fadeTimer) {
|
|
|
|
this._fadeTimer.cancel();
|
|
|
|
this._fadeTimer = null;
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</destructor>
|
|
|
|
|
|
|
|
<field name="instantApply">false</field>
|
|
|
|
|
|
|
|
<property name="preferencePanes"
|
|
|
|
onget="return this.getElementsByTagName('prefpane');"/>
|
|
|
|
|
|
|
|
<property name="type" onget="return this.getAttribute('type');"/>
|
|
|
|
<property name="_paneDeck"
|
|
|
|
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
|
2007-09-02 15:05:53 -07:00
|
|
|
<property name="_paneDeckContainer"
|
|
|
|
onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
|
2007-03-22 10:30:00 -07:00
|
|
|
<property name="_selector"
|
|
|
|
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
|
|
|
|
<property name="lastSelected"
|
|
|
|
onget="return this.getAttribute('lastSelected');">
|
|
|
|
<setter>
|
|
|
|
this.setAttribute("lastSelected", val);
|
|
|
|
document.persist(this.id, "lastSelected");
|
|
|
|
return val;
|
|
|
|
</setter>
|
|
|
|
</property>
|
|
|
|
<field name="currentPane">null</field>
|
|
|
|
|
|
|
|
<method name="_makePaneButton">
|
|
|
|
<parameter name="aPaneElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var radio = document.createElement("radio");
|
|
|
|
radio.setAttribute("pane", aPaneElement.id);
|
|
|
|
radio.setAttribute("label", aPaneElement.label);
|
|
|
|
// Expose preference group choice to accessibility APIs as an unchecked list item
|
|
|
|
// The parent group is exposed to accessibility APIs as a list
|
|
|
|
if (aPaneElement.image)
|
|
|
|
radio.setAttribute("src", aPaneElement.image);
|
|
|
|
radio.style.listStyleImage = aPaneElement.style.listStyleImage;
|
|
|
|
this._selector.appendChild(radio);
|
|
|
|
return radio;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="showPane">
|
|
|
|
<parameter name="aPaneElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
2007-09-24 14:05:29 -07:00
|
|
|
if (!aPaneElement)
|
|
|
|
return;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
|
|
|
|
if (!aPaneElement.loaded) {
|
|
|
|
function OverlayLoadObserver(aPane)
|
|
|
|
{
|
|
|
|
this._pane = aPane;
|
|
|
|
}
|
|
|
|
OverlayLoadObserver.prototype = {
|
|
|
|
_outer: this,
|
|
|
|
observe: function (aSubject, aTopic, aData)
|
|
|
|
{
|
|
|
|
this._pane.loaded = true;
|
|
|
|
this._outer._fireEvent("paneload", this._pane);
|
|
|
|
this._outer._selectPane(this._pane);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var obs = new OverlayLoadObserver(aPaneElement);
|
|
|
|
document.loadOverlay(aPaneElement.src, obs);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this._selectPane(aPaneElement);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_fireEvent">
|
|
|
|
<parameter name="aEventName"/>
|
|
|
|
<parameter name="aTarget"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Panel loaded, synthesize a load event.
|
|
|
|
try {
|
|
|
|
var event = document.createEvent("Events");
|
|
|
|
event.initEvent(aEventName, true, true);
|
|
|
|
var cancel = !aTarget.dispatchEvent(event);
|
|
|
|
if (aTarget.hasAttribute("on" + aEventName)) {
|
|
|
|
var fn = new Function ("event", aTarget.getAttribute("on" + aEventName));
|
|
|
|
var rv = fn.call(aTarget, event);
|
|
|
|
if (rv == false)
|
|
|
|
cancel = true;
|
|
|
|
}
|
|
|
|
return !cancel;
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Components.utils.reportError(e);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<field name="_initialized">false</field>
|
|
|
|
<method name="_selectPane">
|
|
|
|
<parameter name="aPaneElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
var paneTitle = aPaneElement.label;
|
|
|
|
if (paneTitle != "")
|
|
|
|
document.title = paneTitle;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Find this pane's index in the deck and set the deck's
|
|
|
|
// selectedIndex to that value to switch to it.
|
|
|
|
var prefpanes = this.preferencePanes;
|
|
|
|
for (var i = 0; i < prefpanes.length; ++i) {
|
|
|
|
if (prefpanes[i] == aPaneElement) {
|
2007-07-25 06:41:36 -07:00
|
|
|
this._paneDeck.selectedIndex = i;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (this.type != "child") {
|
2007-09-21 16:12:21 -07:00
|
|
|
if (aPaneElement.hasAttribute("flex") && this._shouldAnimate &&
|
|
|
|
prefpanes.length > 1)
|
|
|
|
aPaneElement.removeAttribute("flex");
|
2007-09-17 12:18:17 -07:00
|
|
|
// Calling sizeToContent after the first prefpane is loaded
|
|
|
|
// will size the windows contents so style information is
|
|
|
|
// available to calculate correct sizing.
|
2007-09-18 19:45:58 -07:00
|
|
|
if (!this._initialized && prefpanes.length > 1) {
|
|
|
|
if (this._shouldAnimate)
|
|
|
|
this.style.minHeight = 0;
|
2007-09-17 12:18:17 -07:00
|
|
|
window.sizeToContent();
|
2007-09-18 19:45:58 -07:00
|
|
|
}
|
2007-09-17 12:18:17 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
var oldPane = this.lastSelected ? document.getElementById(this.lastSelected) : this.preferencePanes[0];
|
|
|
|
oldPane.selected = !(aPaneElement.selected = true);
|
|
|
|
this.lastSelected = aPaneElement.id;
|
|
|
|
this.currentPane = aPaneElement;
|
2007-09-17 12:18:17 -07:00
|
|
|
this._initialized = true;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Only animate if we've switched between prefpanes
|
|
|
|
if (this._shouldAnimate && oldPane.id != aPaneElement.id) {
|
|
|
|
aPaneElement.style.opacity = 0.0;
|
|
|
|
this.animate(oldPane, aPaneElement);
|
|
|
|
}
|
2007-09-18 19:45:58 -07:00
|
|
|
else if (!this._shouldAnimate && prefpanes.length > 1) {
|
2007-09-02 15:05:53 -07:00
|
|
|
var targetHeight = parseInt(window.getComputedStyle(this._paneDeckContainer, "").height);
|
2007-09-17 12:18:17 -07:00
|
|
|
var verticalPadding = parseInt(window.getComputedStyle(aPaneElement, "").paddingTop);
|
|
|
|
verticalPadding += parseInt(window.getComputedStyle(aPaneElement, "").paddingBottom);
|
|
|
|
if (aPaneElement.contentHeight > targetHeight - verticalPadding) {
|
2007-09-02 15:05:53 -07:00
|
|
|
// To workaround the bottom border of a groupbox from being
|
|
|
|
// cutoff an hbox with a class of bottomBox may enclose it.
|
|
|
|
// This needs to include its padding to resize properly.
|
|
|
|
// See bug 394433
|
|
|
|
var bottomPadding = 0;
|
|
|
|
var bottomBox = aPaneElement.getElementsByAttribute("class", "bottomBox")[0];
|
|
|
|
if (bottomBox)
|
|
|
|
bottomPadding = parseInt(window.getComputedStyle(bottomBox, "").paddingBottom);
|
2007-09-17 12:18:17 -07:00
|
|
|
window.innerHeight += bottomPadding + verticalPadding + aPaneElement.contentHeight - targetHeight;
|
2007-09-02 15:05:53 -07:00
|
|
|
}
|
2007-09-17 12:18:17 -07:00
|
|
|
|
|
|
|
// XXX rstrong - extend the contents of the prefpane to
|
|
|
|
// prevent elements from being cutoff (see bug 349098).
|
|
|
|
if (aPaneElement.contentHeight + verticalPadding < targetHeight)
|
|
|
|
aPaneElement._content.style.height = targetHeight - verticalPadding + "px";
|
2007-09-02 15:05:53 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var helpButton = document.documentElement.getButton("help");
|
|
|
|
if (aPaneElement.hasAttribute("helpURI"))
|
|
|
|
helpButton.hidden = false;
|
|
|
|
else
|
|
|
|
helpButton.hidden = true;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<property name="_shouldAnimate">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefBranch);
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
var animate = true;
|
|
|
|
#else
|
|
|
|
var animate = false;
|
|
|
|
#endif
|
|
|
|
try {
|
|
|
|
animate = psvc.getBoolPref("browser.preferences.animateFadeIn");
|
|
|
|
}
|
|
|
|
catch (e) { }
|
|
|
|
return animate;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="animate">
|
|
|
|
<parameter name="aOldPane"/>
|
|
|
|
<parameter name="aNewPane"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// if we are already resizing, use currentHeight
|
|
|
|
var oldHeight = this._currentHeight ? this._currentHeight : aOldPane.contentHeight;
|
|
|
|
|
|
|
|
this._multiplier = aNewPane.contentHeight > oldHeight ? 1 : -1;
|
|
|
|
var sizeDelta = Math.abs(oldHeight - aNewPane.contentHeight);
|
|
|
|
this._animateRemainder = sizeDelta % this._animateIncrement;
|
|
|
|
|
|
|
|
this._setUpAnimationTimer(oldHeight);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<property name="_sizeIncrement">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
var lastSelectedPane = document.getElementById(this.lastSelected);
|
|
|
|
var increment = this._animateIncrement * this._multiplier;
|
|
|
|
var newHeight = this._currentHeight + increment;
|
|
|
|
if ((this._multiplier > 0 && this._currentHeight >= lastSelectedPane.contentHeight) ||
|
|
|
|
(this._multiplier < 0 && this._currentHeight <= lastSelectedPane.contentHeight))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((this._multiplier > 0 && newHeight > lastSelectedPane.contentHeight) ||
|
|
|
|
(this._multiplier < 0 && newHeight < lastSelectedPane.contentHeight))
|
|
|
|
increment = this._animateRemainder * this._multiplier;
|
|
|
|
return increment;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<method name="notify">
|
|
|
|
<parameter name="aTimer"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (!document)
|
|
|
|
aTimer.cancel();
|
|
|
|
|
|
|
|
if (aTimer == this._animateTimer) {
|
|
|
|
var increment = this._sizeIncrement;
|
|
|
|
if (increment != 0) {
|
|
|
|
window.innerHeight += increment;
|
|
|
|
this._currentHeight += increment;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aTimer.cancel();
|
|
|
|
this._setUpFadeTimer();
|
|
|
|
}
|
|
|
|
} else if (aTimer == this._fadeTimer) {
|
|
|
|
var elt = document.getElementById(this.lastSelected);
|
|
|
|
var newOpacity = parseFloat(window.getComputedStyle(elt, "").opacity) + this._fadeIncrement;
|
|
|
|
if (newOpacity < 1.0)
|
|
|
|
elt.style.opacity = newOpacity;
|
|
|
|
else {
|
|
|
|
aTimer.cancel();
|
|
|
|
elt.style.opacity = 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_setUpAnimationTimer">
|
|
|
|
<parameter name="aStartHeight"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (!this._animateTimer)
|
|
|
|
this._animateTimer = Components.classes["@mozilla.org/timer;1"]
|
|
|
|
.createInstance(Components.interfaces.nsITimer);
|
|
|
|
else
|
|
|
|
this._animateTimer.cancel();
|
|
|
|
this._currentHeight = aStartHeight;
|
|
|
|
|
|
|
|
this._animateTimer.initWithCallback(this, this._animateDelay,
|
|
|
|
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="_setUpFadeTimer">
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
if (!this._fadeTimer)
|
|
|
|
this._fadeTimer = Components.classes["@mozilla.org/timer;1"]
|
|
|
|
.createInstance(Components.interfaces.nsITimer);
|
|
|
|
else
|
|
|
|
this._fadeTimer.cancel();
|
|
|
|
|
|
|
|
this._fadeTimer.initWithCallback(this, this._fadeDelay,
|
|
|
|
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<field name="_animateTimer">null</field>
|
|
|
|
<field name="_fadeTimer">null</field>
|
|
|
|
<field name="_animateDelay">15</field>
|
|
|
|
<field name="_animateIncrement">40</field>
|
|
|
|
<field name="_fadeDelay">5</field>
|
|
|
|
<field name="_fadeIncrement">0.40</field>
|
|
|
|
<field name="_animateRemainder">0</field>
|
|
|
|
<field name="_currentHeight">0</field>
|
|
|
|
<field name="_multiplier">0</field>
|
|
|
|
|
|
|
|
<method name="addPane">
|
|
|
|
<parameter name="aPaneElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
this.appendChild(aPaneElement);
|
|
|
|
|
|
|
|
// Set up pane button
|
|
|
|
this._makePaneButton(aPaneElement);
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="openSubDialog">
|
|
|
|
<parameter name="aURL"/>
|
|
|
|
<parameter name="aFeatures"/>
|
|
|
|
<parameter name="aParams"/>
|
|
|
|
<body>
|
|
|
|
return openDialog(aURL, "", "modal,centerscreen,resizable=no" + (aFeatures != "" ? ("," + aFeatures) : ""), aParams);
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="openWindow">
|
|
|
|
<parameter name="aWindowType"/>
|
|
|
|
<parameter name="aURL"/>
|
|
|
|
<parameter name="aFeatures"/>
|
|
|
|
<parameter name="aParams"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
|
|
|
.getService(Components.interfaces.nsIWindowMediator);
|
|
|
|
var win = aWindowType ? wm.getMostRecentWindow(aWindowType) : null;
|
|
|
|
if (win) {
|
|
|
|
if ("initWithParams" in win)
|
|
|
|
win.initWithParams(aParams);
|
|
|
|
win.focus();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var features = "resizable,dialog=no,centerscreen" + (aFeatures != "" ? ("," + aFeatures) : "");
|
|
|
|
var parentWindow = (this.instantApply || !window.opener || window.opener.closed) ? window : window.opener;
|
|
|
|
win = parentWindow.openDialog(aURL, "_blank", features, aParams);
|
|
|
|
}
|
|
|
|
return win;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
// copied from contextHelp.js
|
|
|
|
// Locate existing help window for this helpFileURI.
|
|
|
|
<method name="locateHelpWindow">
|
|
|
|
<parameter name="helpFileURI"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
const wm = Components.classes['@mozilla.org/appshell/window-mediator;1']
|
|
|
|
.getService(Components.interfaces.nsIWindowMediator);
|
|
|
|
const iterator = wm.getEnumerator("mozilla:help");
|
|
|
|
var topWindow = null;
|
|
|
|
var aWindow;
|
|
|
|
|
|
|
|
// Loop through help windows looking for one with selected helpFileURI
|
|
|
|
while (iterator.hasMoreElements()) {
|
|
|
|
aWindow = iterator.getNext();
|
|
|
|
if (aWindow.getHelpFileURI() == helpFileURI)
|
|
|
|
topWindow = aWindow;
|
|
|
|
}
|
|
|
|
return topWindow;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
// copied from contextHelp.js
|
|
|
|
// Opens up the Help Viewer with the specified topic and helpFileURI.
|
|
|
|
<method name="openHelp">
|
|
|
|
<parameter name="topic"/>
|
|
|
|
<parameter name="helpFileURI"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Try to find previously opened help.
|
|
|
|
var topWindow = this.locateHelpWindow(helpFileURI);
|
|
|
|
|
|
|
|
if (topWindow) {
|
|
|
|
// Open topic in existing window.
|
|
|
|
topWindow.focus();
|
|
|
|
topWindow.displayTopic(topic);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Open topic in new window.
|
|
|
|
const params = Components.classes["@mozilla.org/embedcomp/dialogparam;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIDialogParamBlock);
|
|
|
|
params.SetNumberStrings(2);
|
|
|
|
params.SetString(0, helpFileURI);
|
|
|
|
params.SetString(1, topic);
|
|
|
|
const ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
|
|
|
.getService(Components.interfaces.nsIWindowWatcher);
|
|
|
|
ww.openWindow(null, "chrome://help/content/help.xul", "_blank", "chrome,all,alwaysRaised,dialog=no", params);
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
|
|
<handler event="dialoghelp">
|
|
|
|
// currentPane is set in _selectPane for prefwindows which aren't childs.
|
|
|
|
// So if there's no currentPane, just use the first pane.
|
|
|
|
var pane = this.currentPane ? this.currentPane : this.preferencePanes[0];
|
|
|
|
this.openHelp(pane.helpTopic, pane.getAttribute("helpURI"));
|
|
|
|
</handler>
|
|
|
|
<handler event="dialogaccept">
|
|
|
|
<![CDATA[
|
|
|
|
if (!this._fireEvent("beforeaccept", this))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this.type == "child" && window.opener) {
|
|
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefBranch);
|
|
|
|
var instantApply = psvc.getBoolPref("browser.preferences.instantApply");
|
|
|
|
if (instantApply) {
|
|
|
|
var panes = this.preferencePanes;
|
|
|
|
for (var i = 0; i < panes.length; ++i)
|
|
|
|
panes[i].writePreferences(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Clone all the preferences elements from the child document and
|
|
|
|
// insert them into the pane collection of the parent.
|
|
|
|
var pdoc = window.opener.document;
|
|
|
|
if (pdoc.documentElement.localName == "prefwindow") {
|
|
|
|
var currentPane = pdoc.documentElement.currentPane;
|
|
|
|
var id = window.location.href + "#childprefs";
|
|
|
|
var childPrefs = pdoc.getElementById(id);
|
|
|
|
if (!childPrefs) {
|
|
|
|
var childPrefs = pdoc.createElement("preferences");
|
|
|
|
currentPane.appendChild(childPrefs);
|
|
|
|
childPrefs.id = id;
|
|
|
|
}
|
|
|
|
var panes = this.preferencePanes;
|
|
|
|
for (var i = 0; i < panes.length; ++i) {
|
|
|
|
var preferences = panes[i].preferences;
|
|
|
|
for (var j = 0; j < preferences.length; ++j) {
|
|
|
|
// Try to find a preference element for the same preference.
|
|
|
|
var preference = null;
|
|
|
|
var parentPreferences = pdoc.getElementsByTagName("preferences");
|
|
|
|
for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
|
|
|
|
var parentPrefs = parentPreferences[k]
|
|
|
|
.getElementsByAttribute("name", preferences[j].name);
|
|
|
|
for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
|
|
|
|
if (parentPrefs[l].localName == "preference")
|
|
|
|
preference = parentPrefs[l];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!preference) {
|
|
|
|
// No matching preference in the parent window.
|
|
|
|
preference = pdoc.createElement("preference");
|
|
|
|
childPrefs.appendChild(preference);
|
|
|
|
preference.name = preferences[j].name;
|
|
|
|
preference.type = preferences[j].type;
|
|
|
|
preference.inverted = preferences[j].inverted;
|
|
|
|
preference.readonly = preferences[j].readonly;
|
|
|
|
preference.disabled = preferences[j].disabled;
|
|
|
|
}
|
|
|
|
preference.value = preferences[j].value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var panes = this.preferencePanes;
|
|
|
|
for (var i = 0; i < panes.length; ++i)
|
|
|
|
panes[i].writePreferences(false);
|
|
|
|
|
|
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefService);
|
|
|
|
psvc.savePrefFile(null);
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
<handler event="command">
|
|
|
|
if (event.originalTarget.hasAttribute("pane")) {
|
|
|
|
var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
|
|
|
|
event.originalTarget.parentNode.parentNode.showPane(pane);
|
|
|
|
}
|
|
|
|
</handler>
|
|
|
|
|
|
|
|
<handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
|
|
|
|
if (this.instantApply)
|
|
|
|
window.close();
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
<binding id="prefpane">
|
|
|
|
<resources>
|
|
|
|
<stylesheet src="chrome://global/skin/preferences.css"/>
|
|
|
|
</resources>
|
|
|
|
<content>
|
|
|
|
<xul:vbox class="content-box" xbl:inherits="flex">
|
|
|
|
<children/>
|
|
|
|
</xul:vbox>
|
|
|
|
</content>
|
|
|
|
<implementation>
|
|
|
|
<method name="writePreferences">
|
|
|
|
<parameter name="aFlushToDisk"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
// Write all values to preferences.
|
|
|
|
var preferences = this.preferences;
|
|
|
|
for (var i = 0; i < preferences.length; ++i) {
|
|
|
|
var preference = preferences[i];
|
|
|
|
preference.batching = true;
|
|
|
|
preference.valueFromPreferences = preference.value;
|
|
|
|
preference.batching = false;
|
|
|
|
}
|
|
|
|
if (aFlushToDisk) {
|
|
|
|
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIPrefService);
|
|
|
|
psvc.savePrefFile(null);
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<property name="src"
|
|
|
|
onget="return this.getAttribute('src');"
|
|
|
|
onset="this.setAttribute('src', val); return val;"/>
|
|
|
|
<property name="selected"
|
|
|
|
onget="return this.getAttribute('selected') == 'true';"
|
|
|
|
onset="this.setAttribute('selected', val); return val;"/>
|
|
|
|
<property name="image"
|
|
|
|
onget="return this.getAttribute('image');"
|
|
|
|
onset="this.setAttribute('image', val); return val;"/>
|
|
|
|
<property name="label"
|
|
|
|
onget="return this.getAttribute('label');"
|
|
|
|
onset="this.setAttribute('label', val); return val;"/>
|
|
|
|
|
|
|
|
<property name="preferenceElements"
|
|
|
|
onget="return this.getElementsByAttribute('preference', '*');"/>
|
|
|
|
<property name="preferences"
|
|
|
|
onget="return this.getElementsByTagName('preference');"/>
|
|
|
|
|
|
|
|
<property name="helpTopic">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
// if there are tabs, and the selected tab provides a helpTopic, return that
|
|
|
|
var box = this.getElementsByTagName("tabbox");
|
|
|
|
if (box[0]) {
|
|
|
|
var tab = box[0].selectedTab;
|
|
|
|
if (tab && tab.hasAttribute("helpTopic"))
|
|
|
|
return tab.getAttribute("helpTopic");
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, return the helpTopic of the current panel
|
|
|
|
return this.getAttribute("helpTopic");
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
|
|
|
|
<field name="_loaded">false</field>
|
|
|
|
<property name="loaded"
|
|
|
|
onget="return !this.src ? true : this._loaded;"
|
|
|
|
onset="this._loaded = val; return val;"/>
|
|
|
|
|
|
|
|
<method name="preferenceForElement">
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body>
|
|
|
|
return document.getElementById(aElement.getAttribute("preference"));
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="getPreferenceElement">
|
|
|
|
<parameter name="aStartElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var temp = aStartElement;
|
|
|
|
while (temp && temp.nodeType == Node.ELEMENT_NODE &&
|
|
|
|
!temp.hasAttribute("preference"))
|
|
|
|
temp = temp.parentNode;
|
|
|
|
return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<method name="userChangedValue">
|
|
|
|
<parameter name="aElement"/>
|
|
|
|
<body>
|
|
|
|
<![CDATA[
|
|
|
|
var element = this.getPreferenceElement(aElement);
|
|
|
|
if (element.hasAttribute("preference")) {
|
|
|
|
var preference = document.getElementById(element.getAttribute("preference"));
|
|
|
|
var prefVal = preference.getElementValue(element);
|
|
|
|
preference.value = prefVal;
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</body>
|
|
|
|
</method>
|
|
|
|
|
|
|
|
<property name="contentHeight">
|
|
|
|
<getter>
|
|
|
|
var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
|
|
|
|
targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
|
|
|
|
targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
|
|
|
|
return targetHeight;
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
<field name="_content">
|
|
|
|
document.getAnonymousElementByAttribute(this, "class", "content-box");
|
|
|
|
</field>
|
|
|
|
</implementation>
|
|
|
|
<handlers>
|
|
|
|
<handler event="command">
|
|
|
|
// This "command" event handler tracks changes made to preferences by
|
|
|
|
// the user in this window.
|
|
|
|
this.userChangedValue(event.target);
|
|
|
|
</handler>
|
|
|
|
<handler event="select">
|
|
|
|
// This "select" event handler tracks changes made to colorpicker
|
|
|
|
// preferences by the user in this window.
|
|
|
|
if (event.target.localName == "colorpicker")
|
|
|
|
this.userChangedValue(event.target);
|
|
|
|
</handler>
|
|
|
|
<handler event="change">
|
|
|
|
// This "change" event handler tracks changes made to preferences by
|
|
|
|
// the user in this window.
|
|
|
|
this.userChangedValue(event.target);
|
|
|
|
</handler>
|
|
|
|
<handler event="input">
|
|
|
|
// This "input" event handler tracks changes made to preferences by
|
|
|
|
// the user in this window.
|
|
|
|
this.userChangedValue(event.target);
|
|
|
|
</handler>
|
|
|
|
<handler event="paneload">
|
|
|
|
<![CDATA[
|
|
|
|
// Initialize all values from preferences.
|
|
|
|
var elements = this.preferenceElements;
|
|
|
|
for (var i = 0; i < elements.length; ++i) {
|
|
|
|
try {
|
|
|
|
var preference = this.preferenceForElement(elements[i]);
|
|
|
|
preference.setElementValue(elements[i]);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]]>
|
|
|
|
</handler>
|
|
|
|
</handlers>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
<binding id="panebutton" extends="chrome://global/content/bindings/radio.xml#radio">
|
|
|
|
<resources>
|
|
|
|
<stylesheet src="chrome://global/skin/preferences.css"/>
|
|
|
|
</resources>
|
|
|
|
<content>
|
|
|
|
<xul:image class="paneButtonIcon" xbl:inherits="src"/>
|
|
|
|
<xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
|
|
|
|
</content>
|
|
|
|
<implementation implements="nsIAccessible">
|
|
|
|
<property name="accessibleType" readonly="true">
|
|
|
|
<getter>
|
|
|
|
<![CDATA[
|
|
|
|
return Components.interfaces.nsIAccessibleProvider.XULListitem;
|
|
|
|
]]>
|
|
|
|
</getter>
|
|
|
|
</property>
|
|
|
|
</implementation>
|
|
|
|
</binding>
|
|
|
|
|
|
|
|
</bindings>
|
|
|
|
|
|
|
|
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
# ***** 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 the Preferences System.
|
|
|
|
#
|
|
|
|
# The Initial Developer of the Original Code is
|
|
|
|
# Ben Goodger.
|
|
|
|
# Portions created by the Initial Developer are Copyright (C) 2005
|
|
|
|
# the Initial Developer. All Rights Reserved.
|
|
|
|
#
|
|
|
|
# Contributor(s):
|
|
|
|
# Ben Goodger <ben@mozilla.org>
|
|
|
|
# Josh Aas <josh@mozilla.com>
|
|
|
|
#
|
|
|
|
# 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 *****
|
|
|
|
|
|
|
|
#
|
|
|
|
# This is PrefWindow 6. The Code Could Well Be Ready, Are You?
|
|
|
|
#
|
|
|
|
# Historical References:
|
|
|
|
# PrefWindow V (February 1, 2003)
|
|
|
|
# PrefWindow IV (April 24, 2000)
|
|
|
|
# PrefWindow III (January 6, 2000)
|
|
|
|
# PrefWindow II (???)
|
|
|
|
# PrefWindow I (June 4, 1999)
|
|
|
|
#
|