extApplication.js
Go to the documentation of this file.
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is FUEL.
15  *
16  * The Initial Developer of the Original Code is Mozilla Corporation.
17  * Portions created by the Initial Developer are Copyright (C) 2006
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Mark Finkle <mfinkle@mozilla.com> (Original Author)
22  * John Resig <jresig@mozilla.com> (Original Author)
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37 
38 //=================================================
39 // Shutdown - used to store cleanup functions which will
40 // be called on Application shutdown
41 var gShutdown = [];
42 
43 //=================================================
44 // Console constructor
45 function Console() {
46  this._console = Components.classes["@mozilla.org/consoleservice;1"]
47  .getService(Ci.nsIConsoleService);
48 }
49 
50 //=================================================
51 // Console implementation
52 Console.prototype = {
53  log : function cs_log(aMsg) {
54  this._console.logStringMessage(aMsg);
55  },
56 
57  open : function cs_open() {
58  var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
59  .getService(Ci.nsIWindowMediator);
60  var console = wMediator.getMostRecentWindow("global:console");
61  if (!console) {
62  var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
63  .getService(Ci.nsIWindowWatcher);
64  wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
65  "chrome,dialog=no,all", null);
66  } else {
67  // console was already open
68  console.focus();
69  }
70  },
71 
72  QueryInterface : XPCOMUtils.generateQI([Ci.extIConsole])
73 };
74 
75 
76 //=================================================
77 // EventItem constructor
78 function EventItem(aType, aData) {
79  this._type = aType;
80  this._data = aData;
81 }
82 
83 //=================================================
84 // EventItem implementation
85 EventItem.prototype = {
86  _cancel : false,
87 
88  get type() {
89  return this._type;
90  },
91 
92  get data() {
93  return this._data;
94  },
95 
96  preventDefault : function ei_pd() {
97  this._cancel = true;
98  },
99 
100  QueryInterface : XPCOMUtils.generateQI([Ci.extIEventItem])
101 };
102 
103 
104 //=================================================
105 // Events constructor
106 function Events() {
107  this._listeners = [];
108 }
109 
110 //=================================================
111 // Events implementation
112 Events.prototype = {
113  addListener : function evts_al(aEvent, aListener) {
114  if (this._listeners.some(hasFilter))
115  return;
116 
117  this._listeners.push({
118  event: aEvent,
119  listener: aListener
120  });
121 
122  function hasFilter(element) {
123  return element.event == aEvent && element.listener == aListener;
124  }
125  },
126 
127  removeListener : function evts_rl(aEvent, aListener) {
128  this._listeners = this._listeners.filter(hasFilter);
129 
130  function hasFilter(element) {
131  return (element.event != aEvent) || (element.listener != aListener);
132  }
133  },
134 
135  dispatch : function evts_dispatch(aEvent, aEventItem) {
136  eventItem = new EventItem(aEvent, aEventItem);
137 
138  this._listeners.forEach(function(key){
139  if (key.event == aEvent) {
140  key.listener.handleEvent ?
141  key.listener.handleEvent(eventItem) :
142  key.listener(eventItem);
143  }
144  });
145 
146  return !eventItem._cancel;
147  },
148 
149  QueryInterface : XPCOMUtils.generateQI([Ci.extIEvents])
150 };
151 
152 
153 //=================================================
154 // PreferenceBranch constructor
155 function PreferenceBranch(aBranch) {
156  if (!aBranch)
157  aBranch = "";
158 
159  this._root = aBranch;
160  this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
161  .getService(Ci.nsIPrefService);
162 
163  if (aBranch)
164  this._prefs = this._prefs.getBranch(aBranch);
165 
166  this._prefs.QueryInterface(Ci.nsIPrefBranch);
167  this._prefs.QueryInterface(Ci.nsIPrefBranch2);
168 
169  // we want to listen to "all" changes for this branch, so pass in a blank domain
170  this._prefs.addObserver("", this, true);
171  this._events = new Events();
172 
173  var self = this;
174  gShutdown.push(function() { self._shutdown(); });
175 }
176 
177 //=================================================
178 // PreferenceBranch implementation
179 PreferenceBranch.prototype = {
180  // cleanup observer so we don't leak
181  _shutdown: function prefs_shutdown() {
182  this._prefs.removeObserver(this._root, this);
183 
184  this._prefs = null;
185  this._events = null;
186  },
187 
188  // for nsIObserver
189  observe: function prefs_observe(aSubject, aTopic, aData) {
190  if (aTopic == "nsPref:changed")
191  this._events.dispatch("change", aData);
192  },
193 
194  get root() {
195  return this._root;
196  },
197 
198  get all() {
199  return this.find({});
200  },
201 
202  get events() {
203  return this._events;
204  },
205 
206  // XXX: Disabled until we can figure out the wrapped object issues
207  // name: "name" or /name/
208  // path: "foo.bar." or "" or /fo+\.bar/
209  // type: Boolean, Number, String (getPrefType)
210  // locked: true, false (prefIsLocked)
211  // modified: true, false (prefHasUserValue)
212  find : function prefs_find(aOptions) {
213  var retVal = [];
214  var items = this._prefs.getChildList("", []);
215 
216  for (var i = 0; i < items.length; i++) {
217  retVal.push(new Preference(items[i], this));
218  }
219 
220  return retVal;
221  },
222 
223  has : function prefs_has(aName) {
224  return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID);
225  },
226 
227  get : function prefs_get(aName) {
228  return this.has(aName) ? new Preference(aName, this) : null;
229  },
230 
231  getValue : function prefs_gv(aName, aValue) {
232  var type = this._prefs.getPrefType(aName);
233 
234  switch (type) {
235  case Ci.nsIPrefBranch2.PREF_STRING:
236  aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data;
237  break;
238  case Ci.nsIPrefBranch2.PREF_BOOL:
239  aValue = this._prefs.getBoolPref(aName);
240  break;
241  case Ci.nsIPrefBranch2.PREF_INT:
242  aValue = this._prefs.getIntPref(aName);
243  break;
244  }
245 
246  return aValue;
247  },
248 
249  setValue : function prefs_sv(aName, aValue) {
250  var type = aValue != null ? aValue.constructor.name : "";
251 
252  switch (type) {
253  case "String":
254  var str = Components.classes["@mozilla.org/supports-string;1"]
255  .createInstance(Ci.nsISupportsString);
256  str.data = aValue;
257  this._prefs.setComplexValue(aName, Ci.nsISupportsString, str);
258  break;
259  case "Boolean":
260  this._prefs.setBoolPref(aName, aValue);
261  break;
262  case "Number":
263  this._prefs.setIntPref(aName, aValue);
264  break;
265  default:
266  throw("Unknown preference value specified.");
267  }
268  },
269 
270  reset : function prefs_reset() {
271  this._prefs.resetBranch("");
272  },
273 
274  QueryInterface : XPCOMUtils.generateQI([Ci.extIPreferenceBranch, Ci.nsISupportsWeakReference])
275 };
276 
277 
278 //=================================================
279 // Preference constructor
280 function Preference(aName, aBranch) {
281  this._name = aName;
282  this._branch = aBranch;
283  this._events = new Events();
284 
285  var self = this;
286 
287  this.branch.events.addListener("change", function(aEvent){
288  if (aEvent.data == self.name)
289  self.events.dispatch(aEvent.type, aEvent.data);
290  });
291 }
292 
293 //=================================================
294 // Preference implementation
295 Preference.prototype = {
296  get name() {
297  return this._name;
298  },
299 
300  get type() {
301  var value = "";
302  var type = this.branch._prefs.getPrefType(this._name);
303 
304  switch (type) {
305  case Ci.nsIPrefBranch2.PREF_STRING:
306  value = "String";
307  break;
308  case Ci.nsIPrefBranch2.PREF_BOOL:
309  value = "Boolean";
310  break;
311  case Ci.nsIPrefBranch2.PREF_INT:
312  value = "Number";
313  break;
314  }
315 
316  return value;
317  },
318 
319  get value() {
320  return this.branch.getValue(this._name, null);
321  },
322 
323  set value(aValue) {
324  return this.branch.setValue(this._name, aValue);
325  },
326 
327  get locked() {
328  return this.branch._prefs.prefIsLocked(this.name);
329  },
330 
331  set locked(aValue) {
332  this.branch._prefs[ aValue ? "lockPref" : "unlockPref" ](this.name);
333  },
334 
335  get modified() {
336  return this.branch._prefs.prefHasUserValue(this.name);
337  },
338 
339  get branch() {
340  return this._branch;
341  },
342 
343  get events() {
344  return this._events;
345  },
346 
347  reset : function pref_reset() {
348  this.branch._prefs.clearUserPref(this.name);
349  },
350 
351  QueryInterface : XPCOMUtils.generateQI([Ci.extIPreference])
352 };
353 
354 
355 //=================================================
356 // SessionStorage constructor
357 function SessionStorage() {
358  this._storage = {};
359  this._events = new Events();
360 }
361 
362 //=================================================
363 // SessionStorage implementation
364 SessionStorage.prototype = {
365  get events() {
366  return this._events;
367  },
368 
369  has : function ss_has(aName) {
370  return this._storage.hasOwnProperty(aName);
371  },
372 
373  set : function ss_set(aName, aValue) {
374  this._storage[aName] = aValue;
375  this._events.dispatch("change", aName);
376  },
377 
378  get : function ss_get(aName, aDefaultValue) {
379  return this.has(aName) ? this._storage[aName] : aDefaultValue;
380  },
381 
382  QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage])
383 };
384 
385 
386 //=================================================
387 // Extension constructor
388 function Extension(aItem) {
389  this._item = aItem;
390  this._firstRun = false;
391  this._prefs = new PreferenceBranch("extensions." + this._item.id + ".");
392  this._storage = new SessionStorage();
393  this._events = new Events();
394 
395  var installPref = "install-event-fired";
396  if (!this._prefs.has(installPref)) {
397  this._prefs.setValue(installPref, true);
398  this._firstRun = true;
399  }
400 
401  this._enabled = false;
402  const PREFIX_ITEM_URI = "urn:mozilla:item:";
403  const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
404  var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
405  var itemResource = rdf.GetResource(PREFIX_ITEM_URI + this._item.id);
406  if (itemResource) {
407  var extmgr = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
408  var ds = extmgr.datasource;
409  var target = ds.GetTarget(itemResource, rdf.GetResource(PREFIX_NS_EM + "isDisabled"), true);
410  if (target && target instanceof Ci.nsIRDFLiteral)
411  this._enabled = (target.Value != "true");
412  }
413 
414  var os = Components.classes["@mozilla.org/observer-service;1"]
415  .getService(Ci.nsIObserverService);
416  os.addObserver(this, "em-action-requested", false);
417 
418  var self = this;
419  gShutdown.push(function(){ self._shutdown(); });
420 }
421 
422 //=================================================
423 // Extension implementation
424 Extension.prototype = {
425  // cleanup observer so we don't leak
426  _shutdown: function ext_shutdown() {
427  var os = Components.classes["@mozilla.org/observer-service;1"]
428  .getService(Ci.nsIObserverService);
429  os.removeObserver(this, "em-action-requested");
430 
431  this._prefs = null;
432  this._storage = null;
433  this._events = null;
434  },
435 
436  // for nsIObserver
437  observe: function ext_observe(aSubject, aTopic, aData)
438  {
439  if ((aSubject instanceof Ci.nsIUpdateItem) && (aSubject.id == this._item.id))
440  {
441  if (aData == "item-uninstalled")
442  this._events.dispatch("uninstall", this._item.id);
443  else if (aData == "item-disabled")
444  this._events.dispatch("disable", this._item.id);
445  else if (aData == "item-enabled")
446  this._events.dispatch("enable", this._item.id);
447  else if (aData == "item-cancel-action")
448  this._events.dispatch("cancel", this._item.id);
449  else if (aData == "item-upgraded")
450  this._events.dispatch("upgrade", this._item.id);
451  }
452  },
453 
454  get id() {
455  return this._item.id;
456  },
457 
458  get name() {
459  return this._item.name;
460  },
461 
462  get enabled() {
463  return this._enabled;
464  },
465 
466  get version() {
467  return this._item.version;
468  },
469 
470  get firstRun() {
471  return this._firstRun;
472  },
473 
474  get storage() {
475  return this._storage;
476  },
477 
478  get prefs() {
479  return this._prefs;
480  },
481 
482  get events() {
483  return this._events;
484  },
485 
486  QueryInterface : XPCOMUtils.generateQI([Ci.extIExtension])
487 };
488 
489 
490 //=================================================
491 // Extensions constructor
492 function Extensions() {
493  this._extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
494  .getService(Ci.nsIExtensionManager);
495 
496  this._cache = {};
497 
498  var self = this;
499  gShutdown.push(function() { self._shutdown(); });
500 }
501 
502 //=================================================
503 // Extensions implementation
504 Extensions.prototype = {
505  _shutdown : function exts_shutdown() {
506  this._extmgr = null;
507  this._cache = null;
508  },
509 
510  /*
511  * Helper method to check cache before creating a new extension
512  */
513  _get : function exts_get(aId) {
514  if (this._cache.hasOwnProperty(aId))
515  return this._cache[aId];
516 
517  var newExt = new Extension(this._extmgr.getItemForID(aId));
518  this._cache[aId] = newExt;
519  return newExt;
520  },
521 
522  get all() {
523  return this.find({});
524  },
525 
526  // XXX: Disabled until we can figure out the wrapped object issues
527  // id: "some@id" or /id/
528  // name: "name" or /name/
529  // version: "1.0.1"
530  // minVersion: "1.0"
531  // maxVersion: "2.0"
532  find : function exts_find(aOptions) {
533  var retVal = [];
534  var items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
535 
536  for (var i = 0; i < items.length; i++) {
537  retVal.push(this._get(items[i].id));
538  }
539 
540  return retVal;
541  },
542 
543  has : function exts_has(aId) {
544  return this._extmgr.getItemForID(aId) != null;
545  },
546 
547  get : function exts_get(aId) {
548  return this.has(aId) ? this._get(aId) : null;
549  },
550 
551  QueryInterface : XPCOMUtils.generateQI([Ci.extIExtensions])
552 };
553 
554 //=================================================
555 // extApplication constructor
556 function extApplication() {
557 }
558 
559 //=================================================
560 // extApplication implementation
561 extApplication.prototype = {
562  initToolkitHelpers: function extApp_initToolkitHelpers() {
563  this._console = null;
564  this._storage = null;
565  this._prefs = null;
566  this._extensions = null;
567  this._events = null;
568 
569  this._info = Components.classes["@mozilla.org/xre/app-info;1"]
570  .getService(Ci.nsIXULAppInfo);
571 
572  var os = Components.classes["@mozilla.org/observer-service;1"]
573  .getService(Ci.nsIObserverService);
574 
575  os.addObserver(this, "final-ui-startup", false);
576  os.addObserver(this, "quit-application-requested", false);
577  os.addObserver(this, "xpcom-shutdown", false);
578  },
579 
580  // get this contractID registered for certain categories via XPCOMUtils
582  // make Application a startup observer
583  { category: "app-startup", service: true },
584 
585  // add Application as a global property for easy access
586  { category: "JavaScript global privileged property" }
587  ],
588 
589  // for nsIClassInfo
590  flags : Ci.nsIClassInfo.SINGLETON,
591  implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
592 
593  getInterfaces : function app_gi(aCount) {
594  var interfaces = [Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
595  aCount.value = interfaces.length;
596  return interfaces;
597  },
598 
599  getHelperForLanguage : function app_ghfl(aCount) {
600  return null;
601  },
602 
603  // extIApplication
604  get id() {
605  return this._info.ID;
606  },
607 
608  get name() {
609  return this._info.name;
610  },
611 
612  get version() {
613  return this._info.version;
614  },
615 
616  // for nsIObserver
617  observe: function app_observe(aSubject, aTopic, aData) {
618  if (aTopic == "app-startup") {
619  this.events.dispatch("load", "application");
620  }
621  else if (aTopic == "final-ui-startup") {
622  this.events.dispatch("ready", "application");
623  }
624  else if (aTopic == "quit-application-requested") {
625  // we can stop the quit by checking the return value
626  if (this.events.dispatch("quit", "application") == false)
627  aSubject.data = true;
628  }
629  else if (aTopic == "xpcom-shutdown") {
630 
631  this.events.dispatch("unload", "application");
632 
633  // call the cleanup functions and empty the array
634  while (gShutdown.length) {
635  gShutdown.shift()();
636  }
637 
638  // release our observers
639  var os = Components.classes["@mozilla.org/observer-service;1"]
640  .getService(Ci.nsIObserverService);
641 
642  os.removeObserver(this, "final-ui-startup");
643  os.removeObserver(this, "quit-application-requested");
644  os.removeObserver(this, "xpcom-shutdown");
645 
646  this._info = null;
647  this._console = null;
648  this._prefs = null;
649  this._storage = null;
650  this._events = null;
651  this._extensions = null;
652  }
653  },
654 
655  get console() {
656  if (this._console == null)
657  this._console = new Console();
658 
659  return this._console;
660  },
661 
662  get storage() {
663  if (this._storage == null)
664  this._storage = new SessionStorage();
665 
666  return this._storage;
667  },
668 
669  get prefs() {
670  if (this._prefs == null)
671  this._prefs = new PreferenceBranch("");
672 
673  return this._prefs;
674  },
675 
676  get extensions() {
677  if (this._extensions == null)
678  this._extensions = new Extensions();
679 
680  return this._extensions;
681  },
682 
683  get events() {
684  if (this._events == null)
685  this._events = new Events();
686 
687  return this._events;
688  },
689 
690  // helper method for correct quitting/restarting
691  _quitWithFlags: function app__quitWithFlags(aFlags) {
692  let os = Components.classes["@mozilla.org/observer-service;1"]
693  .getService(Components.interfaces.nsIObserverService);
694  let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
695  .createInstance(Components.interfaces.nsISupportsPRBool);
696  os.notifyObservers(cancelQuit, "quit-application-requested", null);
697  if (cancelQuit.data)
698  return false; // somebody canceled our quit request
699 
700  let appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1']
701  .getService(Components.interfaces.nsIAppStartup);
702  appStartup.quit(aFlags);
703  return true;
704  },
705 
706  quit: function app_quit() {
707  return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit);
708  },
709 
710  restart: function app_restart() {
711  return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit |
712  Components.interfaces.nsIAppStartup.eRestart);
713  },
714 
715  QueryInterface : XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference])
716 };
const Cc
function EventItem(aType, aData)
id service()
menuItem id
Definition: FeedWriter.js:971
onPageChanged aValue
Definition: FeedWriter.js:1395
function Console()
function log(s)
sbDeviceFirmwareAutoCheckForUpdate prototype flags
function Extensions()
Element Properties events
sbOSDControlService prototype QueryInterface
const PREFIX_NS_EM
version(170)
mashTape firstRun
Definition: mashTape.js:48
function SessionStorage()
sbDeviceFirmwareAutoCheckForUpdate prototype getHelperForLanguage
BogusChannel prototype open
datepicker _get(inst,'showOptions')
var gShutdown
const PREFIX_ITEM_URI
return null
Definition: FeedWriter.js:1143
function PreferenceBranch(aBranch)
function Events()
var os
_updateCookies aName
var prefs
Definition: FeedWriter.js:1169
countRef value
Definition: FeedWriter.js:1423
Sanitizer _prefs
Definition: sanitize.js:435
const Ci
restoreHistoryPrecursor aCount
sbWindowsAutoPlayServiceCfg _xpcom_categories
sbDeviceFirmwareAutoCheckForUpdate prototype getInterfaces
sbDeviceFirmwareAutoCheckForUpdate prototype interfaces
classDescription implementationLanguage
Definition: FeedWriter.js:1427
observe data
Definition: FeedWriter.js:1329
window addListener("unload", function(){window.removeListener("unload", arguments.callee);document.purge();if(Browser.Engine.trident){CollectGarbage();}})
_getSelectedPageStyle s i
function extApplication()
_updateTextAndScrollDataForFrame aData
sbDeviceFirmwareAutoCheckForUpdate prototype observe
function Extension(aItem)
function Preference(aName, aBranch)