www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

word-processor-plugin-installer.js (9296B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3 	
      4 	Copyright (c) 2009  Zotero
      5 	                    Center for History and New Media
      6 						George Mason University, Fairfax, Virginia, USA
      7 						http://zotero.org
      8 	
      9 	Zotero is free software: you can redistribute it and/or modify
     10 	it under the terms of the GNU Affero General Public License as published by
     11 	the Free Software Foundation, either version 3 of the License, or
     12 	(at your option) any later version.
     13 	
     14 	Zotero is distributed in the hope that it will be useful,
     15 	but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 	GNU Affero General Public License for more details.
     18 	
     19 	You should have received a copy of the GNU Affero General Public License
     20 	along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     21     
     22     ***** END LICENSE BLOCK *****
     23 */
     24 
     25 /**
     26  * A common installer interface used by word processor plugins to make themselves
     27  * installable and available in the cite preferences pane.
     28  */
     29 
     30 EXPORTED_SYMBOLS = ["ZoteroPluginInstaller"];
     31 
     32 var Zotero = Components.classes["@zotero.org/Zotero;1"]
     33 				// Currently uses only nsISupports
     34 				//.getService(Components.interfaces.chnmIZoteroService).
     35 				.getService(Components.interfaces.nsISupports)
     36 				.wrappedJSObject;
     37 
     38 Components.utils.import("resource://gre/modules/Services.jsm");
     39 Components.utils.import("resource://gre/modules/AddonManager.jsm");
     40 
     41 var installationInProgress = false;
     42 var _runningTimers = [];
     43 function setTimeout(func, ms) {
     44 	var timer = Components.classes["@mozilla.org/timer;1"].
     45 		createInstance(Components.interfaces.nsITimer);
     46 	var timerCallback = {notify: function() {
     47 		_runningTimers.splice(_runningTimers.indexOf(timer), 1);
     48 		func();
     49 	}};
     50 	timer.initWithCallback(timerCallback, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
     51 	// add timer to global scope so that it doesn't get garbage collected before it completes
     52 	_runningTimers.push(timer);
     53 }
     54 
     55 var ZoteroPluginInstaller = function(addon, failSilently, force) {
     56 	this._addon = addon;
     57 	this.failSilently = failSilently;
     58 	this.force = force;
     59 	
     60 	var prefService = Components.classes["@mozilla.org/preferences-service;1"].
     61 			getService(Components.interfaces.nsIPrefService);
     62 	this.prefBranch = prefService.getBranch(this._addon.EXTENSION_PREF_BRANCH);
     63 
     64 	this.prefPaneDoc = null;
     65 	
     66 	var me = this;
     67 	var extensionIDs = [this._addon.EXTENSION_ID].concat(this._addon.REQUIRED_ADDONS.map(req => req.id));
     68 	Zotero.debug("PluginInstaller: fetching addon info");
     69 	AddonManager.getAddonsByIDs(extensionIDs, function(addons) {
     70 		Zotero.debug("PluginInstaller: addon info fetched");
     71 		me._addonInfo = addons[0];
     72 		me._addonInfoAvailable();
     73 	});
     74 };
     75 
     76 ZoteroPluginInstaller.prototype = {
     77 	_errorDisplayed: false,
     78 	
     79 	_addonInfoAvailable: function() {
     80 		try {
     81 			this._version = this._addonInfo.version;
     82 			
     83 			try {
     84 				this._addon.verifyNotCorrupt(this);
     85 			} catch(e) {
     86 				Zotero.debug("Not installing +this._addon.EXTENSION_STRING+:  "+e.toString());
     87 				return;
     88 			}
     89 			
     90 			var version = this.prefBranch.getCharPref("version");			
     91 			if(this.force || (
     92 					(
     93 						Services.vc.compare(version, this._addon.LAST_INSTALLED_FILE_UPDATE) < 0
     94 						|| (!Zotero.isStandalone && !this.prefBranch.getBoolPref("installed"))
     95 					)
     96 					&& !this.prefBranch.getBoolPref("skipInstallation")
     97 				)) {
     98 					
     99 				var me = this;
    100 				if (installationInProgress) {
    101 					Zotero.debug(`${this._addon.APP} extension installation is already in progress`);
    102 					return;
    103 				}
    104 				
    105 				installationInProgress = true;
    106 				if(!this._addon.DISABLE_PROGRESS_WINDOW) {
    107 					this._progressWindow = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
    108 						.getService(Components.interfaces.nsIWindowWatcher)
    109 						.openWindow(null, "chrome://"+this._addon.EXTENSION_DIR+"/content/progress.xul", '',
    110 							"chrome,resizable=no,close=no,centerscreen", null);	
    111 					this._progressWindow.addEventListener("load", function() { me._firstRunListener() }, false);
    112 				} else {
    113 					this._addon.install(this);
    114 				}
    115 			}
    116 		} catch(e) {
    117 			Zotero.logError(e);
    118 		} finally {
    119 			installationInProgress = false;
    120 		}
    121 	},
    122 	
    123 	isInstalled: function() {
    124 		while(!this._version) Zotero.mainThread.processNextEvent(true);
    125 		return this.prefBranch.getCharPref("version") == this._version && 
    126 			this.prefBranch.getBoolPref("installed");
    127 	},
    128 	
    129 	getAddonPath: function(addonID) {
    130 		return this._addonInfo.getResourceURI().
    131 			QueryInterface(Components.interfaces.nsIFileURL).file;
    132 	},
    133 	
    134 	setProgressWindowLabel: function(value) {
    135 		if(this._progressWindow) this._progressWindowLabel.value = value;
    136 	},
    137 	
    138 	closeProgressWindow: function(value) {
    139 		if(this._progressWindow) this._progressWindow.close();
    140 	},
    141 	
    142 	success: function() {
    143 		installationInProgress = false;
    144 		this.closeProgressWindow();
    145 		this.prefBranch.setCharPref("version", this._version);
    146 		this.updateInstallStatus(true);
    147 		this.prefBranch.setBoolPref("skipInstallation", false);
    148 		if(this.force && !this._addon.DISABLE_PROGRESS_WINDOW) {
    149 			var addon = this._addon;
    150 			setTimeout(function() {
    151 				Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
    152 					.getService(Components.interfaces.nsIPromptService)
    153 					.alert(null, addon.EXTENSION_STRING,
    154 					Zotero.getString("zotero.preferences.wordProcessors.installationSuccess"));
    155 			}, 0);
    156 		}
    157 	},
    158 	
    159 	error: function(error, notFailure) {
    160 		installationInProgress = false;
    161 		this.closeProgressWindow();
    162 		if(!notFailure) {
    163 			this.prefBranch.setCharPref("version", this._version);
    164 			this.updateInstallStatus(false);
    165 		}
    166 		if(this.failSilently) return;
    167 		if(this._errorDisplayed) return;
    168 		this._errorDisplayed = true;
    169 		var addon = this._addon;
    170 		setTimeout(function() {
    171 			Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
    172 				.getService(Components.interfaces.nsIPromptService)
    173 				.alert(null, addon.EXTENSION_STRING,
    174 				(error ? error : Zotero.getString("zotero.preferences.wordProcessors.installationError", [addon.APP, Zotero.appName])));
    175 		}, 0);
    176 	},
    177 	
    178 	cancelled: function(dontSkipInstallation) {
    179 		installationInProgress = false;
    180 		this.closeProgressWindow();
    181 		if(!this.force && !dontSkipInstallation) this.prefBranch.setBoolPref("skipInstallation", true);
    182 	},
    183 
    184 	showPreferences: function(document) {
    185 		this.prefPaneDoc = document;
    186 		var isInstalled = this.isInstalled(),
    187 			groupbox = document.createElement("groupbox");
    188 		groupbox.id = this._addon.EXTENSION_DIR;
    189 
    190 		var caption = document.createElement("caption");
    191 		caption.setAttribute("label", this._addon.APP);
    192 		groupbox.appendChild(caption);
    193 
    194 		var description = document.createElement("description");
    195 		description.style.width = "45em";
    196 		description.appendChild(document.createTextNode(
    197 			isInstalled ?
    198 				Zotero.getString('zotero.preferences.wordProcessors.installed', this._addon.APP) :
    199 				Zotero.getString('zotero.preferences.wordProcessors.notInstalled', this._addon.APP)));
    200 		groupbox.appendChild(description);
    201 
    202 		var hbox = document.createElement("hbox");
    203 		hbox.setAttribute("pack", "center");
    204 		var button = document.createElement("button"),
    205 			addon = this._addon;
    206 		button.setAttribute("label", 
    207 			(isInstalled ?
    208 				Zotero.getString('zotero.preferences.wordProcessors.reinstall', this._addon.APP) :
    209 				Zotero.getString('zotero.preferences.wordProcessors.install', this._addon.APP)));
    210 		button.addEventListener("command", function() {
    211 			Zotero.debug(`Install button pressed for ${addon.APP} plugin`);
    212 			try {
    213 				var zpi = new ZoteroPluginInstaller(addon, false, true);
    214 				zpi.showPreferences(document);
    215 			} catch (e) {
    216 				Zotero.logError(e);
    217 			}
    218 		}, false);
    219 		hbox.appendChild(button);
    220 		groupbox.appendChild(hbox);
    221 
    222 		var tabpanel = document.getElementById("wordProcessors"),
    223 			old = document.getElementById(this._addon.EXTENSION_DIR);
    224 		if(old) {
    225 			tabpanel.replaceChild(groupbox, old);
    226 		} else {
    227 			tabpanel.insertBefore(groupbox, tabpanel.firstChild);
    228 		}
    229 	},
    230 	
    231 	updateInstallStatus: function(status) {
    232 		this.prefBranch.setBoolPref("installed", status);
    233 		if (! this.prefPaneDoc) return;
    234 		var isInstalled = this.isInstalled();
    235 		var description = this.prefPaneDoc.querySelector(`#${this._addon.EXTENSION_DIR} description`);
    236 		description.replaceChild(this.prefPaneDoc.createTextNode(
    237 				isInstalled ?
    238 					Zotero.getString('zotero.preferences.wordProcessors.installed', this._addon.APP) :
    239 					Zotero.getString('zotero.preferences.wordProcessors.notInstalled', this._addon.APP)
    240 				), description.childNodes[0]);
    241 		var button = this.prefPaneDoc.querySelector(`#${this._addon.EXTENSION_DIR} button`);
    242 		button.setAttribute("label", 
    243 			(isInstalled ?
    244 				Zotero.getString('zotero.preferences.wordProcessors.reinstall', this._addon.APP) :
    245 				Zotero.getString('zotero.preferences.wordProcessors.install', this._addon.APP)));
    246 	},	
    247 	
    248 	_firstRunListener: function() {
    249 		this._progressWindowLabel = this._progressWindow.document.getElementById("progress-label");
    250 		this._progressWindowLabel.value = Zotero.getString('zotero.preferences.wordProcessors.installing', this._addon.EXTENSION_STRING);
    251 		var me = this;
    252 		setTimeout(function() {
    253 			me._progressWindow.focus();
    254 			setTimeout(function() {
    255 				me._progressWindow.focus();
    256 				try {
    257 					me._addon.install(me);
    258 				} catch(e) {
    259 					me.error();
    260 					throw e;
    261 				}
    262 			}, 500);
    263 		}, 100);
    264 	},
    265 };