www

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

standalone.js (15008B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2009 Center for History and New Media
      5                      George Mason University, Fairfax, Virginia, USA
      6                      http://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23     ***** END LICENSE BLOCK *****
     24 */
     25 
     26 Components.utils.import("resource://gre/modules/Services.jsm");
     27 
     28 /**
     29  * This object contains the various functions for the interface
     30  */
     31 const ZoteroStandalone = new function() {
     32 	/**
     33 	 * Run when standalone window first opens
     34 	 */
     35 	this.onLoad = function() {
     36 		// Fix window without menubar/titlebar when Zotero is closed in full-screen mode in OS X 10.11+
     37 		if (Zotero.isMac && window.document.documentElement.getAttribute('sizemode') == 'fullscreen') {
     38 			window.document.documentElement.setAttribute('sizemode', 'normal');
     39 		}
     40 		
     41 		Zotero.Promise.try(function () {
     42 			if(!Zotero) {
     43 				throw true;
     44 			}
     45 			if(Zotero.initializationPromise.isPending()) {
     46 				Zotero.showZoteroPaneProgressMeter();
     47 			}
     48 			return Zotero.initializationPromise;
     49 		})
     50 		.then(function () {
     51 			if (Zotero.Prefs.get('devtools.errorconsole.enabled', true)) {
     52 				document.getElementById('menu_errorConsole').hidden = false;
     53 			}
     54 			
     55 			document.getElementById('key_copyCitation')
     56 				.setAttribute('key', Zotero.Keys.getKeyForCommand('copySelectedItemCitationsToClipboard'));
     57 			document.getElementById('key_copyBibliography')
     58 				.setAttribute('key', Zotero.Keys.getKeyForCommand('copySelectedItemsToClipboard'));
     59 			
     60 			ZoteroStandalone.DebugOutput.init();
     61 			
     62 			Zotero.hideZoteroPaneOverlays();
     63 			ZoteroPane.init();
     64 			ZoteroPane.makeVisible();
     65 			
     66 			// Don't ask before handing http and https URIs
     67 			var eps = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
     68 					.getService(Components.interfaces.nsIExternalProtocolService);
     69 			var hs = Components.classes["@mozilla.org/uriloader/handler-service;1"]
     70 					.getService(Components.interfaces.nsIHandlerService);
     71 			for (let scheme of ["http", "https"]) {
     72 				var handlerInfo = eps.getProtocolHandlerInfo(scheme);
     73 				handlerInfo.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
     74 				handlerInfo.alwaysAskBeforeHandling = false;
     75 				hs.store(handlerInfo);
     76 			}
     77 			
     78 			// Add add-on listeners (not yet hooked up)
     79 			Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled", false);
     80 			Services.obs.addObserver(gXPInstallObserver, "addon-install-started", false);
     81 			Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
     82 			Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     83 			Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     84 		})
     85 		.catch(function (e) {
     86 			try { Zotero.debug(e, 1); } catch (e) {}
     87 			Components.utils.reportError(e);
     88 			ZoteroPane.displayStartupError();
     89 			window.close();
     90 			return;
     91 		});
     92 	}
     93 	
     94 	/**
     95 	 * Builds new item menu
     96 	 */
     97 	this.buildNewItemMenu = function() {
     98 		var addMenu = document.getElementById('menu_NewItemPopup');
     99 		
    100 		// Remove all nodes so we can regenerate
    101 		while(addMenu.hasChildNodes()) addMenu.removeChild(addMenu.firstChild);
    102 		
    103 		var typeSets = [Zotero.ItemTypes.getPrimaryTypes(), Zotero.ItemTypes.getSecondaryTypes()];
    104 		for(var j=0; j<typeSets.length; j++) {
    105 			var t = typeSets[j];
    106 			
    107 			// Sort by localized name
    108 			var itemTypes = [];
    109 			for (var i=0; i<t.length; i++) {
    110 				itemTypes.push({
    111 					id: t[i].id,
    112 					name: t[i].name,
    113 					localized: Zotero.ItemTypes.getLocalizedString(t[i].id)
    114 				});
    115 			}
    116 			var collation = Zotero.getLocaleCollation();
    117 			itemTypes.sort(function(a, b) {
    118 				return collation.compareString(1, a.localized, b.localized);
    119 			});
    120 			
    121 			for (var i = 0; i<itemTypes.length; i++) {
    122 				var menuitem = document.createElement("menuitem");
    123 				menuitem.setAttribute("label", itemTypes[i].localized);
    124 				menuitem.setAttribute("tooltiptext", "");
    125 				let type = itemTypes[i].id;
    126 				menuitem.addEventListener("command", function() {
    127 					ZoteroPane_Local.newItem(type, null, null, true);
    128 				}, false);
    129 				menuitem.className = "zotero-tb-add";
    130 				addMenu.appendChild(menuitem);
    131 			}
    132 			
    133 			// add separator between sets
    134 			if(j !== typeSets.length-1) {
    135 				addMenu.appendChild(document.createElement("menuseparator"));
    136 			}
    137 		}
    138 	}
    139 	
    140 	
    141 	this.updateQuickCopyOptions = function () {
    142 		var selected = false;
    143 		try {
    144 			selected = Zotero.getActiveZoteroPane()
    145 				.getSelectedItems()
    146 				.filter(item => item.isRegularItem())
    147 				.length;
    148 		}
    149 		catch (e) {}
    150 		
    151 		var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
    152 		format = Zotero.QuickCopy.unserializeSetting(format);
    153 		
    154 		var copyCitation = document.getElementById('menu_copyCitation');
    155 		var copyBibliography = document.getElementById('menu_copyBibliography');
    156 		var copyExport = document.getElementById('menu_copyExport');
    157 		
    158 		copyCitation.hidden = !selected || format.mode != 'bibliography';
    159 		copyBibliography.hidden = !selected || format.mode != 'bibliography';
    160 		copyExport.hidden = !selected || format.mode != 'export';
    161 		if (format.mode == 'export') {
    162 			try {
    163 				let obj = Zotero.Translators.get(format.id);
    164 				copyExport.label = Zotero.getString('quickCopy.copyAs', obj.label);
    165 			}
    166 			catch (e) {
    167 				if (!(e instanceof Zotero.Exception.UnloadedDataException && e.dataType == 'translators')) {
    168 					Zotero.logError(e);
    169 				}
    170 				copyExport.hidden = true;
    171 			}
    172 		}
    173 	};
    174 	
    175 	
    176 	this.updateAddonsPane = function (doc) {
    177 		// Hide unsigned add-on verification warnings
    178 		//
    179 		// This only works for the initial load of the window. If the user switches to Appearance
    180 		// or Plugins and then back to Extensions, the warnings will appear again. A better way to
    181 		// disable this might be discoverable by studying
    182 		// https://dxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/content/extensions.js
    183 		var addonList = doc.getElementById('addon-list');
    184 		setTimeout(function () {
    185 			for (let i = 0; i < addonList.itemCount; i++) {
    186 				let richListItem = addonList.getItemAtIndex(i);
    187 				let container = doc.getAnonymousElementByAttribute(
    188 					richListItem, 'anonid', 'warning-container'
    189 				);
    190 				if (container) {
    191 					let link = doc.getAnonymousElementByAttribute(
    192 						richListItem, 'anonid', 'warning-link'
    193 					);
    194 					if (link && link.href.indexOf('unsigned-addons') != -1) {
    195 						richListItem.removeAttribute('notification');
    196 						container.hidden = true;
    197 					}
    198 				}
    199 			}
    200 		});
    201 	}
    202 	
    203 	/**
    204 	 * Handles help menu requests
    205 	 */
    206 	this.openHelp = function(type) {
    207 		Components.utils.import("resource://zotero/config.js");
    208 		
    209 		switch (type) {
    210 		case "troubleshooting":
    211 			ZoteroPane.loadURI(ZOTERO_CONFIG.TROUBLESHOOTING_URL);
    212 			break;
    213 		
    214 		case "feedback":
    215 			ZoteroPane.loadURI(ZOTERO_CONFIG.FEEDBACK_URL);
    216 			break;
    217 		
    218 		case "connectors":
    219 			ZoteroPane.loadURI(ZOTERO_CONFIG.CONNECTORS_URL);
    220 			break;
    221 		
    222 		default:
    223 			ZoteroPane.loadURI(ZOTERO_CONFIG.SUPPORT_URL);
    224 		}
    225 	}
    226 	
    227 	/**
    228 	 * Checks for updates
    229 	 */
    230 	this.checkForUpdates = function() {
    231 		window.open('chrome://mozapps/content/update/updates.xul', 'updateChecker', 'chrome,centerscreen');
    232 	}
    233 	
    234 	/**
    235 	 * Called before standalone window is closed
    236 	 */
    237 	this.onUnload = function() {
    238 		ZoteroPane.destroy();
    239 	}
    240 }
    241 
    242 
    243 ZoteroStandalone.DebugOutput = {
    244 	_timer: null,
    245 	
    246 	init: function () {
    247 		var storing = Zotero.Debug.storing;
    248 		this._showMenu();
    249 		this.update();
    250 	},
    251 	
    252 	
    253 	toggleStore: function () {
    254 		Zotero.Debug.setStore(!Zotero.Debug.storing);
    255 	},
    256 	
    257 	
    258 	update: function () {
    259 		var enabled = Zotero.Debug.storing;
    260 		var lines = Zotero.Debug.count();
    261 		var empty = lines == 0;
    262 		
    263 		// Show "Submit" when enabled, but leave disabled until there's output
    264 		var menuitem = document.getElementById('debug-output-submit');
    265 		menuitem.hidden = !enabled && empty;
    266 		menuitem.disabled = empty;
    267 		
    268 		// Toggle between "Enable" and "Disable"
    269 		menuitem = document.getElementById('debug-output-enable-disable');
    270 		menuitem.label = Zotero.getString('general.' + (enabled ? 'disable' : 'enable'));
    271 		
    272 		// Update line count
    273 		var str = Zotero.getString('zotero.debugOutputLogging.linesLogged', lines, lines);
    274 		document.getElementById('debug-output-status').label = str;
    275 		
    276 		// Enable "Clear" when there's output
    277 		document.getElementById('debug-output-clear').disabled = empty;
    278 	},
    279 	
    280 	
    281 	submit: function () {
    282 		// 'Zotero' isn't defined yet when this function is created, so do it inline
    283 		return Zotero.Promise.coroutine(function* () {
    284 			Zotero.debug("Submitting debug output");
    285 			
    286 			Components.utils.import("resource://zotero/config.js");
    287 			
    288 			var url = ZOTERO_CONFIG.REPOSITORY_URL + "report?debug=1";
    289 			var output = yield Zotero.Debug.get(
    290 				Zotero.Prefs.get('debug.store.submitSize'),
    291 				Zotero.Prefs.get('debug.store.submitLineLength')
    292 			);
    293 			Zotero.Debug.setStore(false);
    294 			
    295 			var ps = Services.prompt;
    296 			try {
    297 				var xmlhttp = yield Zotero.HTTP.request(
    298 					"POST",
    299 					url,
    300 					{
    301 						compressBody: true,
    302 						body: output,
    303 						logBodyLength: 30,
    304 						timeout: 15000,
    305 						requestObserver: function (req) {
    306 							// Don't fail during tests, with fake XHR
    307 							if (!req.channel) {
    308 								return;
    309 							}
    310 							req.channel.notificationCallbacks = {
    311 								onProgress: function (request, context, progress, progressMax) {},
    312 								
    313 								// nsIInterfaceRequestor
    314 								getInterface: function (iid) {
    315 									try {
    316 										return this.QueryInterface(iid);
    317 									}
    318 									catch (e) {
    319 										throw Components.results.NS_NOINTERFACE;
    320 									}
    321 								},
    322 								
    323 								QueryInterface: function(iid) {
    324 									if (iid.equals(Components.interfaces.nsISupports) ||
    325 											iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
    326 											iid.equals(Components.interfaces.nsIProgressEventSink)) {
    327 										return this;
    328 									}
    329 									throw Components.results.NS_NOINTERFACE;
    330 								},
    331 				
    332 							}
    333 						}
    334 					}
    335 				);
    336 			}
    337 			catch (e) {
    338 				Zotero.logError(e);
    339 				let title = Zotero.getString('general.error');
    340 				let msg;
    341 				if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
    342 					msg = Zotero.getString('general.invalidResponseServer');
    343 				}
    344 				else if (e instanceof Zotero.HTTP.BrowserOfflineException) {
    345 					msg = Zotero.getString('general.browserIsOffline', Zotero.appName);
    346 				}
    347 				else {
    348 					msg = Zotero.getString('zotero.debugOutputLogging.dialog.error');
    349 				}
    350 				ps.alert(null, title, msg);
    351 				return false;
    352 			}
    353 			
    354 			Zotero.debug(xmlhttp.responseText);
    355 			
    356 			var reported = xmlhttp.responseXML.getElementsByTagName('reported');
    357 			if (reported.length != 1) {
    358 				ps.alert(
    359 					null,
    360 					Zotero.getString('general.error'),
    361 					Zotero.getString('general.serverError')
    362 				);
    363 				return false;
    364 			}
    365 			
    366 			var reportID = reported[0].getAttribute('reportID');
    367 			
    368 			var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
    369 				+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL;
    370 			var index = ps.confirmEx(
    371 				null,
    372 				Zotero.getString('zotero.debugOutputLogging.dialog.title'),
    373 				Zotero.getString('zotero.debugOutputLogging.dialog.sent', [ZOTERO_CONFIG.DOMAIN_NAME, reportID]),
    374 				buttonFlags,
    375 				Zotero.getString('general.copyToClipboard'),
    376 				null, null, null, {}
    377 			);
    378 			if (index == 0) {
    379 				const helper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
    380 					.getService(Components.interfaces.nsIClipboardHelper);
    381 				helper.copyString("D" + reportID);
    382 			}
    383 			
    384 			Zotero.Debug.clear();
    385 			return true;
    386 		}.bind(this))();
    387 	},
    388 	
    389 	
    390 	view: function () {
    391 		Zotero.openInViewer("chrome://zotero/content/debugViewer.html", function (doc) {
    392 			var submitted = false;
    393 			doc.querySelector('#submit-button').addEventListener('click', function (event) {
    394 				submitted = true;
    395 			});
    396 			doc.querySelector('#clear-button').addEventListener('click', function (event) {
    397 				Zotero.Debug.clear();
    398 			});
    399 			// If output has been submitted, disable logging when window is closed
    400 			doc.defaultView.addEventListener('unload', function (event) {
    401 				if (submitted) {
    402 					Zotero.Debug.setStore(false);
    403 					Zotero.Debug.clear();
    404 				}
    405 			});
    406 		});
    407 	},
    408 	
    409 	
    410 	clear: function () {
    411 		Zotero.Debug.clear();
    412 	},
    413 	
    414 	
    415 	restartEnabled: function () {
    416 		var ps = Services.prompt;
    417 		var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
    418 				+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL
    419 				+ ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING;
    420 		var index = ps.confirmEx(
    421 			null,
    422 			Zotero.getString('zotero.debugOutputLogging'),
    423 			Zotero.getString('zotero.debugOutputLogging.enabledAfterRestart', [Zotero.clientName]),
    424 			buttonFlags,
    425 			Zotero.getString('general.restartNow'),
    426 			null, Zotero.getString('general.restartLater'), null, {}
    427 		);
    428 		if (index != 1) {
    429 			Zotero.Prefs.set('debug.store', true);
    430 		}
    431 		if (index == 0) {
    432 			Zotero.Utilities.Internal.quit(true);
    433 		}
    434 	},
    435 	
    436 	
    437 	_showMenu: function () {
    438 		document.getElementById('debug-output-menu').hidden = false;
    439 	}
    440 };
    441 
    442 
    443 /** Taken from browser.js **/
    444 function toJavaScriptConsole() {
    445 	toOpenWindowByType("global:console", "chrome://global/content/console.xul");
    446 }
    447 
    448 function toOpenWindowByType(inType, uri, features)
    449 {
    450 	var topWindow = Services.wm.getMostRecentWindow(inType);
    451 	
    452 	if (topWindow) {
    453 		topWindow.focus();
    454 	} else if(features) {
    455 		window.open(uri, "_blank", features);
    456 	} else {
    457 		window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
    458 	}
    459 }
    460 
    461 const gXPInstallObserver = {
    462 	observe: function (aSubject, aTopic, aData) {
    463 		var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
    464 		var win = installInfo.originatingWindow;
    465 		switch (aTopic) {
    466 			case "addon-install-disabled":
    467 			case "addon-install-blocked":
    468 			case "addon-install-failed":
    469 				var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
    470 					.getService(Components.interfaces.nsIPromptService);
    471 				promptService.alert(win, Zotero.getString("standalone.addonInstallationFailed.title"),
    472 					Zotero.getString("standalone.addonInstallationFailed.body", installInfo.installs[0].name));
    473 				break;
    474 			/*case "addon-install-started":
    475 			case "addon-install-complete":*/
    476 		}
    477 	}
    478 };
    479 
    480 // Used by update prompt
    481 function openUILinkIn(url) {
    482 	ZoteroPane.loadURI(url);
    483 }
    484 
    485 window.addEventListener("load", function(e) { ZoteroStandalone.onLoad(e); }, false);
    486 window.addEventListener("unload", function(e) { ZoteroStandalone.onUnload(e); }, false);