toolkit/content/widgets/preferences.xml

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 <?xml version="1.0"?>
michael@0 2
michael@0 3 <!DOCTYPE bindings [
michael@0 4 <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
michael@0 5 %preferencesDTD;
michael@0 6 <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
michael@0 7 %globalKeysDTD;
michael@0 8 ]>
michael@0 9
michael@0 10 <bindings id="preferencesBindings"
michael@0 11 xmlns="http://www.mozilla.org/xbl"
michael@0 12 xmlns:xbl="http://www.mozilla.org/xbl"
michael@0 13 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
michael@0 14
michael@0 15 #
michael@0 16 # = Preferences Window Framework
michael@0 17 #
michael@0 18 # The syntax for use looks something like:
michael@0 19 #
michael@0 20 # <prefwindow>
michael@0 21 # <prefpane id="prefPaneA">
michael@0 22 # <preferences>
michael@0 23 # <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
michael@0 24 # <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
michael@0 25 # </preferences>
michael@0 26 # <checkbox label="Preference" preference="preference1"/>
michael@0 27 # </prefpane>
michael@0 28 # </prefwindow>
michael@0 29 #
michael@0 30
michael@0 31 <binding id="preferences">
michael@0 32 <implementation implements="nsIObserver">
michael@0 33 <method name="observe">
michael@0 34 <parameter name="aSubject"/>
michael@0 35 <parameter name="aTopic"/>
michael@0 36 <parameter name="aData"/>
michael@0 37 <body>
michael@0 38 <![CDATA[
michael@0 39 for (var i = 0; i < this.childNodes.length; ++i) {
michael@0 40 var preference = this.childNodes[i];
michael@0 41 if (preference.name == aData) {
michael@0 42 preference.value = preference.valueFromPreferences;
michael@0 43 }
michael@0 44 }
michael@0 45 ]]>
michael@0 46 </body>
michael@0 47 </method>
michael@0 48
michael@0 49 <method name="fireChangedEvent">
michael@0 50 <parameter name="aPreference"/>
michael@0 51 <body>
michael@0 52 <![CDATA[
michael@0 53 // Value changed, synthesize an event
michael@0 54 try {
michael@0 55 var event = document.createEvent("Events");
michael@0 56 event.initEvent("change", true, true);
michael@0 57 aPreference.dispatchEvent(event);
michael@0 58 }
michael@0 59 catch (e) {
michael@0 60 Components.utils.reportError(e);
michael@0 61 }
michael@0 62 ]]>
michael@0 63 </body>
michael@0 64 </method>
michael@0 65
michael@0 66 <field name="service">
michael@0 67 Components.classes["@mozilla.org/preferences-service;1"]
michael@0 68 .getService(Components.interfaces.nsIPrefService);
michael@0 69 </field>
michael@0 70 <field name="rootBranch">
michael@0 71 Components.classes["@mozilla.org/preferences-service;1"]
michael@0 72 .getService(Components.interfaces.nsIPrefBranch);
michael@0 73 </field>
michael@0 74 <field name="defaultBranch">
michael@0 75 this.service.getDefaultBranch("");
michael@0 76 </field>
michael@0 77 <field name="rootBranchInternal">
michael@0 78 Components.classes["@mozilla.org/preferences-service;1"]
michael@0 79 .getService(Components.interfaces.nsIPrefBranchInternal);
michael@0 80 </field>
michael@0 81 <property name="type" readonly="true">
michael@0 82 <getter>
michael@0 83 <![CDATA[
michael@0 84 return document.documentElement.type || "";
michael@0 85 ]]>
michael@0 86 </getter>
michael@0 87 </property>
michael@0 88 <property name="instantApply" readonly="true">
michael@0 89 <getter>
michael@0 90 <![CDATA[
michael@0 91 var doc = document.documentElement;
michael@0 92 return this.type == "child" ? doc.instantApply
michael@0 93 : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
michael@0 94 ]]>
michael@0 95 </getter>
michael@0 96 </property>
michael@0 97 </implementation>
michael@0 98 </binding>
michael@0 99
michael@0 100 <binding id="preference">
michael@0 101 <implementation>
michael@0 102 <constructor>
michael@0 103 <![CDATA[
michael@0 104 // if the element has been inserted without the name attribute set,
michael@0 105 // we have nothing to do here
michael@0 106 if (!this.name)
michael@0 107 return;
michael@0 108
michael@0 109 this.preferences.rootBranchInternal
michael@0 110 .addObserver(this.name, this.preferences, false);
michael@0 111 // In non-instant apply mode, we must try and use the last saved state
michael@0 112 // from any previous opens of a child dialog instead of the value from
michael@0 113 // preferences, to pick up any edits a user may have made.
michael@0 114 if (this.preferences.type == "child" &&
michael@0 115 !this.instantApply && window.opener) {
michael@0 116 var pdoc = window.opener.document;
michael@0 117
michael@0 118 // Try to find a preference element for the same preference.
michael@0 119 var preference = null;
michael@0 120 var parentPreferences = pdoc.getElementsByTagName("preferences");
michael@0 121 for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
michael@0 122 var parentPrefs = parentPreferences[k]
michael@0 123 .getElementsByAttribute("name", this.name);
michael@0 124 for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
michael@0 125 if (parentPrefs[l].localName == "preference")
michael@0 126 preference = parentPrefs[l];
michael@0 127 }
michael@0 128 }
michael@0 129 this._setValue(preference ? preference.value
michael@0 130 : this.valueFromPreferences, false);
michael@0 131 }
michael@0 132 else
michael@0 133 this._setValue(this.valueFromPreferences, false);
michael@0 134 ]]>
michael@0 135 </constructor>
michael@0 136 <destructor>
michael@0 137 this.preferences.rootBranchInternal
michael@0 138 .removeObserver(this.name, this.preferences);
michael@0 139 </destructor>
michael@0 140
michael@0 141 <property name="instantApply">
michael@0 142 <getter>
michael@0 143 return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
michael@0 144 </getter>
michael@0 145 </property>
michael@0 146
michael@0 147 <property name="preferences" onget="return this.parentNode"/>
michael@0 148 <property name="name" onget="return this.getAttribute('name');">
michael@0 149 <setter>
michael@0 150 if (val == this.name)
michael@0 151 return val;
michael@0 152
michael@0 153 this.preferences.rootBranchInternal
michael@0 154 .removeObserver(this.name, this.preferences);
michael@0 155 this.setAttribute('name', val);
michael@0 156 this.preferences.rootBranchInternal
michael@0 157 .addObserver(val, this.preferences, false);
michael@0 158
michael@0 159 return val;
michael@0 160 </setter>
michael@0 161 </property>
michael@0 162 <property name="type" onget="return this.getAttribute('type');"
michael@0 163 onset="this.setAttribute('type', val); return val;"/>
michael@0 164 <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
michael@0 165 onset="this.setAttribute('inverted', val); return val;"/>
michael@0 166 <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
michael@0 167 onset="this.setAttribute('readonly', val); return val;"/>
michael@0 168
michael@0 169 <field name="_value">null</field>
michael@0 170 <method name="_setValue">
michael@0 171 <parameter name="aValue"/>
michael@0 172 <parameter name="aUpdate"/>
michael@0 173 <body>
michael@0 174 <![CDATA[
michael@0 175 if (aUpdate && this.value !== aValue) {
michael@0 176 this._value = aValue;
michael@0 177 if (this.instantApply)
michael@0 178 this.valueFromPreferences = aValue;
michael@0 179 this.preferences.fireChangedEvent(this);
michael@0 180 }
michael@0 181 else if (!aUpdate) {
michael@0 182 this._value = aValue;
michael@0 183 this.updateElements();
michael@0 184 }
michael@0 185 return aValue;
michael@0 186 ]]>
michael@0 187 </body>
michael@0 188 </method>
michael@0 189 <property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
michael@0 190
michael@0 191 <property name="locked">
michael@0 192 <getter>
michael@0 193 return this.preferences.rootBranch.prefIsLocked(this.name);
michael@0 194 </getter>
michael@0 195 </property>
michael@0 196
michael@0 197 <property name="disabled">
michael@0 198 <getter>
michael@0 199 return this.getAttribute("disabled") == "true";
michael@0 200 </getter>
michael@0 201 <setter>
michael@0 202 <![CDATA[
michael@0 203 if (val)
michael@0 204 this.setAttribute("disabled", "true");
michael@0 205 else
michael@0 206 this.removeAttribute("disabled");
michael@0 207
michael@0 208 if (!this.id)
michael@0 209 return val;
michael@0 210
michael@0 211 var elements = document.getElementsByAttribute("preference", this.id);
michael@0 212 for (var i = 0; i < elements.length; ++i) {
michael@0 213 elements[i].disabled = val;
michael@0 214
michael@0 215 var labels = document.getElementsByAttribute("control", elements[i].id);
michael@0 216 for (var j = 0; j < labels.length; ++j)
michael@0 217 labels[j].disabled = val;
michael@0 218 }
michael@0 219
michael@0 220 return val;
michael@0 221 ]]>
michael@0 222 </setter>
michael@0 223 </property>
michael@0 224
michael@0 225 <property name="tabIndex">
michael@0 226 <getter>
michael@0 227 return parseInt(this.getAttribute("tabindex"));
michael@0 228 </getter>
michael@0 229 <setter>
michael@0 230 <![CDATA[
michael@0 231 if (val)
michael@0 232 this.setAttribute("tabindex", val);
michael@0 233 else
michael@0 234 this.removeAttribute("tabindex");
michael@0 235
michael@0 236 if (!this.id)
michael@0 237 return val;
michael@0 238
michael@0 239 var elements = document.getElementsByAttribute("preference", this.id);
michael@0 240 for (var i = 0; i < elements.length; ++i) {
michael@0 241 elements[i].tabIndex = val;
michael@0 242
michael@0 243 var labels = document.getElementsByAttribute("control", elements[i].id);
michael@0 244 for (var j = 0; j < labels.length; ++j)
michael@0 245 labels[j].tabIndex = val;
michael@0 246 }
michael@0 247
michael@0 248 return val;
michael@0 249 ]]>
michael@0 250 </setter>
michael@0 251 </property>
michael@0 252
michael@0 253 <property name="hasUserValue">
michael@0 254 <getter>
michael@0 255 <![CDATA[
michael@0 256 return this.preferences.rootBranch.prefHasUserValue(this.name) &&
michael@0 257 this.value !== undefined;
michael@0 258 ]]>
michael@0 259 </getter>
michael@0 260 </property>
michael@0 261
michael@0 262 <method name="reset">
michael@0 263 <body>
michael@0 264 // defer reset until preference update
michael@0 265 this.value = undefined;
michael@0 266 </body>
michael@0 267 </method>
michael@0 268
michael@0 269 <field name="_useDefault">false</field>
michael@0 270 <property name="defaultValue">
michael@0 271 <getter>
michael@0 272 <![CDATA[
michael@0 273 this._useDefault = true;
michael@0 274 var val = this.valueFromPreferences;
michael@0 275 this._useDefault = false;
michael@0 276 return val;
michael@0 277 ]]>
michael@0 278 </getter>
michael@0 279 </property>
michael@0 280
michael@0 281 <property name="_branch">
michael@0 282 <getter>
michael@0 283 return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
michael@0 284 </getter>
michael@0 285 </property>
michael@0 286
michael@0 287 <field name="batching">false</field>
michael@0 288
michael@0 289 <method name="_reportUnknownType">
michael@0 290 <body>
michael@0 291 <![CDATA[
michael@0 292 var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
michael@0 293 .getService(Components.interfaces.nsIConsoleService);
michael@0 294 var msg = "<preference> with id='" + this.id + "' and name='" +
michael@0 295 this.name + "' has unknown type '" + this.type + "'.";
michael@0 296 consoleService.logStringMessage(msg);
michael@0 297 ]]>
michael@0 298 </body>
michael@0 299 </method>
michael@0 300
michael@0 301 <property name="valueFromPreferences">
michael@0 302 <getter>
michael@0 303 <![CDATA[
michael@0 304 try {
michael@0 305 // Force a resync of value with preferences.
michael@0 306 switch (this.type) {
michael@0 307 case "int":
michael@0 308 return this._branch.getIntPref(this.name);
michael@0 309 case "bool":
michael@0 310 var val = this._branch.getBoolPref(this.name);
michael@0 311 return this.inverted ? !val : val;
michael@0 312 case "wstring":
michael@0 313 return this._branch
michael@0 314 .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
michael@0 315 .data;
michael@0 316 case "string":
michael@0 317 case "unichar":
michael@0 318 return this._branch
michael@0 319 .getComplexValue(this.name, Components.interfaces.nsISupportsString)
michael@0 320 .data;
michael@0 321 case "fontname":
michael@0 322 var family = this._branch
michael@0 323 .getComplexValue(this.name, Components.interfaces.nsISupportsString)
michael@0 324 .data;
michael@0 325 var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
michael@0 326 .createInstance(Components.interfaces.nsIFontEnumerator);
michael@0 327 return fontEnumerator.getStandardFamilyName(family);
michael@0 328 case "file":
michael@0 329 var f = this._branch
michael@0 330 .getComplexValue(this.name, Components.interfaces.nsILocalFile);
michael@0 331 return f;
michael@0 332 default:
michael@0 333 this._reportUnknownType();
michael@0 334 }
michael@0 335 }
michael@0 336 catch (e) { }
michael@0 337 return null;
michael@0 338 ]]>
michael@0 339 </getter>
michael@0 340 <setter>
michael@0 341 <![CDATA[
michael@0 342 // Exit early if nothing to do.
michael@0 343 if (this.readonly || this.valueFromPreferences == val)
michael@0 344 return val;
michael@0 345
michael@0 346 // The special value undefined means 'reset preference to default'.
michael@0 347 if (val === undefined) {
michael@0 348 this.preferences.rootBranch.clearUserPref(this.name);
michael@0 349 return val;
michael@0 350 }
michael@0 351
michael@0 352 // Force a resync of preferences with value.
michael@0 353 switch (this.type) {
michael@0 354 case "int":
michael@0 355 this.preferences.rootBranch.setIntPref(this.name, val);
michael@0 356 break;
michael@0 357 case "bool":
michael@0 358 this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
michael@0 359 break;
michael@0 360 case "wstring":
michael@0 361 var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
michael@0 362 .createInstance(Components.interfaces.nsIPrefLocalizedString);
michael@0 363 pls.data = val;
michael@0 364 this.preferences.rootBranch
michael@0 365 .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
michael@0 366 break;
michael@0 367 case "string":
michael@0 368 case "unichar":
michael@0 369 case "fontname":
michael@0 370 var iss = Components.classes["@mozilla.org/supports-string;1"]
michael@0 371 .createInstance(Components.interfaces.nsISupportsString);
michael@0 372 iss.data = val;
michael@0 373 this.preferences.rootBranch
michael@0 374 .setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
michael@0 375 break;
michael@0 376 case "file":
michael@0 377 var lf;
michael@0 378 if (typeof(val) == "string") {
michael@0 379 lf = Components.classes["@mozilla.org/file/local;1"]
michael@0 380 .createInstance(Components.interfaces.nsILocalFile);
michael@0 381 lf.persistentDescriptor = val;
michael@0 382 if (!lf.exists())
michael@0 383 lf.initWithPath(val);
michael@0 384 }
michael@0 385 else
michael@0 386 lf = val.QueryInterface(Components.interfaces.nsILocalFile);
michael@0 387 this.preferences.rootBranch
michael@0 388 .setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
michael@0 389 break;
michael@0 390 default:
michael@0 391 this._reportUnknownType();
michael@0 392 }
michael@0 393 if (!this.batching)
michael@0 394 this.preferences.service.savePrefFile(null);
michael@0 395 return val;
michael@0 396 ]]>
michael@0 397 </setter>
michael@0 398 </property>
michael@0 399
michael@0 400 <method name="setElementValue">
michael@0 401 <parameter name="aElement"/>
michael@0 402 <body>
michael@0 403 <![CDATA[
michael@0 404 if (this.locked)
michael@0 405 aElement.disabled = true;
michael@0 406
michael@0 407 if (!this.isElementEditable(aElement))
michael@0 408 return;
michael@0 409
michael@0 410 var rv = undefined;
michael@0 411 if (aElement.hasAttribute("onsyncfrompreference")) {
michael@0 412 // Value changed, synthesize an event
michael@0 413 try {
michael@0 414 var event = document.createEvent("Events");
michael@0 415 event.initEvent("syncfrompreference", true, true);
michael@0 416 var f = new Function ("event",
michael@0 417 aElement.getAttribute("onsyncfrompreference"));
michael@0 418 rv = f.call(aElement, event);
michael@0 419 }
michael@0 420 catch (e) {
michael@0 421 Components.utils.reportError(e);
michael@0 422 }
michael@0 423 }
michael@0 424 var val = rv !== undefined ? rv : (this.instantApply ? this.valueFromPreferences : this.value);
michael@0 425 // if the preference is marked for reset, show default value in UI
michael@0 426 if (val === undefined)
michael@0 427 val = this.defaultValue;
michael@0 428
michael@0 429 /**
michael@0 430 * Initialize a UI element property with a value. Handles the case
michael@0 431 * where an element has not yet had a XBL binding attached for it and
michael@0 432 * the property setter does not yet exist by setting the same attribute
michael@0 433 * on the XUL element using DOM apis and assuming the element's
michael@0 434 * constructor or property getters appropriately handle this state.
michael@0 435 */
michael@0 436 function setValue(element, attribute, value) {
michael@0 437 if (attribute in element)
michael@0 438 element[attribute] = value;
michael@0 439 else
michael@0 440 element.setAttribute(attribute, value);
michael@0 441 }
michael@0 442 if (aElement.localName == "checkbox" ||
michael@0 443 aElement.localName == "listitem")
michael@0 444 setValue(aElement, "checked", val);
michael@0 445 else if (aElement.localName == "colorpicker")
michael@0 446 setValue(aElement, "color", val);
michael@0 447 else if (aElement.localName == "textbox") {
michael@0 448 // XXXmano Bug 303998: Avoid a caret placement issue if either the
michael@0 449 // preference observer or its setter calls updateElements as a result
michael@0 450 // of the input event handler.
michael@0 451 if (aElement.value !== val)
michael@0 452 setValue(aElement, "value", val);
michael@0 453 }
michael@0 454 else
michael@0 455 setValue(aElement, "value", val);
michael@0 456 ]]>
michael@0 457 </body>
michael@0 458 </method>
michael@0 459
michael@0 460 <method name="getElementValue">
michael@0 461 <parameter name="aElement"/>
michael@0 462 <body>
michael@0 463 <![CDATA[
michael@0 464 if (aElement.hasAttribute("onsynctopreference")) {
michael@0 465 // Value changed, synthesize an event
michael@0 466 try {
michael@0 467 var event = document.createEvent("Events");
michael@0 468 event.initEvent("synctopreference", true, true);
michael@0 469 var f = new Function ("event",
michael@0 470 aElement.getAttribute("onsynctopreference"));
michael@0 471 var rv = f.call(aElement, event);
michael@0 472 if (rv !== undefined)
michael@0 473 return rv;
michael@0 474 }
michael@0 475 catch (e) {
michael@0 476 Components.utils.reportError(e);
michael@0 477 }
michael@0 478 }
michael@0 479
michael@0 480 /**
michael@0 481 * Read the value of an attribute from an element, assuming the
michael@0 482 * attribute is a property on the element's node API. If the property
michael@0 483 * is not present in the API, then assume its value is contained in
michael@0 484 * an attribute, as is the case before a binding has been attached.
michael@0 485 */
michael@0 486 function getValue(element, attribute) {
michael@0 487 if (attribute in element)
michael@0 488 return element[attribute];
michael@0 489 return element.getAttribute(attribute);
michael@0 490 }
michael@0 491 if (aElement.localName == "checkbox" ||
michael@0 492 aElement.localName == "listitem")
michael@0 493 var value = getValue(aElement, "checked");
michael@0 494 else if (aElement.localName == "colorpicker")
michael@0 495 value = getValue(aElement, "color");
michael@0 496 else
michael@0 497 value = getValue(aElement, "value");
michael@0 498
michael@0 499 switch (this.type) {
michael@0 500 case "int":
michael@0 501 return parseInt(value, 10) || 0;
michael@0 502 case "bool":
michael@0 503 return typeof(value) == "boolean" ? value : value == "true";
michael@0 504 }
michael@0 505 return value;
michael@0 506 ]]>
michael@0 507 </body>
michael@0 508 </method>
michael@0 509
michael@0 510 <method name="isElementEditable">
michael@0 511 <parameter name="aElement"/>
michael@0 512 <body>
michael@0 513 <![CDATA[
michael@0 514 switch (aElement.localName) {
michael@0 515 case "checkbox":
michael@0 516 case "colorpicker":
michael@0 517 case "radiogroup":
michael@0 518 case "textbox":
michael@0 519 case "listitem":
michael@0 520 case "listbox":
michael@0 521 case "menulist":
michael@0 522 return true;
michael@0 523 }
michael@0 524 return aElement.getAttribute("preference-editable") == "true";
michael@0 525 ]]>
michael@0 526 </body>
michael@0 527 </method>
michael@0 528
michael@0 529 <method name="updateElements">
michael@0 530 <body>
michael@0 531 <![CDATA[
michael@0 532 if (!this.id)
michael@0 533 return;
michael@0 534
michael@0 535 // This "change" event handler tracks changes made to preferences by
michael@0 536 // sources other than the user in this window.
michael@0 537 var elements = document.getElementsByAttribute("preference", this.id);
michael@0 538 for (var i = 0; i < elements.length; ++i)
michael@0 539 this.setElementValue(elements[i]);
michael@0 540 ]]>
michael@0 541 </body>
michael@0 542 </method>
michael@0 543 </implementation>
michael@0 544
michael@0 545 <handlers>
michael@0 546 <handler event="change">
michael@0 547 this.updateElements();
michael@0 548 </handler>
michael@0 549 </handlers>
michael@0 550 </binding>
michael@0 551
michael@0 552 <binding id="prefwindow"
michael@0 553 extends="chrome://global/content/bindings/dialog.xml#dialog">
michael@0 554 <resources>
michael@0 555 <stylesheet src="chrome://global/skin/preferences.css"/>
michael@0 556 </resources>
michael@0 557 <content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
michael@0 558 closebuttonlabel="&preferencesCloseButton.label;"
michael@0 559 closebuttonaccesskey="&preferencesCloseButton.accesskey;"
michael@0 560 role="dialog"
michael@0 561 #ifdef XP_WIN
michael@0 562 title="&preferencesDefaultTitleWin.title;">
michael@0 563 #else
michael@0 564 title="&preferencesDefaultTitleMac.title;">
michael@0 565 #endif
michael@0 566 <xul:windowdragbox orient="vertical">
michael@0 567 <xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
michael@0 568 role="listbox"/> <!-- Expose to accessibility APIs as a listbox -->
michael@0 569 </xul:windowdragbox>
michael@0 570 <xul:hbox flex="1" class="paneDeckContainer">
michael@0 571 <xul:deck anonid="paneDeck" flex="1">
michael@0 572 <children includes="prefpane"/>
michael@0 573 </xul:deck>
michael@0 574 </xul:hbox>
michael@0 575 <xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons" pack="end">
michael@0 576 #ifdef XP_UNIX
michael@0 577 <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
michael@0 578 <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
michael@0 579 <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
michael@0 580 <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
michael@0 581 <xul:spacer anonid="spacer" flex="1"/>
michael@0 582 <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
michael@0 583 <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
michael@0 584 #else
michael@0 585 <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
michael@0 586 <xul:spacer anonid="spacer" flex="1"/>
michael@0 587 <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
michael@0 588 <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
michael@0 589 <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
michael@0 590 <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
michael@0 591 <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
michael@0 592 #endif
michael@0 593 </xul:hbox>
michael@0 594 <xul:hbox>
michael@0 595 <children/>
michael@0 596 </xul:hbox>
michael@0 597 </content>
michael@0 598 <implementation implements="nsITimerCallback">
michael@0 599 <constructor>
michael@0 600 <![CDATA[
michael@0 601 if (this.type != "child") {
michael@0 602 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
michael@0 603 .getService(Components.interfaces.nsIPrefBranch);
michael@0 604 this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
michael@0 605 if (this.instantApply) {
michael@0 606 var docElt = document.documentElement;
michael@0 607 var acceptButton = docElt.getButton("accept");
michael@0 608 acceptButton.hidden = true;
michael@0 609 var cancelButton = docElt.getButton("cancel");
michael@0 610 #ifdef XP_MACOSX
michael@0 611 // no buttons on Mac except Help
michael@0 612 cancelButton.hidden = true;
michael@0 613 // Move Help button to the end
michael@0 614 document.getAnonymousElementByAttribute(this, "anonid", "spacer").hidden = true;
michael@0 615 // Also, don't fire onDialogAccept on enter
michael@0 616 acceptButton.disabled = true;
michael@0 617 #else
michael@0 618 // morph the Cancel button into the Close button
michael@0 619 cancelButton.setAttribute ("icon", "close");
michael@0 620 cancelButton.label = docElt.getAttribute("closebuttonlabel");
michael@0 621 cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
michael@0 622 #endif
michael@0 623 }
michael@0 624 }
michael@0 625 this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
michael@0 626 var panes = this.preferencePanes;
michael@0 627
michael@0 628 var lastPane = null;
michael@0 629 if (this.lastSelected) {
michael@0 630 lastPane = document.getElementById(this.lastSelected);
michael@0 631 if (!lastPane) {
michael@0 632 this.lastSelected = "";
michael@0 633 }
michael@0 634 }
michael@0 635
michael@0 636 var paneToLoad;
michael@0 637 if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
michael@0 638 paneToLoad = document.getElementById(window.arguments[0]);
michael@0 639 this.lastSelected = paneToLoad.id;
michael@0 640 }
michael@0 641 else if (lastPane)
michael@0 642 paneToLoad = lastPane;
michael@0 643 else
michael@0 644 paneToLoad = panes[0];
michael@0 645
michael@0 646 for (var i = 0; i < panes.length; ++i) {
michael@0 647 this._makePaneButton(panes[i]);
michael@0 648 if (panes[i].loaded) {
michael@0 649 // Inline pane content, fire load event to force initialization.
michael@0 650 this._fireEvent("paneload", panes[i]);
michael@0 651 }
michael@0 652 }
michael@0 653 this.showPane(paneToLoad);
michael@0 654
michael@0 655 if (panes.length == 1)
michael@0 656 this._selector.setAttribute("collapsed", "true");
michael@0 657 ]]>
michael@0 658 </constructor>
michael@0 659
michael@0 660 <destructor>
michael@0 661 <![CDATA[
michael@0 662 // Release timers to avoid reference cycles.
michael@0 663 if (this._animateTimer) {
michael@0 664 this._animateTimer.cancel();
michael@0 665 this._animateTimer = null;
michael@0 666 }
michael@0 667 if (this._fadeTimer) {
michael@0 668 this._fadeTimer.cancel();
michael@0 669 this._fadeTimer = null;
michael@0 670 }
michael@0 671 ]]>
michael@0 672 </destructor>
michael@0 673
michael@0 674 <field name="instantApply">false</field>
michael@0 675
michael@0 676 <property name="preferencePanes"
michael@0 677 onget="return this.getElementsByTagName('prefpane');"/>
michael@0 678
michael@0 679 <property name="type" onget="return this.getAttribute('type');"/>
michael@0 680 <property name="_paneDeck"
michael@0 681 onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
michael@0 682 <property name="_paneDeckContainer"
michael@0 683 onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
michael@0 684 <property name="_selector"
michael@0 685 onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
michael@0 686 <property name="lastSelected"
michael@0 687 onget="return this.getAttribute('lastSelected');">
michael@0 688 <setter>
michael@0 689 this.setAttribute("lastSelected", val);
michael@0 690 document.persist(this.id, "lastSelected");
michael@0 691 return val;
michael@0 692 </setter>
michael@0 693 </property>
michael@0 694 <property name="currentPane"
michael@0 695 onset="return this._currentPane = val;">
michael@0 696 <getter>
michael@0 697 if (!this._currentPane)
michael@0 698 this._currentPane = this.preferencePanes[0];
michael@0 699
michael@0 700 return this._currentPane;
michael@0 701 </getter>
michael@0 702 </property>
michael@0 703 <field name="_currentPane">null</field>
michael@0 704
michael@0 705
michael@0 706 <method name="_makePaneButton">
michael@0 707 <parameter name="aPaneElement"/>
michael@0 708 <body>
michael@0 709 <![CDATA[
michael@0 710 var radio = document.createElement("radio");
michael@0 711 radio.setAttribute("pane", aPaneElement.id);
michael@0 712 radio.setAttribute("label", aPaneElement.label);
michael@0 713 // Expose preference group choice to accessibility APIs as an unchecked list item
michael@0 714 // The parent group is exposed to accessibility APIs as a list
michael@0 715 if (aPaneElement.image)
michael@0 716 radio.setAttribute("src", aPaneElement.image);
michael@0 717 radio.style.listStyleImage = aPaneElement.style.listStyleImage;
michael@0 718 this._selector.appendChild(radio);
michael@0 719 return radio;
michael@0 720 ]]>
michael@0 721 </body>
michael@0 722 </method>
michael@0 723
michael@0 724 <method name="showPane">
michael@0 725 <parameter name="aPaneElement"/>
michael@0 726 <body>
michael@0 727 <![CDATA[
michael@0 728 if (!aPaneElement)
michael@0 729 return;
michael@0 730
michael@0 731 this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
michael@0 732 if (!aPaneElement.loaded) {
michael@0 733 let OverlayLoadObserver = function(aPane)
michael@0 734 {
michael@0 735 this._pane = aPane;
michael@0 736 }
michael@0 737 OverlayLoadObserver.prototype = {
michael@0 738 _outer: this,
michael@0 739 observe: function (aSubject, aTopic, aData)
michael@0 740 {
michael@0 741 this._pane.loaded = true;
michael@0 742 this._outer._fireEvent("paneload", this._pane);
michael@0 743 this._outer._selectPane(this._pane);
michael@0 744 }
michael@0 745 };
michael@0 746
michael@0 747 var obs = new OverlayLoadObserver(aPaneElement);
michael@0 748 document.loadOverlay(aPaneElement.src, obs);
michael@0 749 }
michael@0 750 else
michael@0 751 this._selectPane(aPaneElement);
michael@0 752 ]]>
michael@0 753 </body>
michael@0 754 </method>
michael@0 755
michael@0 756 <method name="_fireEvent">
michael@0 757 <parameter name="aEventName"/>
michael@0 758 <parameter name="aTarget"/>
michael@0 759 <body>
michael@0 760 <![CDATA[
michael@0 761 // Panel loaded, synthesize a load event.
michael@0 762 try {
michael@0 763 var event = document.createEvent("Events");
michael@0 764 event.initEvent(aEventName, true, true);
michael@0 765 var cancel = !aTarget.dispatchEvent(event);
michael@0 766 if (aTarget.hasAttribute("on" + aEventName)) {
michael@0 767 var fn = new Function ("event", aTarget.getAttribute("on" + aEventName));
michael@0 768 var rv = fn.call(aTarget, event);
michael@0 769 if (rv == false)
michael@0 770 cancel = true;
michael@0 771 }
michael@0 772 return !cancel;
michael@0 773 }
michael@0 774 catch (e) {
michael@0 775 Components.utils.reportError(e);
michael@0 776 }
michael@0 777 return false;
michael@0 778 ]]>
michael@0 779 </body>
michael@0 780 </method>
michael@0 781
michael@0 782 <field name="_initialized">false</field>
michael@0 783 <method name="_selectPane">
michael@0 784 <parameter name="aPaneElement"/>
michael@0 785 <body>
michael@0 786 <![CDATA[
michael@0 787 #ifdef XP_MACOSX
michael@0 788 var paneTitle = aPaneElement.label;
michael@0 789 if (paneTitle != "")
michael@0 790 document.title = paneTitle;
michael@0 791 #endif
michael@0 792 var helpButton = document.documentElement.getButton("help");
michael@0 793 if (aPaneElement.helpTopic)
michael@0 794 helpButton.hidden = false;
michael@0 795 else
michael@0 796 helpButton.hidden = true;
michael@0 797
michael@0 798 // Find this pane's index in the deck and set the deck's
michael@0 799 // selectedIndex to that value to switch to it.
michael@0 800 var prefpanes = this.preferencePanes;
michael@0 801 for (var i = 0; i < prefpanes.length; ++i) {
michael@0 802 if (prefpanes[i] == aPaneElement) {
michael@0 803 this._paneDeck.selectedIndex = i;
michael@0 804
michael@0 805 if (this.type != "child") {
michael@0 806 if (aPaneElement.hasAttribute("flex") && this._shouldAnimate &&
michael@0 807 prefpanes.length > 1)
michael@0 808 aPaneElement.removeAttribute("flex");
michael@0 809 // Calling sizeToContent after the first prefpane is loaded
michael@0 810 // will size the windows contents so style information is
michael@0 811 // available to calculate correct sizing.
michael@0 812 if (!this._initialized && prefpanes.length > 1) {
michael@0 813 if (this._shouldAnimate)
michael@0 814 this.style.minHeight = 0;
michael@0 815 window.sizeToContent();
michael@0 816 }
michael@0 817
michael@0 818 var oldPane = this.lastSelected ? document.getElementById(this.lastSelected) : this.preferencePanes[0];
michael@0 819 oldPane.selected = !(aPaneElement.selected = true);
michael@0 820 this.lastSelected = aPaneElement.id;
michael@0 821 this.currentPane = aPaneElement;
michael@0 822 this._initialized = true;
michael@0 823
michael@0 824 // Only animate if we've switched between prefpanes
michael@0 825 if (this._shouldAnimate && oldPane.id != aPaneElement.id) {
michael@0 826 aPaneElement.style.opacity = 0.0;
michael@0 827 this.animate(oldPane, aPaneElement);
michael@0 828 }
michael@0 829 else if (!this._shouldAnimate && prefpanes.length > 1) {
michael@0 830 var targetHeight = parseInt(window.getComputedStyle(this._paneDeckContainer, "").height);
michael@0 831 var verticalPadding = parseInt(window.getComputedStyle(aPaneElement, "").paddingTop);
michael@0 832 verticalPadding += parseInt(window.getComputedStyle(aPaneElement, "").paddingBottom);
michael@0 833 if (aPaneElement.contentHeight > targetHeight - verticalPadding) {
michael@0 834 // To workaround the bottom border of a groupbox from being
michael@0 835 // cutoff an hbox with a class of bottomBox may enclose it.
michael@0 836 // This needs to include its padding to resize properly.
michael@0 837 // See bug 394433
michael@0 838 var bottomPadding = 0;
michael@0 839 var bottomBox = aPaneElement.getElementsByAttribute("class", "bottomBox")[0];
michael@0 840 if (bottomBox)
michael@0 841 bottomPadding = parseInt(window.getComputedStyle(bottomBox, "").paddingBottom);
michael@0 842 window.innerHeight += bottomPadding + verticalPadding + aPaneElement.contentHeight - targetHeight;
michael@0 843 }
michael@0 844
michael@0 845 // XXX rstrong - extend the contents of the prefpane to
michael@0 846 // prevent elements from being cutoff (see bug 349098).
michael@0 847 if (aPaneElement.contentHeight + verticalPadding < targetHeight)
michael@0 848 aPaneElement._content.style.height = targetHeight - verticalPadding + "px";
michael@0 849 }
michael@0 850 }
michael@0 851 break;
michael@0 852 }
michael@0 853 }
michael@0 854 ]]>
michael@0 855 </body>
michael@0 856 </method>
michael@0 857
michael@0 858 <property name="_shouldAnimate">
michael@0 859 <getter>
michael@0 860 <![CDATA[
michael@0 861 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
michael@0 862 .getService(Components.interfaces.nsIPrefBranch);
michael@0 863 #ifdef XP_MACOSX
michael@0 864 var animate = true;
michael@0 865 #else
michael@0 866 var animate = false;
michael@0 867 #endif
michael@0 868 try {
michael@0 869 animate = psvc.getBoolPref("browser.preferences.animateFadeIn");
michael@0 870 }
michael@0 871 catch (e) { }
michael@0 872 return animate;
michael@0 873 ]]>
michael@0 874 </getter>
michael@0 875 </property>
michael@0 876
michael@0 877 <method name="animate">
michael@0 878 <parameter name="aOldPane"/>
michael@0 879 <parameter name="aNewPane"/>
michael@0 880 <body>
michael@0 881 <![CDATA[
michael@0 882 // if we are already resizing, use currentHeight
michael@0 883 var oldHeight = this._currentHeight ? this._currentHeight : aOldPane.contentHeight;
michael@0 884
michael@0 885 this._multiplier = aNewPane.contentHeight > oldHeight ? 1 : -1;
michael@0 886 var sizeDelta = Math.abs(oldHeight - aNewPane.contentHeight);
michael@0 887 this._animateRemainder = sizeDelta % this._animateIncrement;
michael@0 888
michael@0 889 this._setUpAnimationTimer(oldHeight);
michael@0 890 ]]>
michael@0 891 </body>
michael@0 892 </method>
michael@0 893
michael@0 894 <property name="_sizeIncrement">
michael@0 895 <getter>
michael@0 896 <![CDATA[
michael@0 897 var lastSelectedPane = document.getElementById(this.lastSelected);
michael@0 898 var increment = this._animateIncrement * this._multiplier;
michael@0 899 var newHeight = this._currentHeight + increment;
michael@0 900 if ((this._multiplier > 0 && this._currentHeight >= lastSelectedPane.contentHeight) ||
michael@0 901 (this._multiplier < 0 && this._currentHeight <= lastSelectedPane.contentHeight))
michael@0 902 return 0;
michael@0 903
michael@0 904 if ((this._multiplier > 0 && newHeight > lastSelectedPane.contentHeight) ||
michael@0 905 (this._multiplier < 0 && newHeight < lastSelectedPane.contentHeight))
michael@0 906 increment = this._animateRemainder * this._multiplier;
michael@0 907 return increment;
michael@0 908 ]]>
michael@0 909 </getter>
michael@0 910 </property>
michael@0 911
michael@0 912 <method name="notify">
michael@0 913 <parameter name="aTimer"/>
michael@0 914 <body>
michael@0 915 <![CDATA[
michael@0 916 if (!document)
michael@0 917 aTimer.cancel();
michael@0 918
michael@0 919 if (aTimer == this._animateTimer) {
michael@0 920 var increment = this._sizeIncrement;
michael@0 921 if (increment != 0) {
michael@0 922 window.innerHeight += increment;
michael@0 923 this._currentHeight += increment;
michael@0 924 }
michael@0 925 else {
michael@0 926 aTimer.cancel();
michael@0 927 this._setUpFadeTimer();
michael@0 928 }
michael@0 929 } else if (aTimer == this._fadeTimer) {
michael@0 930 var elt = document.getElementById(this.lastSelected);
michael@0 931 var newOpacity = parseFloat(window.getComputedStyle(elt, "").opacity) + this._fadeIncrement;
michael@0 932 if (newOpacity < 1.0)
michael@0 933 elt.style.opacity = newOpacity;
michael@0 934 else {
michael@0 935 aTimer.cancel();
michael@0 936 elt.style.opacity = 1.0;
michael@0 937 }
michael@0 938 }
michael@0 939 ]]>
michael@0 940 </body>
michael@0 941 </method>
michael@0 942
michael@0 943 <method name="_setUpAnimationTimer">
michael@0 944 <parameter name="aStartHeight"/>
michael@0 945 <body>
michael@0 946 <![CDATA[
michael@0 947 if (!this._animateTimer)
michael@0 948 this._animateTimer = Components.classes["@mozilla.org/timer;1"]
michael@0 949 .createInstance(Components.interfaces.nsITimer);
michael@0 950 else
michael@0 951 this._animateTimer.cancel();
michael@0 952 this._currentHeight = aStartHeight;
michael@0 953
michael@0 954 this._animateTimer.initWithCallback(this, this._animateDelay,
michael@0 955 Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
michael@0 956 ]]>
michael@0 957 </body>
michael@0 958 </method>
michael@0 959
michael@0 960 <method name="_setUpFadeTimer">
michael@0 961 <body>
michael@0 962 <![CDATA[
michael@0 963 if (!this._fadeTimer)
michael@0 964 this._fadeTimer = Components.classes["@mozilla.org/timer;1"]
michael@0 965 .createInstance(Components.interfaces.nsITimer);
michael@0 966 else
michael@0 967 this._fadeTimer.cancel();
michael@0 968
michael@0 969 this._fadeTimer.initWithCallback(this, this._fadeDelay,
michael@0 970 Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
michael@0 971 ]]>
michael@0 972 </body>
michael@0 973 </method>
michael@0 974
michael@0 975 <field name="_animateTimer">null</field>
michael@0 976 <field name="_fadeTimer">null</field>
michael@0 977 <field name="_animateDelay">15</field>
michael@0 978 <field name="_animateIncrement">40</field>
michael@0 979 <field name="_fadeDelay">5</field>
michael@0 980 <field name="_fadeIncrement">0.40</field>
michael@0 981 <field name="_animateRemainder">0</field>
michael@0 982 <field name="_currentHeight">0</field>
michael@0 983 <field name="_multiplier">0</field>
michael@0 984
michael@0 985 <method name="addPane">
michael@0 986 <parameter name="aPaneElement"/>
michael@0 987 <body>
michael@0 988 <![CDATA[
michael@0 989 this.appendChild(aPaneElement);
michael@0 990
michael@0 991 // Set up pane button
michael@0 992 this._makePaneButton(aPaneElement);
michael@0 993 ]]>
michael@0 994 </body>
michael@0 995 </method>
michael@0 996
michael@0 997 <method name="openSubDialog">
michael@0 998 <parameter name="aURL"/>
michael@0 999 <parameter name="aFeatures"/>
michael@0 1000 <parameter name="aParams"/>
michael@0 1001 <body>
michael@0 1002 return openDialog(aURL, "", "modal,centerscreen,resizable=no" + (aFeatures != "" ? ("," + aFeatures) : ""), aParams);
michael@0 1003 </body>
michael@0 1004 </method>
michael@0 1005
michael@0 1006 <method name="openWindow">
michael@0 1007 <parameter name="aWindowType"/>
michael@0 1008 <parameter name="aURL"/>
michael@0 1009 <parameter name="aFeatures"/>
michael@0 1010 <parameter name="aParams"/>
michael@0 1011 <body>
michael@0 1012 <![CDATA[
michael@0 1013 var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
michael@0 1014 .getService(Components.interfaces.nsIWindowMediator);
michael@0 1015 var win = aWindowType ? wm.getMostRecentWindow(aWindowType) : null;
michael@0 1016 if (win) {
michael@0 1017 if ("initWithParams" in win)
michael@0 1018 win.initWithParams(aParams);
michael@0 1019 win.focus();
michael@0 1020 }
michael@0 1021 else {
michael@0 1022 var features = "resizable,dialog=no,centerscreen" + (aFeatures != "" ? ("," + aFeatures) : "");
michael@0 1023 var parentWindow = (this.instantApply || !window.opener || window.opener.closed) ? window : window.opener;
michael@0 1024 win = parentWindow.openDialog(aURL, "_blank", features, aParams);
michael@0 1025 }
michael@0 1026 return win;
michael@0 1027 ]]>
michael@0 1028 </body>
michael@0 1029 </method>
michael@0 1030 </implementation>
michael@0 1031 <handlers>
michael@0 1032 <handler event="dialogaccept">
michael@0 1033 <![CDATA[
michael@0 1034 if (!this._fireEvent("beforeaccept", this)){
michael@0 1035 return false;
michael@0 1036 }
michael@0 1037
michael@0 1038 if (this.type == "child" && window.opener) {
michael@0 1039 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
michael@0 1040 .getService(Components.interfaces.nsIPrefBranch);
michael@0 1041 var instantApply = psvc.getBoolPref("browser.preferences.instantApply");
michael@0 1042 if (instantApply) {
michael@0 1043 var panes = this.preferencePanes;
michael@0 1044 for (var i = 0; i < panes.length; ++i)
michael@0 1045 panes[i].writePreferences(true);
michael@0 1046 }
michael@0 1047 else {
michael@0 1048 // Clone all the preferences elements from the child document and
michael@0 1049 // insert them into the pane collection of the parent.
michael@0 1050 var pdoc = window.opener.document;
michael@0 1051 if (pdoc.documentElement.localName == "prefwindow") {
michael@0 1052 var currentPane = pdoc.documentElement.currentPane;
michael@0 1053 var id = window.location.href + "#childprefs";
michael@0 1054 var childPrefs = pdoc.getElementById(id);
michael@0 1055 if (!childPrefs) {
michael@0 1056 var childPrefs = pdoc.createElement("preferences");
michael@0 1057 currentPane.appendChild(childPrefs);
michael@0 1058 childPrefs.id = id;
michael@0 1059 }
michael@0 1060 var panes = this.preferencePanes;
michael@0 1061 for (var i = 0; i < panes.length; ++i) {
michael@0 1062 var preferences = panes[i].preferences;
michael@0 1063 for (var j = 0; j < preferences.length; ++j) {
michael@0 1064 // Try to find a preference element for the same preference.
michael@0 1065 var preference = null;
michael@0 1066 var parentPreferences = pdoc.getElementsByTagName("preferences");
michael@0 1067 for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
michael@0 1068 var parentPrefs = parentPreferences[k]
michael@0 1069 .getElementsByAttribute("name", preferences[j].name);
michael@0 1070 for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
michael@0 1071 if (parentPrefs[l].localName == "preference")
michael@0 1072 preference = parentPrefs[l];
michael@0 1073 }
michael@0 1074 }
michael@0 1075 if (!preference) {
michael@0 1076 // No matching preference in the parent window.
michael@0 1077 preference = pdoc.createElement("preference");
michael@0 1078 childPrefs.appendChild(preference);
michael@0 1079 preference.name = preferences[j].name;
michael@0 1080 preference.type = preferences[j].type;
michael@0 1081 preference.inverted = preferences[j].inverted;
michael@0 1082 preference.readonly = preferences[j].readonly;
michael@0 1083 preference.disabled = preferences[j].disabled;
michael@0 1084 }
michael@0 1085 preference.value = preferences[j].value;
michael@0 1086 }
michael@0 1087 }
michael@0 1088 }
michael@0 1089 }
michael@0 1090 }
michael@0 1091 else {
michael@0 1092 var panes = this.preferencePanes;
michael@0 1093 for (var i = 0; i < panes.length; ++i)
michael@0 1094 panes[i].writePreferences(false);
michael@0 1095
michael@0 1096 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
michael@0 1097 .getService(Components.interfaces.nsIPrefService);
michael@0 1098 psvc.savePrefFile(null);
michael@0 1099 }
michael@0 1100
michael@0 1101 return true;
michael@0 1102 ]]>
michael@0 1103 </handler>
michael@0 1104 <handler event="command">
michael@0 1105 if (event.originalTarget.hasAttribute("pane")) {
michael@0 1106 var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
michael@0 1107 this.showPane(pane);
michael@0 1108 }
michael@0 1109 </handler>
michael@0 1110
michael@0 1111 <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
michael@0 1112 <![CDATA[
michael@0 1113 if (this.instantApply)
michael@0 1114 window.close();
michael@0 1115 event.stopPropagation();
michael@0 1116 event.preventDefault();
michael@0 1117 ]]>
michael@0 1118 </handler>
michael@0 1119
michael@0 1120 <handler event="keypress"
michael@0 1121 #ifdef XP_MACOSX
michael@0 1122 key="&openHelpMac.commandkey;" modifiers="accel"
michael@0 1123 #else
michael@0 1124 keycode="&openHelp.commandkey;"
michael@0 1125 #endif
michael@0 1126 phase="capturing">
michael@0 1127 <![CDATA[
michael@0 1128 var helpButton = this.getButton("help");
michael@0 1129 if (helpButton.disabled || helpButton.hidden)
michael@0 1130 return;
michael@0 1131 this._fireEvent("dialoghelp", this);
michael@0 1132 event.stopPropagation();
michael@0 1133 event.preventDefault();
michael@0 1134 ]]>
michael@0 1135 </handler>
michael@0 1136 </handlers>
michael@0 1137 </binding>
michael@0 1138
michael@0 1139 <binding id="prefpane">
michael@0 1140 <resources>
michael@0 1141 <stylesheet src="chrome://global/skin/preferences.css"/>
michael@0 1142 </resources>
michael@0 1143 <content>
michael@0 1144 <xul:vbox class="content-box" xbl:inherits="flex">
michael@0 1145 <children/>
michael@0 1146 </xul:vbox>
michael@0 1147 </content>
michael@0 1148 <implementation>
michael@0 1149 <method name="writePreferences">
michael@0 1150 <parameter name="aFlushToDisk"/>
michael@0 1151 <body>
michael@0 1152 <![CDATA[
michael@0 1153 // Write all values to preferences.
michael@0 1154 var preferences = this.preferences;
michael@0 1155 for (var i = 0; i < preferences.length; ++i) {
michael@0 1156 var preference = preferences[i];
michael@0 1157 preference.batching = true;
michael@0 1158 preference.valueFromPreferences = preference.value;
michael@0 1159 preference.batching = false;
michael@0 1160 }
michael@0 1161 if (aFlushToDisk) {
michael@0 1162 var psvc = Components.classes["@mozilla.org/preferences-service;1"]
michael@0 1163 .getService(Components.interfaces.nsIPrefService);
michael@0 1164 psvc.savePrefFile(null);
michael@0 1165 }
michael@0 1166 ]]>
michael@0 1167 </body>
michael@0 1168 </method>
michael@0 1169
michael@0 1170 <property name="src"
michael@0 1171 onget="return this.getAttribute('src');"
michael@0 1172 onset="this.setAttribute('src', val); return val;"/>
michael@0 1173 <property name="selected"
michael@0 1174 onget="return this.getAttribute('selected') == 'true';"
michael@0 1175 onset="this.setAttribute('selected', val); return val;"/>
michael@0 1176 <property name="image"
michael@0 1177 onget="return this.getAttribute('image');"
michael@0 1178 onset="this.setAttribute('image', val); return val;"/>
michael@0 1179 <property name="label"
michael@0 1180 onget="return this.getAttribute('label');"
michael@0 1181 onset="this.setAttribute('label', val); return val;"/>
michael@0 1182
michael@0 1183 <property name="preferenceElements"
michael@0 1184 onget="return this.getElementsByAttribute('preference', '*');"/>
michael@0 1185 <property name="preferences"
michael@0 1186 onget="return this.getElementsByTagName('preference');"/>
michael@0 1187
michael@0 1188 <property name="helpTopic">
michael@0 1189 <getter>
michael@0 1190 <![CDATA[
michael@0 1191 // if there are tabs, and the selected tab provides a helpTopic, return that
michael@0 1192 var box = this.getElementsByTagName("tabbox");
michael@0 1193 if (box[0]) {
michael@0 1194 var tab = box[0].selectedTab;
michael@0 1195 if (tab && tab.hasAttribute("helpTopic"))
michael@0 1196 return tab.getAttribute("helpTopic");
michael@0 1197 }
michael@0 1198
michael@0 1199 // otherwise, return the helpTopic of the current panel
michael@0 1200 return this.getAttribute("helpTopic");
michael@0 1201 ]]>
michael@0 1202 </getter>
michael@0 1203 </property>
michael@0 1204
michael@0 1205 <field name="_loaded">false</field>
michael@0 1206 <property name="loaded"
michael@0 1207 onget="return !this.src ? true : this._loaded;"
michael@0 1208 onset="this._loaded = val; return val;"/>
michael@0 1209
michael@0 1210 <method name="preferenceForElement">
michael@0 1211 <parameter name="aElement"/>
michael@0 1212 <body>
michael@0 1213 return document.getElementById(aElement.getAttribute("preference"));
michael@0 1214 </body>
michael@0 1215 </method>
michael@0 1216
michael@0 1217 <method name="getPreferenceElement">
michael@0 1218 <parameter name="aStartElement"/>
michael@0 1219 <body>
michael@0 1220 <![CDATA[
michael@0 1221 var temp = aStartElement;
michael@0 1222 while (temp && temp.nodeType == Node.ELEMENT_NODE &&
michael@0 1223 !temp.hasAttribute("preference"))
michael@0 1224 temp = temp.parentNode;
michael@0 1225 return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
michael@0 1226 ]]>
michael@0 1227 </body>
michael@0 1228 </method>
michael@0 1229
michael@0 1230 <method name="userChangedValue">
michael@0 1231 <parameter name="aElement"/>
michael@0 1232 <body>
michael@0 1233 <![CDATA[
michael@0 1234 var element = this.getPreferenceElement(aElement);
michael@0 1235 if (element.hasAttribute("preference")) {
michael@0 1236 var preference = document.getElementById(element.getAttribute("preference"));
michael@0 1237 var prefVal = preference.getElementValue(element);
michael@0 1238 preference.value = prefVal;
michael@0 1239 }
michael@0 1240 ]]>
michael@0 1241 </body>
michael@0 1242 </method>
michael@0 1243
michael@0 1244 <property name="contentHeight">
michael@0 1245 <getter>
michael@0 1246 var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
michael@0 1247 targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
michael@0 1248 targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
michael@0 1249 return targetHeight;
michael@0 1250 </getter>
michael@0 1251 </property>
michael@0 1252 <field name="_content">
michael@0 1253 document.getAnonymousElementByAttribute(this, "class", "content-box");
michael@0 1254 </field>
michael@0 1255 </implementation>
michael@0 1256 <handlers>
michael@0 1257 <handler event="command">
michael@0 1258 // This "command" event handler tracks changes made to preferences by
michael@0 1259 // the user in this window.
michael@0 1260 if (event.sourceEvent)
michael@0 1261 event = event.sourceEvent;
michael@0 1262 this.userChangedValue(event.target);
michael@0 1263 </handler>
michael@0 1264 <handler event="select">
michael@0 1265 // This "select" event handler tracks changes made to colorpicker
michael@0 1266 // preferences by the user in this window.
michael@0 1267 if (event.target.localName == "colorpicker")
michael@0 1268 this.userChangedValue(event.target);
michael@0 1269 </handler>
michael@0 1270 <handler event="change">
michael@0 1271 // This "change" event handler tracks changes made to preferences by
michael@0 1272 // the user in this window.
michael@0 1273 this.userChangedValue(event.target);
michael@0 1274 </handler>
michael@0 1275 <handler event="input">
michael@0 1276 // This "input" event handler tracks changes made to preferences by
michael@0 1277 // the user in this window.
michael@0 1278 this.userChangedValue(event.target);
michael@0 1279 </handler>
michael@0 1280 <handler event="paneload">
michael@0 1281 <![CDATA[
michael@0 1282 // Initialize all values from preferences.
michael@0 1283 var elements = this.preferenceElements;
michael@0 1284 for (var i = 0; i < elements.length; ++i) {
michael@0 1285 try {
michael@0 1286 var preference = this.preferenceForElement(elements[i]);
michael@0 1287 preference.setElementValue(elements[i]);
michael@0 1288 }
michael@0 1289 catch (e) {
michael@0 1290 dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
michael@0 1291 }
michael@0 1292 }
michael@0 1293 ]]>
michael@0 1294 </handler>
michael@0 1295 </handlers>
michael@0 1296 </binding>
michael@0 1297
michael@0 1298 <binding id="panebutton" role="xul:listitem"
michael@0 1299 extends="chrome://global/content/bindings/radio.xml#radio">
michael@0 1300 <resources>
michael@0 1301 <stylesheet src="chrome://global/skin/preferences.css"/>
michael@0 1302 </resources>
michael@0 1303 <content>
michael@0 1304 <xul:image class="paneButtonIcon" xbl:inherits="src"/>
michael@0 1305 <xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
michael@0 1306 </content>
michael@0 1307 </binding>
michael@0 1308
michael@0 1309 </bindings>
michael@0 1310
michael@0 1311 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 1312 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 1313 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 1314 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 1315
michael@0 1316 #
michael@0 1317 # This is PrefWindow 6. The Code Could Well Be Ready, Are You?
michael@0 1318 #
michael@0 1319 # Historical References:
michael@0 1320 # PrefWindow V (February 1, 2003)
michael@0 1321 # PrefWindow IV (April 24, 2000)
michael@0 1322 # PrefWindow III (January 6, 2000)
michael@0 1323 # PrefWindow II (???)
michael@0 1324 # PrefWindow I (June 4, 1999)
michael@0 1325 #

mercurial