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