Add feed menu buttons. Close adomasven/zotero#9.

This commit is contained in:
Adomas Venčkauskas 2016-03-25 05:49:14 +01:00
parent 4f54214f11
commit 3dc0ad3745
12 changed files with 295 additions and 32 deletions

View file

@ -0,0 +1,12 @@
/* Some distros have icons disabled by default at the OS level and
* mozilla is a respectful gent.
*/
#zotero-feed-item-addTo-button .button-icon {
display: block;
margin-right: 5px
}
/* Set to hidden in user-agent css for some reason. */
#zotero-feed-item-addTo-button .menu-iconic-left {
visibility: visible;
}

View file

@ -25,6 +25,7 @@
var ZoteroItemPane = new function() {
var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox;
var _translationTarget;
this.onLoad = function () {
if (!Zotero) {
@ -47,6 +48,22 @@ var ZoteroItemPane = new function() {
}
this.init = function() {
Zotero.debug("Initializing ZoteroItemPane");
let lastTranslationTarget = Zotero.Prefs.get('feeds.lastTranslationTarget');
if (lastTranslationTarget) {
if (lastTranslationTarget[0] == "C") {
_translationTarget = Zotero.Collections.get(parseInt(lastTranslationTarget.substr(1)));
} else if (lastTranslationTarget[0] == "L") {
_translationTarget = Zotero.Libraries.get(parseInt(lastTranslationTarget.substr(1)));
}
}
if (!_translationTarget) {
_translationTarget = Zotero.Libraries.userLibrary;
}
this.setTranslateButton();
}
/*
* Load a top-level item
*/
@ -185,6 +202,92 @@ var ZoteroItemPane = new function() {
}
this.translateSelectedItems = Zotero.Promise.coroutine(function* () {
var collectionID = _translationTarget.objectType == 'collection' ? _translationTarget.id : undefined;
var items = ZoteroPane_Local.itemsView.getSelectedItems();
for (let item of items) {
yield item.translate(_translationTarget.libraryID, collectionID);
}
});
this.buildTranslateSelectContextMenu = function (event) {
var menu = document.getElementById('zotero-item-addTo-menu');
// Don't trigger rebuilding on nested popupmenu open/close
if (event.target != menu) {
return;
}
// Clear previous items
while (menu.firstChild) {
menu.removeChild(menu.firstChild);
}
var libraries = Zotero.Libraries.getAll();
for (let library of libraries) {
if (!library.editable || library.libraryType == 'publications') {
continue;
}
Zotero.Utilities.Internal.createMenuForTarget(library, menu, function(event, libraryOrCollection) {
ZoteroItemPane.setTranslationTarget(libraryOrCollection);
event.stopPropagation();
});
}
};
this.setTranslateButton = function() {
var label = Zotero.getString('general.addTo', _translationTarget.name);
var elem = document.getElementById('zotero-feed-item-addTo-button');
elem.setAttribute('label', label);
var key = Zotero.Keys.getKeyForCommand('saveToZotero');
var tooltip = label
+ (Zotero.rtl ? ' \u202B' : ' ') + '('
+ (Zotero.isMac ? '⇧⌘' : Zotero.getString('general.keys.ctrlShift'))
+ key + ')';
elem.setAttribute('tooltiptext', tooltip);
var objectType = _translationTarget._objectType;
var imageSrc = Zotero.Utilities.Internal.getCollectionImageSrc(objectType);
elem.setAttribute('image', imageSrc);
};
this.setTranslationTarget = function(translationTarget) {
_translationTarget = translationTarget;
if (translationTarget.objectType == 'collection') {
Zotero.Prefs.set('feeds.translationTarget', "C" + translationTarget.id);
} else {
Zotero.Prefs.set('feeds.translationTarget', "L" + translationTarget.libraryID);
}
ZoteroItemPane.setTranslateButton();
};
this.setToggleReadLabel = function() {
var markRead = false;
var items = ZoteroPane_Local.itemsView.getSelectedItems();
for (let item of items) {
if (!item.isRead) {
markRead = true;
break;
}
}
var elem = document.getElementById('zotero-feed-item-toggleRead-button');
if (markRead) {
var label = Zotero.getString('pane.item.markAsRead');
} else {
label = Zotero.getString('pane.item.markAsUnread');
}
elem.setAttribute('label', label);
var key = Zotero.Keys.getKeyForCommand('toggleRead');
var tooltip = label + (Zotero.rtl ? ' \u202B' : ' ') + '(' + key + ')'
elem.setAttribute('tooltiptext', tooltip);
};
function _updateNoteCount() {
var c = _notesList.childNodes.length;

View file

@ -24,6 +24,7 @@
***** END LICENSE BLOCK *****
-->
<?xml-stylesheet href="chrome://zotero/skin/itemPane.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/itemPane.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
@ -33,13 +34,23 @@
<vbox id="zotero-item-pane" zotero-persist="width">
<!-- Trash -->
<hbox id="zotero-item-top-buttons-holder" hidden="true">
<hbox id="zotero-item-pane-top-buttons-trash" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-item-restore-button" label="&zotero.items.menu.restoreToLibrary;"
oncommand="ZoteroPane_Local.restoreSelectedItems()"/>
<button id="zotero-item-delete-button" label="&zotero.item.deletePermanently;"
oncommand="ZoteroPane_Local.deleteSelectedItems()"/>
</hbox>
<!-- Feed -->
<hbox id="zotero-item-pane-top-buttons-feed" class="zotero-item-pane-top-buttons" hidden="true">
<button id="zotero-feed-item-toggleRead-button" flex="1"
oncommand="ZoteroPane_Local.toggleSelectedItemsRead();"/>
<button id="zotero-feed-item-addTo-button" type="menu-button" flex="1"
oncommand="ZoteroItemPane.translateSelectedItems()">
<menupopup id="zotero-item-addTo-menu" onpopupshowing="ZoteroItemPane.buildTranslateSelectContextMenu(event);"/>
</button>
</hbox>
<!-- Commons -->
<button id="zotero-item-show-original" label="Show Original"
oncommand="ZoteroPane_Local.showOriginalItem()" hidden="true"/>

View file

@ -52,6 +52,7 @@
<preference id="pref-keys-newItem" name="extensions.zotero.keys.newItem" type="string"/>
<preference id="pref-keys-newNote" name="extensions.zotero.keys.newNote" type="string"/>
<preference id="pref-keys-toggleRead" name="extensions.zotero.keys.toggleRead" type="string"/>
<preference id="pref-keys-toggleAllRead" name="extensions.zotero.keys.toggleAllRead" type="string"/>
<preference id="pref-keys-importFromClipboard" name="extensions.zotero.keys.importFromClipboard" type="string"/>
<preference id="pref-keys-copySelectedItemCitationsToClipboard" name="extensions.zotero.keys.copySelectedItemCitationsToClipboard" type="string"/>
<preference id="pref-keys-copySelectedItemsToClipboard" name="extensions.zotero.keys.copySelectedItemsToClipboard" type="string"/>
@ -277,11 +278,11 @@
<label class="modifier"/>
<textbox id="textbox-toggleTagSelector" maxlength="1" size="1" preference="pref-keys-toggleTagSelector"/>
</row>
<row>
<label value="&zotero.preferences.keys.toggleRead;" control="textbox-toggleRead"/>
<label/>
<textbox id="textbox-toggleRead" maxlength="1" size="1" preference="pref-keys-toggleRead"/>
<label value="&zotero.preferences.keys.toggleAllRead;" control="textbox-toggleAllRead"/>
<label class="modifier"/>
<textbox id="textbox-toggleAllRead" maxlength="1" size="1" preference="pref-keys-toggleAllRead"/>
</row>
</rows>
</grid>

View file

@ -456,14 +456,6 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
return;
}
// FeedItem may have changed read/unread state
if (type == 'feedItem' && action == 'modify') {
for (let i=0; i<ids.length; i++) {
this._treebox.invalidateRow(this._itemRowMap[ids[i]]);
}
return;
}
if (type == 'search' && action == 'modify') {
// TODO: Only refresh on condition change (not currently available in extraData)
yield this.refresh();
@ -482,6 +474,12 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
}
var collectionTreeRow = this.collectionTreeRow;
if (collectionTreeRow.isFeed() && action == 'modify') {
for (let i=0; i<ids.length; i++) {
this._treebox.invalidateRow(this._rowMap[ids[i]]);
}
}
var madeChanges = false;
var refreshed = false;
@ -664,6 +662,10 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
sort = true;
}
if (collectionTreeRow.isFeed()) {
this._ownerDocument.defaultView.ZoteroItemPane.setToggleReadLabel();
}
// If no quicksearch, process modifications manually
else if (!quicksearch || quicksearch.value == '')
{

View file

@ -925,6 +925,81 @@ Zotero.Utilities.Internal = {
parts.push(isbn.charAt(isbn.length-1)); // Check digit
return parts.join('-');
},
/**
* Create a libraryOrCollection DOM tree to place in <menupopup> element.
* If has no children, returns a <menuitem> element, otherwise <menu>.
*
* @param {Library/Collection} libraryOrCollection
* @param {Node<menupopup>} elem parent element
* @param {function} clickAction function to execute on clicking the menuitem.
* Receives the event and libraryOrCollection for given item.
*
* @return {Node<menuitem>/Node<menu>} appended node
*/
createMenuForTarget: function(libraryOrCollection, elem, clickAction) {
var doc = elem.ownerDocument;
function _createMenuitem(label, value, icon, command) {
let menuitem = doc.createElement('menuitem');
menuitem.setAttribute("label", label);
menuitem.setAttribute("value", value);
menuitem.setAttribute("image", icon);
menuitem.addEventListener('command', command);
menuitem.classList.add('menuitem-iconic');
return menuitem
}
function _createMenu(label, icon) {
let menu = doc.createElement('menu');
menu.setAttribute("label", label);
menu.setAttribute("image", icon);
menu.classList.add('menu-iconic');
let menupopup = doc.createElement('menupopup');
menu.appendChild(menupopup);
return menu;
}
var imageSrc = this.getCollectionImageSrc(libraryOrCollection._objectType);
var menuitem = _createMenuitem(
libraryOrCollection.name,
libraryOrCollection.id,
imageSrc,
function (event) {
clickAction(event, libraryOrCollection);
}
);
var collections;
if (libraryOrCollection.objectType == 'collection') {
collections = Zotero.Collections.getByParent(libraryOrCollection.id);
} else {
collections = Zotero.Collections.getByLibrary(libraryOrCollection.id);
}
if (collections.length == 0) {
elem.appendChild(menuitem);
return menuitem
}
var menu = _createMenu(libraryOrCollection.name, imageSrc);
var menupopup = menu.firstChild;
menupopup.appendChild(menuitem);
menupopup.appendChild(doc.createElement('menuseparator'));
for (let collection of collections) {
let collectionMenu = this.createMenuForTarget(collection, elem, clickAction);
menupopup.appendChild(collectionMenu);
}
elem.appendChild(menu);
return menu;
},
getCollectionImageSrc: function(objectType) {
var suffix = Zotero.hiDPI ? "@2x" : "";
var collectionType = objectType == 'group' ? 'library' : objectType;
return "chrome://zotero/skin/treesource-" + collectionType + suffix + ".png";
}
}

View file

@ -126,6 +126,8 @@ var ZoteroPane = new function()
});
this.addReloadListener(_loadPane);
ZoteroItemPane.init();
// continue loading pane
_loadPane();
}
@ -601,14 +603,7 @@ var ZoteroPane = new function()
// Toggle read/unread
let row = this.collectionsView.getRow(this.collectionsView.selection.currentIndex);
if (!row || !row.isFeed()) return;
if(itemReadTimeout) {
itemReadTimeout.cancel();
itemReadTimeout = null;
}
let itemIDs = this.getSelectedItems(true);
Zotero.FeedItems.toggleReadByID(itemIDs);
return;
this.toggleSelectedItemsRead();
}
}
@ -626,7 +621,7 @@ var ZoteroPane = new function()
return;
}
Zotero.debug('Keyboard shortcut: ', command);
Zotero.debug('Keyboard shortcut: ' + command);
// Errors don't seem to make it out otherwise
try {
@ -726,6 +721,20 @@ var ZoteroPane = new function()
case 'sync':
Zotero.Sync.Runner.sync();
break;
case 'saveToZotero':
var collectionTreeRow = this.collectionsView.selectedTreeRow;
if (collectionTreeRow.isFeed()) {
ZoteroItemPane.translateSelectedItems();
} else {
Zotero.debug(command + ' does not do anything in non-feed views')
}
break;
case 'toggleAllRead':
var collectionTreeRow = this.collectionsView.selectedTreeRow;
if (collectionTreeRow.isFeed()) {
this.markFeedRead();
}
break;
default:
throw ('Command "' + command + '" not found in ZoteroPane_Local.handleKeyDown()');
}
@ -1288,14 +1297,18 @@ var ZoteroPane = new function()
return false;
}
// Display restore/delete buttons if items selected in Trash
// Display restore/delete buttons depending on context
if (this.itemsView.selection.count) {
document.getElementById('zotero-item-top-buttons-holder').hidden
document.getElementById('zotero-item-pane-top-buttons-trash').hidden
= !this.getCollectionTreeRow().isTrash()
|| _nonDeletedItemsSelected(this.itemsView);
document.getElementById('zotero-item-pane-top-buttons-feed').hidden
= !this.getCollectionTreeRow().isFeed()
}
else {
document.getElementById('zotero-item-top-buttons-holder').hidden = true;
document.getElementById('zotero-item-pane-top-buttons-trash').hidden = true;
document.getElementById('zotero-item-pane-top-buttons-feed').hidden = true;
}
var tabs = document.getElementById('zotero-view-tabbox');
@ -1391,12 +1404,19 @@ var ZoteroPane = new function()
// if (!item.isTranslated) {
// item.translate();
// }
this.startItemReadTimeout(item.id);
item.isRead = true;
ZoteroItemPane.setToggleReadLabel();
yield item.saveTx();
// this.startItemReadTimeout(item.id);
}
}
}
// Zero or multiple items selected
else {
if (collectionTreeRow.isFeed()) {
ZoteroItemPane.setToggleReadLabel();
}
var count = this.itemsView.selection.count;
// Display duplicates merge interface in item pane
@ -1924,9 +1944,9 @@ var ZoteroPane = new function()
}
});
this.toggleSelectedItemsRead = function() {
return Zotero.FeedItems.toggleReadByID(this.getSelectedItems(true));
};
this.toggleSelectedItemsRead = Zotero.Promise.coroutine(function* () {
yield Zotero.FeedItems.toggleReadByID(this.getSelectedItems(true));
});
this.markFeedRead = Zotero.Promise.coroutine(function* () {
if (!this.collectionsView.selection.count) return;

View file

@ -140,7 +140,7 @@
<!ENTITY zotero.preferences.keys.quicksearch "Quick Search">
<!ENTITY zotero.preferences.keys.newItem "Create a New Item">
<!ENTITY zotero.preferences.keys.newNote "Create a New Note">
<!ENTITY zotero.preferences.keys.toggleRead "Mark Item Read/Unread">
<!ENTITY zotero.preferences.keys.toggleAllRead "Mark All Feed Items As Read/Unread">
<!ENTITY zotero.preferences.keys.toggleTagSelector "Toggle Tag Selector">
<!ENTITY zotero.preferences.keys.copySelectedItemCitationsToClipboard "Copy Selected Item Citations to Clipboard">
<!ENTITY zotero.preferences.keys.copySelectedItemsToClipboard "Copy Selected Items to Clipboard">

View file

@ -56,6 +56,7 @@ general.openPreferences = Open Preferences
general.keys.ctrlShift = Ctrl+Shift+
general.keys.cmdShift = Cmd+Shift+
general.dontShowAgain = Dont Show Again
general.addTo = Add to %S
general.operationInProgress = A Zotero operation is currently in progress.
general.operationInProgress.waitUntilFinished = Please wait until it has finished.

View file

@ -42,13 +42,13 @@
}
/* Restore/Delete buttons in trash view */
#zotero-item-top-buttons-holder {
.zotero-item-pane-top-buttons {
-moz-appearance: toolbar;
-moz-box-pack: center;
min-height: 3em;
}
#zotero-item-top-buttons-holder > button {
.zotero-item-pane-top-buttons > button {
-moz-box-flex: 1
}
@ -67,3 +67,23 @@
{
min-height: 20px;
}
#zotero-feed-item-toggleRead-button {
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
}
#zotero-feed-item-addTo-button {
max-width: 250px;
}
#zotero-feed-item-addTo-button button {
overflow: hidden;
text-overflow: ellipsis;
}
#zotero-feed-item-addTo-button .button-icon {
margin-right: 5px
height: 16px;
}

View file

@ -55,6 +55,7 @@ pref("extensions.zotero.groups.copyTags", true);
pref("extensions.zotero.feeds.sortAscending", false);
pref("extensions.zotero.feeds.defaultTTL", 1);
pref("extensions.zotero.feeds.defaultCleanupAfter", 2);
pref("extensions.zotero.feeds.lastTranslationTarget", false);
pref("extensions.zotero.backup.numBackups", 2);
pref("extensions.zotero.backup.interval", 1440);
@ -84,6 +85,7 @@ pref("extensions.zotero.keys.copySelectedItemCitationsToClipboard", 'A');
pref("extensions.zotero.keys.copySelectedItemsToClipboard", 'C');
pref("extensions.zotero.keys.toggleTagSelector", 'T');
pref("extensions.zotero.keys.sync", 'Y');
pref("extensions.zotero.keys.toggleAllRead", 'R');
pref("extensions.zotero.keys.toggleRead", '`');
// Fulltext indexing

View file

@ -69,4 +69,20 @@ describe("Item pane", function () {
assert.equal(noteBox.noteField.value, '<p>Test</p>');
})
})
describe("Feed buttons", function() {
describe("Mark as Read/Unread", function() {
it("Updates label when state of an item changes", function* () {
let feed = yield createFeed();
yield selectLibrary(win, feed.libraryID);
let item = yield createDataObject('feedItem', {libraryID: feed.libraryID});
yield itemsView.selectItem(item.id);
let button = doc.getElementById('zotero-feed-item-toggleRead-button');
assert.equal(button.getAttribute('label'), Zotero.getString('pane.item.markAsUnread'));
yield item.toggleRead(false);
assert.equal(button.getAttribute('label'), Zotero.getString('pane.item.markAsRead'));
});
});
});
})