mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
a5593b77b9
r=sayrer
265 lines
9.2 KiB
JavaScript
Executable File
265 lines
9.2 KiB
JavaScript
Executable File
/*
|
|
#ifdef 0
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Content Preferences (cpref).
|
|
*
|
|
* The Initial Developer of the Original Code is Mozilla.
|
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Myk Melez <myk@mozilla.org>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK *****
|
|
#endif
|
|
*/
|
|
|
|
/**
|
|
* Listens for site-specific pref-related events and dispatches them
|
|
* to setting controllers.
|
|
*/
|
|
|
|
var ContentPrefSink = {
|
|
//**************************************************************************//
|
|
// Convenience Getters
|
|
|
|
// Content Pref Service
|
|
__cps: null,
|
|
get _cps() {
|
|
if (!this.__cps)
|
|
this.__cps = Cc["@mozilla.org/content-pref/service;1"].
|
|
getService(Ci.nsIContentPrefService);
|
|
return this.__cps;
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// nsISupports
|
|
|
|
// Note: we can't use the Ci shortcut here because it isn't defined yet.
|
|
interfaces: [Components.interfaces.nsIDOMEventListener,
|
|
Components.interfaces.nsISupports],
|
|
|
|
QueryInterface: function ContentPrefSink_QueryInterface(iid) {
|
|
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
|
|
throw Cr.NS_ERROR_NO_INTERFACE;
|
|
return this;
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// Initialization & Destruction
|
|
|
|
init: function ContentPrefSink_init() {
|
|
gBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
|
gBrowser.addEventListener("DOMContentLoaded", this, false);
|
|
// XXX Should we also listen for pageshow and/or load?
|
|
},
|
|
|
|
destroy: function ContentPrefSink_destroy() {
|
|
gBrowser.removeEventListener("DOMContentLoaded", this, false);
|
|
gBrowser.removeProgressListener(this);
|
|
|
|
// Delete references to XPCOM components to make sure we don't leak them
|
|
// (although we haven't observed leakage in tests). Also delete references
|
|
// in _observers and _genericObservers to avoid cycles with those that
|
|
// refer to us and don't remove themselves from those observer pools.
|
|
for (var i in this) {
|
|
try { this[i] = null }
|
|
// Ignore "setting a property that has only a getter" exceptions.
|
|
catch(ex) {}
|
|
}
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// Event Handlers
|
|
|
|
// nsIWebProgressListener
|
|
|
|
onLocationChange: function ContentPrefSink_onLocationChange(progress, request, uri) {
|
|
// Catch exceptions until bug 376222 gets fixed so that we don't hork
|
|
// other progress listeners if our code throws an exception.
|
|
try {
|
|
this._handleLocationChanged(uri);
|
|
}
|
|
catch(ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
},
|
|
onStateChange: function ContentPrefSink_onStateChange(progress, request, flags, status) {},
|
|
onProgressChange: function ContentPrefSink_onProgressChange(progress, request, curSelfProgress,
|
|
maxSelfProgress, curTotalProgress,
|
|
maxTotalProgress) {},
|
|
onStatusChange: function ContentPrefSink_onStatusChange(progress, request, status, message) {},
|
|
onSecurityChange: function ContentPrefSink_onSecurityChange(progress, request, state) {},
|
|
|
|
// nsIDOMEventListener
|
|
|
|
handleEvent: function ContentPrefSink_handleEvent(event) {
|
|
// The only events we handle are DOMContentLoaded events.
|
|
this._handleDOMContentLoaded(event);
|
|
},
|
|
|
|
_handleLocationChanged: function ContentPrefSink__handleLocationChanged(uri) {
|
|
if (!uri)
|
|
return;
|
|
|
|
var prefs = this._cps.getPrefs(uri);
|
|
|
|
for (var name in this._observers) {
|
|
var value = prefs.hasKey(name) ? prefs.get(name) : undefined;
|
|
for each (var observer in this._observers[name])
|
|
if (observer.onLocationChanged) {
|
|
try {
|
|
observer.onLocationChanged(uri, name, value);
|
|
}
|
|
catch(ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
for each (var observer in this._genericObservers)
|
|
if (observer.onLocationChanged) {
|
|
try {
|
|
observer.onLocationChanged(uri, prefs);
|
|
}
|
|
catch(ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
}
|
|
},
|
|
|
|
_handleDOMContentLoaded: function ContentPrefSink__handleDOMContentLoaded(event) {
|
|
var browser = gBrowser.getBrowserForDocument(event.target);
|
|
// If the document isn't one of the ones loaded into a top-level browser,
|
|
// don't notify observers about it. XXX Might some observers want to know
|
|
// about documents loaded into iframes?
|
|
if (!browser)
|
|
return;
|
|
var uri = browser.currentURI;
|
|
|
|
var prefs = this._cps.getPrefs(uri);
|
|
|
|
for (var name in this._observers) {
|
|
var value = prefs.hasKey(name) ? prefs.get(name) : undefined;
|
|
for each (var observer in this._observers[name]) {
|
|
if (observer.onDOMContentLoaded) {
|
|
try {
|
|
observer.onDOMContentLoaded(event, name, value);
|
|
}
|
|
catch(ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for each (var observer in this._genericObservers) {
|
|
if (observer.onDOMContentLoaded) {
|
|
try {
|
|
observer.onDOMContentLoaded(event, prefs);
|
|
}
|
|
catch(ex) {
|
|
Components.utils.reportError(ex);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
//**************************************************************************//
|
|
// Sink Observers
|
|
|
|
_observers: {},
|
|
_genericObservers: [],
|
|
|
|
// Note: this isn't an XPCOM interface (for performance and so we can pass
|
|
// nsIVariants), although it resembles nsIObserverService. Sink observers
|
|
// are regular JS objects, and they get called directly, not via XPConnect.
|
|
|
|
/**
|
|
* Add an observer.
|
|
*
|
|
* The observer can be setting-specific or generic, which affects what it
|
|
* gets handed when the sink notifies it about an event. A setting-specific
|
|
* observer gets handed the value of its pref for the target page, while
|
|
* a generic observer gets handed the values of all prefs for the target page.
|
|
*
|
|
* @param name the name of the setting for which to add an observer,
|
|
* or null to add a generic observer
|
|
* @param observer the observer to add
|
|
*
|
|
* @returns if setting-specific, the global preference for the setting
|
|
* if generic, null
|
|
*/
|
|
addObserver: function ContentPrefSink_addObserver(name, observer) {
|
|
var observers;
|
|
if (name) {
|
|
if (!this._observers[name])
|
|
this._observers[name] = [];
|
|
observers = this._observers[name];
|
|
}
|
|
else
|
|
observers = this._genericObservers;
|
|
|
|
if (observers.indexOf(observer) == -1)
|
|
observers.push(observer);
|
|
|
|
return name ? this._cps.getPref(null, name) : null;
|
|
},
|
|
|
|
/**
|
|
* Remove an observer.
|
|
*
|
|
* @param name the name of the setting for which to remove
|
|
* an observer, or null to remove a generic observer
|
|
* @param observer the observer to remove
|
|
*/
|
|
removeObserver: function ContentPrefSink_removeObserver(name, observer) {
|
|
var observers = name ? this._observers[name] : this._genericObservers;
|
|
if (observers.indexOf(observer) != -1)
|
|
observers.splice(observers.indexOf(observer), 1);
|
|
},
|
|
|
|
_getObservers: function ContentPrefSink__getObservers(name) {
|
|
var observers = [];
|
|
|
|
// Construct the list of observers, putting setting-specific ones before
|
|
// generic ones, so observers that initialize individual settings (like
|
|
// the page style controller) execute before observers that do something
|
|
// with multiple settings and depend on them being initialized first
|
|
// (f.e. the content prefs sidebar).
|
|
if (name && this._observers[name])
|
|
observers = observers.concat(this._observers[name]);
|
|
observers = observers.concat(this._genericObservers);
|
|
|
|
return observers;
|
|
}
|
|
};
|