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 };