From 541c228a372a8bdd94be30e293acd547ecc08584 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 8 Mar 2007 23:36:19 +0000 Subject: [PATCH] Translator errors now include a link to an upcoming Known Translator Issues page, which will eventually contain instructions for helping to fix broken translators Related progress window changes: - Translators now use Zotero.ProgressWindow rather than Zotero_Browser.Progress (removed) -- browser.js currently creates a single instance of ProgressWindow per browser window for its use - Progress boxes now stay open while the mouse is over them and close when you click on them - New method Zotero.Utilities.parseMarkup() -- parses a text string for HTML/XUL markup and returns an array of parts (currently only ) - Using parseMarkup, ProgressWindow.addDescription() now supports adding clickable links to notifications Other progress window changes: - Fixed progress window offsets on Mac (on OS X outerHeight doesn't include 22px title bar and moveTo() positions popups 22px below the specified location) -- need to test this on other platforms - Added support for displaying progress window notifications relative to screen edges when there's no browser window Unrelated: - Fixed warning when calling getSelectedCollections() before the Z pane had been opened --- chrome/content/zotero/browser.js | 155 +------------ chrome/content/zotero/overlay.js | 4 +- chrome/content/zotero/overlay.xul | 4 +- chrome/content/zotero/progressWindow.xul | 6 +- chrome/content/zotero/xpcom/progressWindow.js | 216 ++++++++++++++---- chrome/content/zotero/xpcom/utilities.js | 48 ++++ 6 files changed, 239 insertions(+), 194 deletions(-) diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js index 604557f972..e774bc6f3c 100644 --- a/chrome/content/zotero/browser.js +++ b/chrome/content/zotero/browser.js @@ -372,11 +372,15 @@ var Zotero_Browser = new function() { */ function finishScraping(obj, returnValue, collection) { if(!returnValue) { - Zotero_Browser.Progress.changeHeadline(Zotero.getString("ingester.scrapeError")); - Zotero_Browser.Progress.addDescription(Zotero.getString("ingester.scrapeErrorDescription")); + Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scrapeError")); + // Include link to Known Translator Issues page + var url = "http://www.zotero.org/documentation/known_translator_issues"; + var linkText = '' + + Zotero.getString('ingester.scrapeErrorDescription.linkText') + ''; + Zotero_Browser.progress.addDescription(Zotero.getString("ingester.scrapeErrorDescription", linkText)); } - Zotero_Browser.Progress.fade(); + Zotero_Browser.progress.fade(); } @@ -386,7 +390,8 @@ var Zotero_Browser = new function() { function itemDone(obj, item, collection) { var title = item.getField("title"); var icon = item.getImageSrc(); - Zotero_Browser.Progress.addLines([title], [icon]); + Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scraping")); + Zotero_Browser.progress.addLines([title], [icon]); // add item to collection, if one was specified if(collection) { @@ -547,7 +552,7 @@ Zotero_Browser.Tab.prototype._searchFrames = function(rootDoc, searchDoc) { */ Zotero_Browser.Tab.prototype.translate = function(saveLocation) { if(this.page.translators && this.page.translators.length) { - Zotero_Browser.Progress.show(); + Zotero_Browser.progress.show(); if(saveLocation) { saveLocation = Zotero.Collections.get(saveLocation); @@ -602,7 +607,7 @@ Zotero_Browser.Tab.prototype._selectItems = function(obj, itemList) { "_blank","chrome,modal,centerscreen,resizable=yes", io); if(!io.dataOut) { // user selected no items, so kill the progress indicatior - Zotero_Browser.Progress.kill(); + Zotero_Browser.progress.kill(); } return io.dataOut; @@ -621,143 +626,7 @@ Zotero_Browser.Tab.prototype._translatorsAvailable = function(translate, transla Zotero_Browser.updateStatus(); } -////////////////////////////////////////////////////////////////////////////// -// -// Zotero_Browser.Progress -// -////////////////////////////////////////////////////////////////////////////// - // Handles the display of a div showing progress in scraping -Zotero_Browser.Progress = new function() { - var _progressWindow; - - var _windowLoaded = false; - var _windowLoading = false; - // keep track of all of these things in case they're called before we're - // done loading the progress window - var _loadDescription = null; - var _loadLines = new Array(); - var _loadIcons = new Array(); - var _loadHeadline = Zotero.getString("ingester.scraping"); - - this.show = show; - this.changeHeadline = changeHeadline; - this.addLines = addLines; - this.addDescription = addDescription; - this.fade = fade; - this.kill = kill; - - function show() { - if(_windowLoading || _windowLoaded) { // already loading or loaded - return false; - } - _progressWindow = window.openDialog("chrome://zotero/chrome/ingester/progress.xul", - "", "chrome,dialog=no,titlebar=no,popup=yes"); - _progressWindow.addEventListener("load", _onWindowLoaded, false); - _windowLoading = true; - - return true; - } - - function changeHeadline(headline) { - if(_windowLoaded) { - _progressWindow.document.getElementById("zotero-progress-text-headline").value = headline; - } else { - _loadHeadline = headline; - } - } - - function addLines(label, icon) { - if(_windowLoaded) { - for(i in label) { - var newLabel = _progressWindow.document.createElement("label"); - newLabel.setAttribute("class", "zotero-progress-item-label"); - newLabel.setAttribute("crop", "end"); - newLabel.setAttribute("value", label[i]); - - var newImage = _progressWindow.document.createElement("image"); - newImage.setAttribute("class", "zotero-progress-item-icon"); - newImage.setAttribute("src", icon[i]); - - var newHB = _progressWindow.document.createElement("hbox"); - newHB.setAttribute("class", "zotero-progress-item-hbox"); - newHB.setAttribute("valign", "center"); - newHB.appendChild(newImage); - newHB.appendChild(newLabel); - - _progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB); - } - - _move(); - } else { - _loadLines = _loadLines.concat(label); - _loadIcons = _loadIcons.concat(icon); - } - } - - function addDescription(text) { - if(_windowLoaded) { - var newHB = _progressWindow.document.createElement("hbox"); - newHB.setAttribute("class", "zotero-progress-item-hbox"); - var newDescription = _progressWindow.document.createElement("description"); - newDescription.setAttribute("class", "zotero-progress-description"); - var newText = _progressWindow.document.createTextNode(text); - - newDescription.appendChild(newText); - newHB.appendChild(newDescription); - _progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB); - - _move(); - } else { - _loadDescription = text; - } - } - - function fade() { - if(_windowLoaded || _windowLoading) { - setTimeout(_timeout, 2500); - } - } - - function kill() { - _windowLoaded = false; - _windowLoading = false; - try { - _progressWindow.close(); - } catch(ex) {} - } - - function _onWindowLoaded() { - _windowLoading = false; - _windowLoaded = true; - - _move(); - // do things we delayed because the window was loading - changeHeadline(_loadHeadline); - addLines(_loadLines, _loadIcons); - if(_loadDescription) { - addDescription(_loadDescription); - } - - // reset parameters - _loadDescription = null; - _loadLines = new Array(); - _loadIcons = new Array(); - _loadHeadline = Zotero.getString("ingester.scraping") - } - - function _move() { - _progressWindow.sizeToContent(); - _progressWindow.moveTo( - window.screenX + window.innerWidth - _progressWindow.outerWidth - 30, - window.screenY + window.innerHeight - _progressWindow.outerHeight - 10 - ); - } - - function _timeout() { - kill(); // could check to see if we're really supposed to fade yet - // (in case multiple scrapers are operating at once) - } -} +Zotero_Browser.progress = new Zotero.ProgressWindow(); Zotero_Browser.init(); \ No newline at end of file diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index a9eeb4536f..ea43cfca66 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -962,7 +962,9 @@ var ZoteroPane = new function() } function getSelectedCollection(asID) { - if (this.collectionsView.selection.count > 0 && this.collectionsView.selection.currentIndex != -1) { + if (this.collectionsView.selection + && this.collectionsView.selection.count > 0 + && this.collectionsView.selection.currentIndex != -1) { var collection = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex); if (collection && collection.isCollection()) { if (asID) { diff --git a/chrome/content/zotero/overlay.xul b/chrome/content/zotero/overlay.xul index ba271ef37a..e0146e3fc0 100644 --- a/chrome/content/zotero/overlay.xul +++ b/chrome/content/zotero/overlay.xul @@ -26,7 +26,7 @@ - + diff --git a/chrome/content/zotero/progressWindow.xul b/chrome/content/zotero/progressWindow.xul index 341d27d8d9..26a1b69562 100755 --- a/chrome/content/zotero/progressWindow.xul +++ b/chrome/content/zotero/progressWindow.xul @@ -5,13 +5,11 @@ - + windowtype="alert:alert"> + - diff --git a/chrome/content/zotero/xpcom/progressWindow.js b/chrome/content/zotero/xpcom/progressWindow.js index 2adee453b3..b561c33b83 100644 --- a/chrome/content/zotero/xpcom/progressWindow.js +++ b/chrome/content/zotero/xpcom/progressWindow.js @@ -25,49 +25,79 @@ Zotero.ProgressWindowSet = new function() { this.add = add; this.tile = tile; this.remove = remove; + this.updateTimers = updateTimers; - var _numWindows = 0; var _progressWindows = []; - const X_OFFSET = 30; - const Y_OFFSET = 10; + const X_OFFSET = 25; + const Y_OFFSET = 35; + const Y_SEPARATOR = 12; + const X_WINDOWLESS_OFFSET = 50; + const Y_WINDOWLESS_OFFSET = 100; - function add(progressWin) { - _progressWindows.push(progressWin); - _numWindows++; + function add(progressWindow, instance) { + _progressWindows.push({ + progressWindow: progressWindow, + instance: instance + }); } function tile(progressWin) { var parent = progressWin.opener; - var sum = 0; + var y_sub = null; for (var i=0; i<_progressWindows.length; i++) { - var p = _progressWindows[i]; + var p = _progressWindows[i].progressWindow; // Skip progress windows from other windows if (p.opener != parent) { continue; } - sum += Y_OFFSET + p.outerHeight; + if (!y_sub) { + y_sub = Y_OFFSET + p.outerHeight; + } - p.moveTo( - parent.screenX + parent.innerWidth - p.outerWidth - X_OFFSET, - parent.screenY + parent.innerHeight - sum - ); + if (parent) { + var right = parent.screenX + parent.outerWidth; + var bottom = parent.screenY + parent.outerHeight; + // On OS X outerHeight doesn't include 22px title bar and + // moveTo() positions popups 22px below the specified location + if (Zotero.isMac) { + bottom += (22 * 2); + } + } + else { + var right = progressWin.screen.width + X_OFFSET - X_WINDOWLESS_OFFSET; + var bottom = progressWin.screen.height + Y_OFFSET - Y_WINDOWLESS_OFFSET; + } + + p.moveTo(right - p.outerWidth - X_OFFSET, bottom - y_sub); + + y_sub += p.outerHeight + Y_SEPARATOR; } } function remove(progressWin) { - _numWindows--; for (var i=0; i<_progressWindows.length; i++) { - if (_progressWindows[i] == progressWin) { + if (_progressWindows[i].progressWindow == progressWin) { _progressWindows.splice(i, 1); } } } + + + function updateTimers() { + if (!_progressWindows.length) { + return; + } + + for (var i=0; i<_progressWindows.length; i++) { + _progressWindows[i].instance.fade(); + } + } } @@ -77,23 +107,6 @@ Zotero.ProgressWindowSet = new function() { * Pass the active window into the constructor */ Zotero.ProgressWindow = function(_window){ - if (!_window){ - var _window = - Components.classes["@mozilla.org/embedcomp/window-watcher;1"]. - getService(Components.interfaces.nsIWindowWatcher). - activeWindow; - } - - var _progressWindow = null; - var _windowLoaded = false; - var _windowLoading = false; - // keep track of all of these things in case they're called before we're - // done loading the progress window - var _loadDescription = null; - var _loadLines = new Array(); - var _loadIcons = new Array(); - var _loadHeadline = ''; - this.show = show; this.changeHeadline = changeHeadline; this.addLines = addLines; @@ -101,18 +114,49 @@ Zotero.ProgressWindow = function(_window){ this.fade = fade; this.kill = kill; + var _window = null; + + var _progressWindow = null; + var _windowLoaded = false; + var _windowLoading = false; + var _timeoutID = false; + + // keep track of all of these things in case they're called before we're + // done loading the progress window + var _loadHeadline = ''; + var _loadLines = []; + var _loadIcons = []; + var _loadDescription = null; + function show() { if(_windowLoading || _windowLoaded) { // already loading or loaded return false; } - _progressWindow = _window.openDialog("chrome://zotero/chrome/progressWindow.xul", - "", "chrome,dialog=no,titlebar=no,popup=yes"); + var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Components.interfaces.nsIWindowWatcher); + + if (!_window){ + _window = ww.activeWindow; + } + + if (_window) { + _progressWindow = _window.openDialog("chrome://zotero/chrome/progressWindow.xul", + "", "chrome,dialog=no,titlebar=no,popup=yes"); + } + else { + _progressWindow = ww.openWindow(null, "chrome://zotero/chrome/progressWindow.xul", + "", "chrome,dialog=no,titlebar=no,popup=yes", null); + } _progressWindow.addEventListener("pageshow", _onWindowLoaded, false); + _progressWindow.addEventListener("mouseover", _onMouseOver, false); + _progressWindow.addEventListener("mouseout", _onMouseOut, false); + _progressWindow.addEventListener("mouseup", _onMouseUp, false); + _windowLoading = true; - Zotero.ProgressWindowSet.add(_progressWindow); + Zotero.ProgressWindowSet.add(_progressWindow, this); return true; } @@ -127,7 +171,7 @@ Zotero.ProgressWindow = function(_window){ function addLines(label, icon) { if(_windowLoaded) { - for(i in label) { + for (var i in label) { var newLabel = _progressWindow.document.createElement("label"); newLabel.setAttribute("class", "zotero-progress-item-label"); newLabel.setAttribute("crop", "end"); @@ -153,15 +197,42 @@ Zotero.ProgressWindow = function(_window){ } } + + /* + * Add a description to the progress window + * + * elements are turned into XUL links + */ function addDescription(text) { if(_windowLoaded) { var newHB = _progressWindow.document.createElement("hbox"); newHB.setAttribute("class", "zotero-progress-item-hbox"); var newDescription = _progressWindow.document.createElement("description"); - newDescription.setAttribute("class", "zotero-progress-description"); - var newText = _progressWindow.document.createTextNode(text); - newDescription.appendChild(newText); + var utils = new Zotero.Utilities(); + var parts = utils.parseMarkup(text); + for each(var part in parts) { + if (part.type == 'text') { + var elem = _progressWindow.document.createTextNode(part.text); + } + else if (part.type == 'link') { + var elem = _progressWindow.document.createElement('label'); + elem.setAttribute('value', part.text); + elem.setAttribute('class', 'text-link'); + for (var i in part.attributes) { + elem.setAttribute(i, part.attributes[i]); + + if (i == 'href') { + // DEBUG: As of Fx2, 'mouseup' seems to be the only + // way to detect a click in a popup window + elem.addEventListener('mouseup', _handleLinkClick, false); + } + } + } + + newDescription.appendChild(elem); + } + newHB.appendChild(newDescription); _progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB); @@ -171,13 +242,19 @@ Zotero.ProgressWindow = function(_window){ } } + function fade() { - if(_windowLoaded || _windowLoading) { - _window.setTimeout(_timeout, 2500); + if (_windowLoaded || _windowLoading) { + if (_timeoutID) { + return; + } + + _timeoutID = _progressWindow.setTimeout(_timeout, 2500); } } function kill() { + _disableTimeout(); _windowLoaded = false; _windowLoading = false; Zotero.ProgressWindowSet.remove(_progressWindow); @@ -194,15 +271,15 @@ Zotero.ProgressWindow = function(_window){ // do things we delayed because the window was loading changeHeadline(_loadHeadline); addLines(_loadLines, _loadIcons); - if(_loadDescription) { + if (_loadDescription) { addDescription(_loadDescription); } // reset parameters - _loadDescription = null; - _loadLines = new Array(); - _loadIcons = new Array(); _loadHeadline = ''; + _loadLines = []; + _loadIcons = []; + _loadDescription = null; } function _move() { @@ -213,5 +290,54 @@ Zotero.ProgressWindow = function(_window){ function _timeout() { kill(); // could check to see if we're really supposed to fade yet // (in case multiple scrapers are operating at once) + _timeoutID = false; + } + + function _disableTimeout() { + _progressWindow.clearTimeout(_timeoutID); + _timeoutID = false; + } + + + /* + * Disable the fade timer when the mouse is over the window + */ + function _onMouseOver(e) { + _disableTimeout(); + } + + + /* + * Start the fade timer when the mouse leaves the window + * + * Note that this onmouseout doesn't work correctly on popups in Fx2, + * so 1) we have to calculate the window borders manually to avoid fading + * when the mouse is still over the box, and 2) this only does anything + * when the mouse is moved off of the browser window -- otherwise the fade + * is triggered by onmousemove on appcontent in overlay.xul. + */ + function _onMouseOut(e) { + // |this| refers to progressWindow's XUL window + var top = this.screenY + (Zotero.isMac ? 22 : 0); + if ((e.screenX >= this.screenX && e.screenX <= (this.screenX + this.outerWidth)) + && (e.screenY >= top) && e.screenY <= (top + this.outerHeight)) { + return; + } + + fade(); + } + + + function _onMouseUp(e) { + kill(); + } + + + /* + * Open URL specified in target's href attribute in a new window + */ + function _handleLinkClick(event) { + _progressWindow.open(event.target.getAttribute('href'), 'zotero-loaded-page', + 'menubar=yes,location=yes,toolbar=yes,personalbar=yes,resizable=yes,scrollbars=yes,status=yes'); } } diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index c9f63cc278..fcefa7d9bb 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -152,6 +152,54 @@ Zotero.Utilities.prototype.htmlSpecialChars = function(str) { } +/* + * Parses a text string for HTML/XUL markup and returns an array of parts + * + * Currently only finds HTML links ( tags) + * + * Returns an array of objects with the following form: + * { + * type: 'text'|'link', + * text: "text content", + * [ attributes: { key1: val [ , key2: val, ...] } + * } + */ +Zotero.Utilities.prototype.parseMarkup = function(str) { + var parts = []; + var splits = str.split(/(]+>[^<]*<\/a>)/); + + for each(var split in splits) { + // Link + if (split.indexOf(']+)>([^<]*)<\/a>/); + if (matches) { + // Attribute pairs + var attributes = {}; + var pairs = matches[1].match(/([^ =]+)="([^"]+")/g); + for each (var pair in pairs) { + var [key, val] = pair.split(/=/); + attributes[key] = val.substr(1, val.length - 2); + } + + parts.push({ + type: 'link', + text: matches[2], + attributes: attributes + }); + continue; + } + } + + parts.push({ + type: 'text', + text: split + }); + } + + return parts; +} + + /* * Test if a string is an integer */