|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict"; |
|
5 |
|
6 const {classes: Cc, interfaces: Ci, manager: Cm, utils: Cu} = Components; |
|
7 Cu.import("resource://gre/modules/Services.jsm"); |
|
8 |
|
9 const VKB_ENTER_KEY = 13; // User press of VKB enter key |
|
10 const INITIAL_PAGE_DELAY = 500; // Initial pause on program start for scroll alignment |
|
11 const PREFS_BUFFER_MAX = 30; // Max prefs buffer size for getPrefsBuffer() |
|
12 const PAGE_SCROLL_TRIGGER = 200; // Triggers additional getPrefsBuffer() on user scroll-to-bottom |
|
13 const FILTER_CHANGE_TRIGGER = 200; // Delay between responses to filterInput changes |
|
14 const INNERHTML_VALUE_DELAY = 100; // Delay before providing prefs innerHTML value |
|
15 |
|
16 let gStringBundle = Services.strings.createBundle("chrome://browser/locale/config.properties"); |
|
17 let gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); |
|
18 |
|
19 |
|
20 /* ============================== NewPrefDialog ============================== |
|
21 * |
|
22 * New Preference Dialog Object and methods |
|
23 * |
|
24 * Implements User Interfaces for creation of a single(new) Preference setting |
|
25 * |
|
26 */ |
|
27 var NewPrefDialog = { |
|
28 |
|
29 _prefsShield: null, |
|
30 |
|
31 _newPrefsDialog: null, |
|
32 _newPrefItem: null, |
|
33 _prefNameInputElt: null, |
|
34 _prefTypeSelectElt: null, |
|
35 |
|
36 _booleanValue: null, |
|
37 _booleanToggle: null, |
|
38 _stringValue: null, |
|
39 _intValue: null, |
|
40 |
|
41 _positiveButton: null, |
|
42 |
|
43 get type() { |
|
44 return this._prefTypeSelectElt.value; |
|
45 }, |
|
46 |
|
47 set type(aType) { |
|
48 this._prefTypeSelectElt.value = aType; |
|
49 switch(this._prefTypeSelectElt.value) { |
|
50 case "boolean": |
|
51 this._prefTypeSelectElt.selectedIndex = 0; |
|
52 break; |
|
53 case "string": |
|
54 this._prefTypeSelectElt.selectedIndex = 1; |
|
55 break; |
|
56 case "int": |
|
57 this._prefTypeSelectElt.selectedIndex = 2; |
|
58 break; |
|
59 } |
|
60 |
|
61 this._newPrefItem.setAttribute("typestyle", aType); |
|
62 }, |
|
63 |
|
64 // Init the NewPrefDialog |
|
65 init: function AC_init() { |
|
66 this._prefsShield = document.getElementById("prefs-shield"); |
|
67 |
|
68 this._newPrefsDialog = document.getElementById("new-pref-container"); |
|
69 this._newPrefItem = document.getElementById("new-pref-item"); |
|
70 this._prefNameInputElt = document.getElementById("new-pref-name"); |
|
71 this._prefTypeSelectElt = document.getElementById("new-pref-type"); |
|
72 |
|
73 this._booleanValue = document.getElementById("new-pref-value-boolean"); |
|
74 this._stringValue = document.getElementById("new-pref-value-string"); |
|
75 this._intValue = document.getElementById("new-pref-value-int"); |
|
76 |
|
77 this._positiveButton = document.getElementById("positive-button"); |
|
78 }, |
|
79 |
|
80 // Called to update positive button to display text ("Create"/"Change), and enabled/disabled status |
|
81 // As new pref name is initially displayed, re-focused, or modifed during user input |
|
82 _updatePositiveButton: function AC_updatePositiveButton(aPrefName) { |
|
83 this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.createButton"); |
|
84 this._positiveButton.setAttribute("disabled", true); |
|
85 if (aPrefName == "") { |
|
86 return; |
|
87 } |
|
88 |
|
89 // If item already in list, it's being changed, else added |
|
90 let item = document.querySelector(".pref-item[name=" + aPrefName.quote() + "]"); |
|
91 if (item) { |
|
92 this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.changeButton"); |
|
93 } else { |
|
94 this._positiveButton.removeAttribute("disabled"); |
|
95 } |
|
96 }, |
|
97 |
|
98 // When we want to cancel/hide an existing, or show a new pref dialog |
|
99 toggleShowHide: function AC_toggleShowHide() { |
|
100 if (this._newPrefsDialog.classList.contains("show")) { |
|
101 this.hide(); |
|
102 } else { |
|
103 this._show(); |
|
104 } |
|
105 }, |
|
106 |
|
107 // When we want to show the new pref dialog / shield the prefs list |
|
108 _show: function AC_show() { |
|
109 this._newPrefsDialog.classList.add("show"); |
|
110 this._prefsShield.setAttribute("shown", true); |
|
111 |
|
112 // Initial default field values |
|
113 this._prefNameInputElt.value = ""; |
|
114 this._updatePositiveButton(this._prefNameInputElt.value); |
|
115 |
|
116 this.type = "boolean"; |
|
117 this._booleanValue.value = "false"; |
|
118 this._stringValue.value = ""; |
|
119 this._intValue.value = ""; |
|
120 |
|
121 this._prefNameInputElt.focus(); |
|
122 |
|
123 window.addEventListener("keypress", this.handleKeypress, false); |
|
124 }, |
|
125 |
|
126 // When we want to cancel/hide the new pref dialog / un-shield the prefs list |
|
127 hide: function AC_hide() { |
|
128 this._newPrefsDialog.classList.remove("show"); |
|
129 this._prefsShield.removeAttribute("shown"); |
|
130 |
|
131 window.removeEventListener("keypress", this.handleKeypress, false); |
|
132 }, |
|
133 |
|
134 // Watch user key input so we can provide Enter key action, commit input values |
|
135 handleKeypress: function AC_handleKeypress(aEvent) { |
|
136 // Close our VKB on new pref enter key press |
|
137 if (aEvent.keyCode == VKB_ENTER_KEY) |
|
138 aEvent.target.blur(); |
|
139 }, |
|
140 |
|
141 // New prefs create dialog only allows creating a non-existing preference, doesn't allow for |
|
142 // Changing an existing one on-the-fly, tap existing/displayed line item pref for that |
|
143 create: function AC_create(aEvent) { |
|
144 if (this._positiveButton.getAttribute("disabled") == "true") { |
|
145 return; |
|
146 } |
|
147 |
|
148 switch(this.type) { |
|
149 case "boolean": |
|
150 Services.prefs.setBoolPref(this._prefNameInputElt.value, (this._booleanValue.value == "true") ? true : false); |
|
151 break; |
|
152 case "string": |
|
153 Services.prefs.setCharPref(this._prefNameInputElt.value, this._stringValue.value); |
|
154 break; |
|
155 case "int": |
|
156 Services.prefs.setIntPref(this._prefNameInputElt.value, this._intValue.value); |
|
157 break; |
|
158 } |
|
159 |
|
160 this.hide(); |
|
161 }, |
|
162 |
|
163 // Display proper positive button text/state on new prefs name input focus |
|
164 focusName: function AC_focusName(aEvent) { |
|
165 this._updatePositiveButton(aEvent.target.value); |
|
166 }, |
|
167 |
|
168 // Display proper positive button text/state as user changes new prefs name |
|
169 updateName: function AC_updateName(aEvent) { |
|
170 this._updatePositiveButton(aEvent.target.value); |
|
171 }, |
|
172 |
|
173 // In new prefs dialog, bool prefs are <input type="text">, as they aren't yet tied to an |
|
174 // Actual Services.prefs.*etBoolPref() |
|
175 toggleBoolValue: function AC_toggleBoolValue() { |
|
176 this._booleanValue.value = (this._booleanValue.value == "true" ? "false" : "true"); |
|
177 } |
|
178 } |
|
179 |
|
180 |
|
181 /* ============================== AboutConfig ============================== |
|
182 * |
|
183 * Main AboutConfig object and methods |
|
184 * |
|
185 * Implements User Interfaces for maintenance of a list of Preference settings |
|
186 * |
|
187 */ |
|
188 var AboutConfig = { |
|
189 |
|
190 contextMenuLINode: null, |
|
191 filterInput: null, |
|
192 _filterPrevInput: null, |
|
193 _filterChangeTimer: null, |
|
194 _prefsContainer: null, |
|
195 _loadingContainer: null, |
|
196 _list: null, |
|
197 |
|
198 // Init the main AboutConfig dialog |
|
199 init: function AC_init() { |
|
200 this.filterInput = document.getElementById("filter-input"); |
|
201 this._prefsContainer = document.getElementById("prefs-container"); |
|
202 this._loadingContainer = document.getElementById("loading-container"); |
|
203 |
|
204 let list = Services.prefs.getChildList(""); |
|
205 this._list = list.sort().map( function AC_getMapPref(aPref) { |
|
206 return new Pref(aPref); |
|
207 }, this); |
|
208 |
|
209 // Display the current prefs list (retains searchFilter value) |
|
210 this.bufferFilterInput(); |
|
211 |
|
212 // Setup the prefs observers |
|
213 Services.prefs.addObserver("", this, false); |
|
214 }, |
|
215 |
|
216 // Uninit the main AboutConfig dialog |
|
217 uninit: function AC_uninit() { |
|
218 // Remove the prefs observer |
|
219 Services.prefs.removeObserver("", this); |
|
220 |
|
221 // Ensure pref adds/changes/resets flushed to disk on unload |
|
222 Services.prefs.savePrefFile(null); |
|
223 }, |
|
224 |
|
225 // Clear the filterInput value, to display the entire list |
|
226 clearFilterInput: function AC_clearFilterInput() { |
|
227 this.filterInput.value = ""; |
|
228 this.bufferFilterInput(); |
|
229 }, |
|
230 |
|
231 // Buffer down rapid changes in filterInput value from keyboard |
|
232 bufferFilterInput: function AC_bufferFilterInput() { |
|
233 if (this._filterChangeTimer) { |
|
234 clearTimeout(this._filterChangeTimer); |
|
235 } |
|
236 |
|
237 this._filterChangeTimer = setTimeout((function() { |
|
238 this._filterChangeTimer = null; |
|
239 // Display updated prefs list when filterInput value settles |
|
240 this._displayNewList(); |
|
241 }).bind(this), FILTER_CHANGE_TRIGGER); |
|
242 }, |
|
243 |
|
244 // Update displayed list when filterInput value changes |
|
245 _displayNewList: function AC_displayNewList() { |
|
246 // This survives the search filter value past a page refresh |
|
247 this.filterInput.setAttribute("value", this.filterInput.value); |
|
248 |
|
249 // Don't start new filter search if same as last |
|
250 if (this.filterInput.value == this._filterPrevInput) { |
|
251 return; |
|
252 } |
|
253 this._filterPrevInput = this.filterInput.value; |
|
254 |
|
255 // Clear list item selection / context menu, prefs list, get first buffer, set scrolling on |
|
256 this.selected = ""; |
|
257 this._clearPrefsContainer(); |
|
258 this._addMorePrefsToContainer(); |
|
259 window.onscroll = this.onScroll.bind(this); |
|
260 |
|
261 // Pause for screen to settle, then ensure at top |
|
262 setTimeout((function() { |
|
263 window.scrollTo(0, 0); |
|
264 }).bind(this), INITIAL_PAGE_DELAY); |
|
265 }, |
|
266 |
|
267 // Clear the displayed preferences list |
|
268 _clearPrefsContainer: function AC_clearPrefsContainer() { |
|
269 // Quick clear the prefsContainer list |
|
270 let empty = this._prefsContainer.cloneNode(false); |
|
271 this._prefsContainer.parentNode.replaceChild(empty, this._prefsContainer); |
|
272 this._prefsContainer = empty; |
|
273 |
|
274 // Quick clear the prefs li.HTML list |
|
275 this._list.forEach(function(item) { |
|
276 delete item.li; |
|
277 }); |
|
278 }, |
|
279 |
|
280 // Get a small manageable block of prefs items, and add them to the displayed list |
|
281 _addMorePrefsToContainer: function AC_addMorePrefsToContainer() { |
|
282 // Create filter regex |
|
283 let filterExp = this.filterInput.value ? |
|
284 new RegExp(this.filterInput.value, "i") : null; |
|
285 |
|
286 // Get a new block for the display list |
|
287 let prefsBuffer = []; |
|
288 for (let i = 0; i < this._list.length && prefsBuffer.length < PREFS_BUFFER_MAX; i++) { |
|
289 if (!this._list[i].li && this._list[i].test(filterExp)) { |
|
290 prefsBuffer.push(this._list[i]); |
|
291 } |
|
292 } |
|
293 |
|
294 // Add the new block to the displayed list |
|
295 for (let i = 0; i < prefsBuffer.length; i++) { |
|
296 this._prefsContainer.appendChild(prefsBuffer[i].getOrCreateNewLINode()); |
|
297 } |
|
298 |
|
299 // Determine if anything left to add later by scrolling |
|
300 let anotherPrefsBufferRemains = false; |
|
301 for (let i = 0; i < this._list.length; i++) { |
|
302 if (!this._list[i].li && this._list[i].test(filterExp)) { |
|
303 anotherPrefsBufferRemains = true; |
|
304 break; |
|
305 } |
|
306 } |
|
307 |
|
308 if (anotherPrefsBufferRemains) { |
|
309 // If still more could be displayed, show the throbber |
|
310 this._loadingContainer.style.display = "block"; |
|
311 } else { |
|
312 // If no more could be displayed, hide the throbber, and stop noticing scroll events |
|
313 this._loadingContainer.style.display = "none"; |
|
314 window.onscroll = null; |
|
315 } |
|
316 }, |
|
317 |
|
318 // If scrolling at the bottom, maybe add some more entries |
|
319 onScroll: function AC_onScroll(aEvent) { |
|
320 if (this._prefsContainer.scrollHeight - (window.pageYOffset + window.innerHeight) < PAGE_SCROLL_TRIGGER) { |
|
321 if (!this._filterChangeTimer) { |
|
322 this._addMorePrefsToContainer(); |
|
323 } |
|
324 } |
|
325 }, |
|
326 |
|
327 |
|
328 // Return currently selected list item node |
|
329 get selected() { |
|
330 return document.querySelector(".pref-item.selected"); |
|
331 }, |
|
332 |
|
333 // Set list item node as selected |
|
334 set selected(aSelection) { |
|
335 let currentSelection = this.selected; |
|
336 if (aSelection == currentSelection) { |
|
337 return; |
|
338 } |
|
339 |
|
340 // Clear any previous selection |
|
341 if (currentSelection) { |
|
342 currentSelection.classList.remove("selected"); |
|
343 currentSelection.removeEventListener("keypress", this.handleKeypress, false); |
|
344 } |
|
345 |
|
346 // Set any current selection |
|
347 if (aSelection) { |
|
348 aSelection.classList.add("selected"); |
|
349 aSelection.addEventListener("keypress", this.handleKeypress, false); |
|
350 } |
|
351 }, |
|
352 |
|
353 // Watch user key input so we can provide Enter key action, commit input values |
|
354 handleKeypress: function AC_handleKeypress(aEvent) { |
|
355 if (aEvent.keyCode == VKB_ENTER_KEY) |
|
356 aEvent.target.blur(); |
|
357 }, |
|
358 |
|
359 // Return the target list item node of an action event |
|
360 getLINodeForEvent: function AC_getLINodeForEvent(aEvent) { |
|
361 let node = aEvent.target; |
|
362 while (node && node.nodeName != "li") { |
|
363 node = node.parentNode; |
|
364 } |
|
365 |
|
366 return node; |
|
367 }, |
|
368 |
|
369 // Return a pref of a list item node |
|
370 _getPrefForNode: function AC_getPrefForNode(aNode) { |
|
371 let pref = aNode.getAttribute("name"); |
|
372 |
|
373 return new Pref(pref); |
|
374 }, |
|
375 |
|
376 // When list item name or value are tapped |
|
377 selectOrToggleBoolPref: function AC_selectOrToggleBoolPref(aEvent) { |
|
378 let node = this.getLINodeForEvent(aEvent); |
|
379 |
|
380 // If not already selected, just do so |
|
381 if (this.selected != node) { |
|
382 this.selected = node; |
|
383 return; |
|
384 } |
|
385 |
|
386 // If already selected, and value is boolean, toggle it |
|
387 let pref = this._getPrefForNode(node); |
|
388 if (pref.type != Services.prefs.PREF_BOOL) { |
|
389 return; |
|
390 } |
|
391 |
|
392 this.toggleBoolPref(aEvent); |
|
393 }, |
|
394 |
|
395 // When finalizing list input values due to blur |
|
396 setIntOrStringPref: function AC_setIntOrStringPref(aEvent) { |
|
397 let node = this.getLINodeForEvent(aEvent); |
|
398 |
|
399 // Skip if locked |
|
400 let pref = this._getPrefForNode(node); |
|
401 if (pref.locked) { |
|
402 return; |
|
403 } |
|
404 |
|
405 // Boolean inputs blur to remove focus from "button" |
|
406 if (pref.type == Services.prefs.PREF_BOOL) { |
|
407 return; |
|
408 } |
|
409 |
|
410 // String and Int inputs change / commit on blur |
|
411 pref.value = aEvent.target.value; |
|
412 }, |
|
413 |
|
414 // When we reset a pref to it's default value (note resetting a user created pref will delete it) |
|
415 resetDefaultPref: function AC_resetDefaultPref(aEvent) { |
|
416 let node = this.getLINodeForEvent(aEvent); |
|
417 |
|
418 // If not already selected, do so |
|
419 if (this.selected != node) { |
|
420 this.selected = node; |
|
421 } |
|
422 |
|
423 // Reset will handle any locked condition |
|
424 let pref = this._getPrefForNode(node); |
|
425 pref.reset(); |
|
426 }, |
|
427 |
|
428 // When we want to toggle a bool pref |
|
429 toggleBoolPref: function AC_toggleBoolPref(aEvent) { |
|
430 let node = this.getLINodeForEvent(aEvent); |
|
431 |
|
432 // Skip if locked, or not boolean |
|
433 let pref = this._getPrefForNode(node); |
|
434 if (pref.locked) { |
|
435 return; |
|
436 } |
|
437 |
|
438 // Toggle, and blur to remove field focus |
|
439 pref.value = !pref.value; |
|
440 aEvent.target.blur(); |
|
441 }, |
|
442 |
|
443 // When Int inputs have their Up or Down arrows toggled |
|
444 incrOrDecrIntPref: function AC_incrOrDecrIntPref(aEvent, aInt) { |
|
445 let node = this.getLINodeForEvent(aEvent); |
|
446 |
|
447 // Skip if locked |
|
448 let pref = this._getPrefForNode(node); |
|
449 if (pref.locked) { |
|
450 return; |
|
451 } |
|
452 |
|
453 pref.value += aInt; |
|
454 }, |
|
455 |
|
456 // Observe preference changes |
|
457 observe: function AC_observe(aSubject, aTopic, aPrefName) { |
|
458 let pref = new Pref(aPrefName); |
|
459 |
|
460 // Ignore uninteresting changes, and avoid "private" preferences |
|
461 if (aTopic != "nsPref:changed") { |
|
462 return; |
|
463 } |
|
464 |
|
465 // If pref type invalid, refresh display as user reset/removed an item from the list |
|
466 if (pref.type == Services.prefs.PREF_INVALID) { |
|
467 document.location.reload(); |
|
468 return; |
|
469 } |
|
470 |
|
471 // If pref not already in list, refresh display as it's being added |
|
472 let item = document.querySelector(".pref-item[name=" + pref.name.quote() + "]"); |
|
473 if (!item) { |
|
474 document.location.reload(); |
|
475 return; |
|
476 } |
|
477 |
|
478 // Else we're modifying a pref |
|
479 item.setAttribute("value", pref.value); |
|
480 let input = item.querySelector("input"); |
|
481 input.setAttribute("value", pref.value); |
|
482 input.value = pref.value; |
|
483 |
|
484 pref.default ? |
|
485 item.querySelector(".reset").setAttribute("disabled", "true") : |
|
486 item.querySelector(".reset").removeAttribute("disabled"); |
|
487 }, |
|
488 |
|
489 // Quick context menu helpers for about:config |
|
490 clipboardCopy: function AC_clipboardCopy(aField) { |
|
491 let pref = this._getPrefForNode(this.contextMenuLINode); |
|
492 if (aField == 'name') { |
|
493 gClipboardHelper.copyString(pref.name); |
|
494 } else { |
|
495 gClipboardHelper.copyString(pref.value); |
|
496 } |
|
497 } |
|
498 } |
|
499 |
|
500 |
|
501 /* ============================== Pref ============================== |
|
502 * |
|
503 * Individual Preference object / methods |
|
504 * |
|
505 * Defines a Pref object, a document list item tied to Preferences Services |
|
506 * And the methods by which they interact. |
|
507 * |
|
508 */ |
|
509 function Pref(aName) { |
|
510 this.name = aName; |
|
511 } |
|
512 |
|
513 Pref.prototype = { |
|
514 get type() { |
|
515 return Services.prefs.getPrefType(this.name); |
|
516 }, |
|
517 |
|
518 get value() { |
|
519 switch (this.type) { |
|
520 case Services.prefs.PREF_BOOL: |
|
521 return Services.prefs.getBoolPref(this.name); |
|
522 case Services.prefs.PREF_INT: |
|
523 return Services.prefs.getIntPref(this.name); |
|
524 case Services.prefs.PREF_STRING: |
|
525 default: |
|
526 return Services.prefs.getCharPref(this.name); |
|
527 } |
|
528 |
|
529 }, |
|
530 set value(aPrefValue) { |
|
531 switch (this.type) { |
|
532 case Services.prefs.PREF_BOOL: |
|
533 Services.prefs.setBoolPref(this.name, aPrefValue); |
|
534 break; |
|
535 case Services.prefs.PREF_INT: |
|
536 Services.prefs.setIntPref(this.name, aPrefValue); |
|
537 break; |
|
538 case Services.prefs.PREF_STRING: |
|
539 default: |
|
540 Services.prefs.setCharPref(this.name, aPrefValue); |
|
541 } |
|
542 }, |
|
543 |
|
544 get default() { |
|
545 return !Services.prefs.prefHasUserValue(this.name); |
|
546 }, |
|
547 |
|
548 get locked() { |
|
549 return Services.prefs.prefIsLocked(this.name); |
|
550 }, |
|
551 |
|
552 reset: function AC_reset() { |
|
553 Services.prefs.clearUserPref(this.name); |
|
554 }, |
|
555 |
|
556 test: function AC_test(aValue) { |
|
557 return aValue ? aValue.test(this.name) : true; |
|
558 }, |
|
559 |
|
560 // Get existing or create new LI node for the pref |
|
561 getOrCreateNewLINode: function AC_getOrCreateNewLINode() { |
|
562 if (!this.li) { |
|
563 this.li = document.createElement("li"); |
|
564 |
|
565 this.li.className = "pref-item"; |
|
566 this.li.setAttribute("name", this.name); |
|
567 |
|
568 // Click callback to ensure list item selected even on no-action tap events |
|
569 this.li.addEventListener("click", |
|
570 function(aEvent) { |
|
571 AboutConfig.selected = AboutConfig.getLINodeForEvent(aEvent); |
|
572 }, |
|
573 false |
|
574 ); |
|
575 |
|
576 // Contextmenu callback to identify selected list item |
|
577 this.li.addEventListener("contextmenu", |
|
578 function(aEvent) { |
|
579 AboutConfig.contextMenuLINode = AboutConfig.getLINodeForEvent(aEvent); |
|
580 }, |
|
581 false |
|
582 ); |
|
583 |
|
584 this.li.setAttribute("contextmenu", "prefs-context-menu"); |
|
585 |
|
586 // Create list item outline, bind to object actions |
|
587 this.li.innerHTML = |
|
588 "<div class='pref-name' " + |
|
589 "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" + |
|
590 this.name + |
|
591 "</div>" + |
|
592 "<div class='pref-item-line'>" + |
|
593 "<input class='pref-value' value='' " + |
|
594 "onblur='AboutConfig.setIntOrStringPref(event);' " + |
|
595 "onclick='AboutConfig.selectOrToggleBoolPref(event);'>" + |
|
596 "</input>" + |
|
597 "<div class='pref-button reset' " + |
|
598 "onclick='AboutConfig.resetDefaultPref(event);'>" + |
|
599 gStringBundle.GetStringFromName("pref.resetButton") + |
|
600 "</div>" + |
|
601 "<div class='pref-button toggle' " + |
|
602 "onclick='AboutConfig.toggleBoolPref(event);'>" + |
|
603 gStringBundle.GetStringFromName("pref.toggleButton") + |
|
604 "</div>" + |
|
605 "<div class='pref-button up' " + |
|
606 "onclick='AboutConfig.incrOrDecrIntPref(event, 1);'>" + |
|
607 "</div>" + |
|
608 "<div class='pref-button down' " + |
|
609 "onclick='AboutConfig.incrOrDecrIntPref(event, -1);'>" + |
|
610 "</div>" + |
|
611 "</div>"; |
|
612 |
|
613 // Delay providing the list item values, until the LI is returned and added to the document |
|
614 setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY); |
|
615 } |
|
616 |
|
617 return this.li; |
|
618 }, |
|
619 |
|
620 // Initialize list item object values |
|
621 _valueSetup: function AC_valueSetup() { |
|
622 |
|
623 this.li.setAttribute("type", this.type); |
|
624 this.li.setAttribute("value", this.value); |
|
625 |
|
626 let valDiv = this.li.querySelector(".pref-value"); |
|
627 valDiv.value = this.value; |
|
628 |
|
629 switch(this.type) { |
|
630 case Services.prefs.PREF_BOOL: |
|
631 valDiv.setAttribute("type", "button"); |
|
632 this.li.querySelector(".up").setAttribute("disabled", true); |
|
633 this.li.querySelector(".down").setAttribute("disabled", true); |
|
634 break; |
|
635 case Services.prefs.PREF_STRING: |
|
636 valDiv.setAttribute("type", "text"); |
|
637 this.li.querySelector(".up").setAttribute("disabled", true); |
|
638 this.li.querySelector(".down").setAttribute("disabled", true); |
|
639 this.li.querySelector(".toggle").setAttribute("disabled", true); |
|
640 break; |
|
641 case Services.prefs.PREF_INT: |
|
642 valDiv.setAttribute("type", "number"); |
|
643 this.li.querySelector(".toggle").setAttribute("disabled", true); |
|
644 break; |
|
645 } |
|
646 |
|
647 this.li.setAttribute("default", this.default); |
|
648 if (this.default) { |
|
649 this.li.querySelector(".reset").setAttribute("disabled", true); |
|
650 } |
|
651 |
|
652 if (this.locked) { |
|
653 valDiv.setAttribute("disabled", this.locked); |
|
654 this.li.querySelector(".pref-name").setAttribute("locked", true); |
|
655 } |
|
656 } |
|
657 } |
|
658 |