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