diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml index 4a5630ee71..9ef7ab6abf 100644 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ b/chrome/content/zotero/bindings/tagsbox.xml @@ -118,7 +118,7 @@ this.mode = this.getAttribute('mode'); } - this._notifierID = Zotero.Notifier.registerObserver(this, ['setting']); + this._notifierID = Zotero.Notifier.registerObserver(this, ['item-tag', 'setting']); ]]> @@ -142,6 +142,55 @@ } return; } + else if (type == 'item-tag') { + let itemID, tagID; + + for (var i=0; i newTabIndex) { + this._lastTabIndex++; + } + } + else if (this._tabDirection == 1) { + if (this._lastTabIndex > newTabIndex) { + this._lastTabIndex++; + } + } + } + else if (event == 'remove') { + var oldTabIndex = this.remove(tagID); + if (oldTabIndex == -1) { + return; + } + if (this._tabDirection == -1) { + if (this._lastTabIndex > oldTabIndex) { + this._lastTabIndex--; + } + } + else if (this._tabDirection == 1) { + if (this._lastTabIndex >= oldTabIndex) { + this._lastTabIndex--; + } + } + } + } + + this.updateCount(); + } + else if (type == 'tag') { + if (event == 'modify') { + this.reload(); + } + } ]]> @@ -166,14 +215,11 @@ while(rows.hasChildNodes()) { rows.removeChild(rows.firstChild); } - var tags = self.item.getTags(); - if (tags) { - for (var i=0; i + @@ -234,10 +283,13 @@ + - @@ -583,21 +633,12 @@ 1) { - var lastTag = row == row.parentNode.lastChild; - - Zotero.DB.beginTransaction(); - - // If old tag isn't in array, remove it - if (id) { - var oldValue = Zotero.Tags.getName(id); - if (tagArray.indexOf(oldValue) == -1) { - this.item.removeTag(id); - } - } - - this.item.addTags(tagArray); - - Zotero.DB.commitTransaction(); - - // TODO: get tab index right - - if (lastTag) { - this._lastTabIndex = this.item.getTags().length; - } - - this.reload(); - return; - } - // Single tag at end + // Existing tag cleared else { - id = tagsbox.add(value); - // New tag - if (id) { - // Stay put, since a tag was added above - if (this._tabDirection == -1) { - this._tabDirection = false; - } + this.item.removeTag(oldTagID); + } + } + // Multiple tags + else if (tagArray.length > 1) { + var lastTag = row == row.parentNode.lastChild; + + Zotero.DB.beginTransaction(); + + if (oldTagID) { + var oldValue = Zotero.Tags.getName(oldTagID); + // If old tag isn't in array, remove it + if (tagArray.indexOf(oldValue) == -1) { + this.item.removeTag(oldTagID); } - // Already exists + // If old tag is staying, restore the textbox + // immediately. This isn't strictly necessary, but it + // makes the transition nicer. else { - // Go back one, since we'll remove this below - if (this._tabDirection == 1) { - this._lastTabIndex--; - } + textbox.value = textbox.getAttribute('value'); + this.textboxToLabel(textbox); } } - } - - if (id) { - var elem = this.createValueElement( - value, - tabindex - ); - var row = textbox.parentNode; - row.replaceChild(elem, textbox); + this.item.addTags(tagArray); - this.updateRow(row, Zotero.Tags.get(id), tabindex); + Zotero.DB.commitTransaction(); - if (!unchanged) { - // Move row to appropriate place, alphabetically - var collation = Zotero.getLocaleCollation(); - var rows = row.parentNode; - var labels = rows.getElementsByAttribute('fieldname', 'tag'); - - rows.removeChild(row); - var currentTabIndex = elem.getAttribute('ztabindex'); - - var before = null; - var inserted = false; - for (var i=0; i 0) { - labels[i].setAttribute('ztabindex', newTabIndex); - continue; - } - - elem.setAttribute('ztabindex', newTabIndex); - rows.insertBefore(row, labels[i].parentNode); - inserted = true; - - // Adjust last tab index - if (this._tabDirection == -1) { - if (this._lastTabIndex > newTabIndex) { - this._lastTabIndex++; - } - } - else if (this._tabDirection == 1) { - if (this._lastTabIndex < newTabIndex) { - this._lastTabIndex--; - } - } - } - if (!inserted) { - elem.setAttribute('ztabindex', i + 1); - rows.appendChild(row); - } + if (lastTag) { + this._lastTabIndex = this.item.getTags().length; } + + this.reload(); } + // Single tag at end else { - // Just remove the row - // - // If there's an open popup, this throws NODE CANNOT BE FOUND - try { - var row = rows.removeChild(row); - } - catch (e) {} + row.parentNode.removeChild(row); + this.item.addTag(value); } ]]> @@ -769,16 +730,84 @@ + + + + + + - - - + - + + if (collation.compareString(1, name, labels[i].textContent) > 0) { + labels[i].setAttribute('ztabindex', index); + continue; + } + + elem.setAttribute('ztabindex', index); + rowsElement.insertBefore(row, labels[i].parentNode); + newTabIndex = index; + inserted = true; + } + if (!inserted) { + newTabIndex = i + 1; + elem.setAttribute('ztabindex', newTabIndex); + rowsElement.appendChild(row); + } + + return newTabIndex; + ]]> @@ -803,12 +832,35 @@ - - - + @@ -816,7 +868,11 @@ - false - null - + null + @@ -226,9 +218,45 @@ // Remove children tagsToggleBox.textContent = ""; - var lastTag; + // Sort by name + var orderedTags = []; + var collation = Zotero.getLocaleCollation(); for (let tagID in self._tags) { - let tagButton = self._makeClickableTag(tagID, lastTag, self.editable); + orderedTags.push(self._tags[tagID]) + } + orderedTags.sort(function(a, b) { + return collation.compareString(1, a.name, b.name); + }); + + var tagColorsLowerCase = {}; + var colorTags = []; + for (let name in tagColors) { + colorTags[tagColors[name].position] = name; + tagColorsLowerCase[name.toLowerCase()] = true; + } + var positions = Object.keys(colorTags); + for (let i=positions.length-1; i>=0; i--) { + let name = colorTags[positions[i]]; + let ids = Zotero.Tags.getIDs(name, self.libraryID); + orderedTags.unshift({ + id: ids ? ids.join('-') : null, + name: name, + type: 0, + hasColor: true + }); + } + + var lastTag; + for (let i=0; i=0; i--) { - tagsToggleBox.insertBefore(colorTags[positions[i]], tagsToggleBox.firstChild); - } - //start tag cloud code var tagCloud = Zotero.Prefs.get('tagCloud'); @@ -516,7 +556,12 @@ // This could be more optimized to insert new/changed tags at the appropriate // spot if we cared, but we probably don't var t = me.id('tags-search').inputField; - me.setFilterTags(Zotero.Tags.search(t.value), true); + if (t.value) { + me.setSearch(t.value, true); + } + else { + me.setSearch(false, true); + } me._dirty = true; me.doCommand(); @@ -590,7 +635,7 @@ if (typeof clear != 'undefined') { if (clear){ t.value = ''; - this.setFilterTags(false); + this.setSearch(); return false; } else { @@ -598,7 +643,12 @@ } } - this.setFilterTags(Zotero.Tags.search(t.value)); + if (t.value) { + this.setSearch(t.value); + } + else { + this.setSearch(); + } return true; ]]> @@ -639,16 +689,9 @@ - + - + @@ -743,25 +821,27 @@ - + - + - - - + + + @@ -930,15 +1012,28 @@ onkeypress="if (event.keyCode == event.DOM_VK_ESCAPE) { document.getBindingParent(this).handleKeyPress(true); }"/> - + - - + + diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js index 0989ae3665..cce85c05d4 100644 --- a/chrome/content/zotero/xpcom/collectionTreeView.js +++ b/chrome/content/zotero/xpcom/collectionTreeView.js @@ -814,7 +814,7 @@ Zotero.CollectionTreeView.prototype.getLastViewedRow = function () { /* * Delete the selection */ -Zotero.CollectionTreeView.prototype.deleteSelection = function() +Zotero.CollectionTreeView.prototype.deleteSelection = function(deleteItems) { if(this.selection.count == 0) return; @@ -842,14 +842,12 @@ Zotero.CollectionTreeView.prototype.deleteSelection = function() for (var i=0; i if(node === undefined) { - var platformVersion = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULAppInfo).platformVersion; - if(Components.classes["@mozilla.org/xpcom/version-comparator;1"] - .getService(Components.interfaces.nsIVersionComparator) - .compare(platformVersion, "12.0") >= 0) { - var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] - .createInstance(Components.interfaces.nsIDOMParser); - var domDocument = parser.parseFromString("", - "text/html"); - node = domDocument.createElement("div"); - } else { - node = false; - } + var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"] + .createInstance(Components.interfaces.nsIDOMParser); + var domDocument = parser.parseFromString("", + "text/html"); + node = domDocument.createElement("div"); } - if(node) { - node.innerHTML = str; - return node.textContent.replace(/ {2,}/g, " "); - } else if(!nsIScriptableUnescapeHTML) { - nsIScriptableUnescapeHTML = Components.classes["@mozilla.org/feed-unescapehtml;1"] - .getService(Components.interfaces.nsIScriptableUnescapeHTML); - } - return nsIScriptableUnescapeHTML.unescape(str); + node.innerHTML = str; + return node.textContent.replace(/ {2,}/g, " "); } else if(Zotero.isNode) { /*var doc = require('jsdom').jsdom(str, null, { "features":{ diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index c903b6b19c..f22c754caf 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -663,7 +663,8 @@ var ZoteroPane = new function() if (from == 'zotero-collections-tree') { if ((event.keyCode == event.DOM_VK_BACK_SPACE && Zotero.isMac) || event.keyCode == event.DOM_VK_DELETE) { - ZoteroPane_Local.deleteSelectedCollection(); + var deleteItems = event.metaKey || (!Zotero.isMac && event.shiftKey); + ZoteroPane_Local.deleteSelectedCollection(deleteItems); event.preventDefault(); return; } @@ -673,7 +674,7 @@ var ZoteroPane = new function() event.keyCode == event.DOM_VK_DELETE) { // If Cmd/Ctrl delete, use forced mode, which does different // things depending on the context - var force = event.metaKey || (!Zotero.isMac && event.ctrlKey); + var force = event.metaKey || (!Zotero.isMac && event.shiftKey); ZoteroPane_Local.deleteSelectedItems(force); event.preventDefault(); return; @@ -1587,7 +1588,7 @@ var ZoteroPane = new function() } - this.deleteSelectedCollection = function () { + this.deleteSelectedCollection = function (deleteItems) { var itemGroup = this.getItemGroup(); // Remove virtual duplicates collection @@ -1606,18 +1607,52 @@ var ZoteroPane = new function() return; } + + var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Components.interfaces.nsIPromptService); + buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING + + ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL; if (this.collectionsView.selection.count == 1) { if (itemGroup.isCollection()) { - if (confirm(Zotero.getString('pane.collections.delete'))) - { - this.collectionsView.deleteSelection(); + if (deleteItems) { + var index = ps.confirmEx( + null, + Zotero.getString('pane.collections.deleteWithItems.title'), + Zotero.getString('pane.collections.deleteWithItems'), + buttonFlags, + Zotero.getString('pane.collections.deleteWithItems.title'), + "", "", "", {} + ); + } + else { + var index = ps.confirmEx( + null, + Zotero.getString('pane.collections.delete.title'), + Zotero.getString('pane.collections.delete') + + "\n\n" + + Zotero.getString('pane.collections.delete.keepItems'), + buttonFlags, + Zotero.getString('pane.collections.delete.title'), + "", "", "", {} + ); + } + if (index == 0) { + this.collectionsView.deleteSelection(deleteItems); } } else if (itemGroup.isSearch()) { - if (confirm(Zotero.getString('pane.collections.deleteSearch'))) - { + + var index = ps.confirmEx( + null, + Zotero.getString('pane.collections.deleteSearch.title'), + Zotero.getString('pane.collections.deleteSearch'), + buttonFlags, + Zotero.getString('pane.collections.deleteSearch.title'), + "", "", "", {} + ); + if (index == 0) { this.collectionsView.deleteSelection(); } } @@ -1962,7 +1997,8 @@ var ZoteroPane = new function() "showDuplicates", "showUnfiled", "editSelectedCollection", - "removeCollection", + "deleteCollection", + "deleteCollectionAndItems", "sep2", "exportCollection", "createBibCollection", @@ -1992,7 +2028,8 @@ var ZoteroPane = new function() m.newSubcollection, m.sep1, m.editSelectedCollection, - m.removeCollection, + m.deleteCollection, + m.deleteCollectionAndItems, m.sep2, m.exportCollection, m.createBibCollection, @@ -2010,7 +2047,8 @@ var ZoteroPane = new function() // Adjust labels menu.childNodes[m.editSelectedCollection].setAttribute('label', Zotero.getString('pane.collections.menu.rename.collection')); - menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('pane.collections.menu.remove.collection')); + menu.childNodes[m.deleteCollection].setAttribute('label', Zotero.getString('pane.collections.menu.delete.collection')); + menu.childNodes[m.deleteCollectionAndItems].setAttribute('label', Zotero.getString('pane.collections.menu.delete.collectionAndItems')); menu.childNodes[m.exportCollection].setAttribute('label', Zotero.getString('pane.collections.menu.export.collection')); menu.childNodes[m.createBibCollection].setAttribute('label', Zotero.getString('pane.collections.menu.createBib.collection')); menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.collection')); @@ -2018,14 +2056,14 @@ var ZoteroPane = new function() else if (itemGroup.isSearch()) { show = [ m.editSelectedCollection, - m.removeCollection, + m.deleteCollection, m.sep2, m.exportCollection, m.createBibCollection, m.loadReport ]; - menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('pane.collections.menu.remove.savedSearch')); + menu.childNodes[m.deleteCollection].setAttribute('label', Zotero.getString('pane.collections.menu.delete.savedSearch')); var s = [m.exportCollection, m.createBibCollection, m.loadReport]; if (!this.itemsView.rowCount) { @@ -2046,10 +2084,10 @@ var ZoteroPane = new function() } else if (itemGroup.isDuplicates() || itemGroup.isUnfiled()) { show = [ - m.removeCollection + m.deleteCollection ]; - menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('general.remove')); + menu.childNodes[m.deleteCollection].setAttribute('label', Zotero.getString('general.hide')); } else if (itemGroup.isHeader()) { if (itemGroup.ref.id == 'commons-header') { @@ -2068,7 +2106,7 @@ var ZoteroPane = new function() // Disable some actions if user doesn't have write access // // Some actions are disabled via their commands in onCollectionSelected() - var s = [m.newSubcollection, m.editSelectedCollection, m.removeCollection]; + var s = [m.newSubcollection, m.editSelectedCollection, m.deleteCollection, m.deleteCollectionAndItems]; if (itemGroup.isWithinGroup() && !itemGroup.editable && !itemGroup.isDuplicates() && !itemGroup.isUnfiled()) { disable = disable.concat(s); } @@ -2337,7 +2375,7 @@ var ZoteroPane = new function() } // Plural if necessary - menu.childNodes[m.deleteFromLibrary].setAttribute('label', Zotero.getString('pane.items.menu.erase' + multiple)); + menu.childNodes[m.deleteFromLibrary].setAttribute('label', Zotero.getString('pane.items.menu.moveToTrash' + multiple)); menu.childNodes[m.exportItems].setAttribute('label', Zotero.getString('pane.items.menu.export' + multiple)); menu.childNodes[m.createBib].setAttribute('label', Zotero.getString('pane.items.menu.createBib' + multiple)); menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.items.menu.generateReport' + multiple)); diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul index 11d6cd4758..96910d8361 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -245,6 +245,7 @@ + diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd index 0e4fa616dc..e51128f262 100644 --- a/chrome/locale/en-US/zotero/zotero.dtd +++ b/chrome/locale/en-US/zotero/zotero.dtd @@ -85,7 +85,7 @@ - + diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index a821742d64..8bcb61c2ed 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -34,11 +34,13 @@ general.permissionDenied = Permission Denied general.character.singular = character general.character.plural = characters general.create = Create +general.delete = Delete general.seeForMoreInformation = See %S for more information. general.enable = Enable general.disable = Disable general.remove = Remove general.reset = Reset +general.hide = Hide general.quit = Quit general.useDefault = Use Default general.openDocumentation = Open Documentation @@ -132,8 +134,14 @@ date.relative.daysAgo.multiple = %S days ago date.relative.yearsAgo.one = 1 year ago date.relative.yearsAgo.multiple = %S years ago +pane.collections.delete.title = Delete Collection pane.collections.delete = Are you sure you want to delete the selected collection? -pane.collections.deleteSearch = Are you sure you want to delete the selected search? +pane.collections.delete.keepItems = Items within this collection will not be deleted. +pane.collections.deleteWithItems.title = Delete Collection and Items +pane.collections.deleteWithItems = Are you sure you want to delete the selected collection and move all items within it to the Trash? + +pane.collections.deleteSearch.title = Delete Search +pane.collections.deleteSearch = Are you sure you want to delete the selected search? pane.collections.emptyTrash = Are you sure you want to permanently remove items in the Trash? pane.collections.newCollection = New Collection pane.collections.name = Enter a name for this collection: @@ -149,8 +157,9 @@ pane.collections.duplicate = Duplicate Items pane.collections.menu.rename.collection = Rename Collection… pane.collections.menu.edit.savedSearch = Edit Saved Search -pane.collections.menu.remove.collection = Remove Collection… -pane.collections.menu.remove.savedSearch = Remove Saved Search… +pane.collections.menu.delete.collection = Delete Collection… +pane.collections.menu.delete.collectionAndItems = Delete Collection and Items… +pane.collections.menu.delete.savedSearch = Delete Saved Search… pane.collections.menu.export.collection = Export Collection… pane.collections.menu.export.savedSearch = Export Saved Search… pane.collections.menu.createBib.collection = Create Bibliography From Collection… @@ -180,22 +189,22 @@ pane.items.trash.multiple = Are you sure you want to move the selected items to pane.items.delete.title = Delete pane.items.delete = Are you sure you want to delete the selected item? pane.items.delete.multiple = Are you sure you want to delete the selected items? -pane.items.menu.remove = Remove Selected Item -pane.items.menu.remove.multiple = Remove Selected Items -pane.items.menu.erase = Delete Selected Item from Library… -pane.items.menu.erase.multiple = Delete Selected Items from Library… -pane.items.menu.export = Export Selected Item… -pane.items.menu.export.multiple = Export Selected Items… -pane.items.menu.createBib = Create Bibliography from Selected Item… -pane.items.menu.createBib.multiple = Create Bibliography from Selected Items… -pane.items.menu.generateReport = Generate Report from Selected Item… -pane.items.menu.generateReport.multiple = Generate Report from Selected Items… +pane.items.menu.remove = Remove Item from Collection +pane.items.menu.remove.multiple = Remove Items from Collection +pane.items.menu.moveToTrash = Move Item to Trash… +pane.items.menu.moveToTrash.multiple = Move Items to Trash… +pane.items.menu.export = Export Item… +pane.items.menu.export.multiple = Export Items… +pane.items.menu.createBib = Create Bibliography from Item… +pane.items.menu.createBib.multiple = Create Bibliography from Items… +pane.items.menu.generateReport = Generate Report from Item… +pane.items.menu.generateReport.multiple = Generate Report from Items… pane.items.menu.reindexItem = Reindex Item pane.items.menu.reindexItem.multiple = Reindex Items pane.items.menu.recognizePDF = Retrieve Metadata for PDF pane.items.menu.recognizePDF.multiple = Retrieve Metadata for PDFs -pane.items.menu.createParent = Create Parent Item from Selected Item -pane.items.menu.createParent.multiple = Create Parent Items from Selected Items +pane.items.menu.createParent = Create Parent Item +pane.items.menu.createParent.multiple = Create Parent Items pane.items.menu.renameAttachments = Rename File from Parent Metadata pane.items.menu.renameAttachments.multiple = Rename Files from Parent Metadata diff --git a/chrome/skin/default/zotero/bindings/tagselector.css b/chrome/skin/default/zotero/bindings/tagselector.css index 22b0659ff1..e67b6211b2 100644 --- a/chrome/skin/default/zotero/bindings/tagselector.css +++ b/chrome/skin/default/zotero/bindings/tagselector.css @@ -25,19 +25,18 @@ checkbox padding: 0 .25em 0 .25em !important; -moz-user-focus: ignore; max-width: 250px; + border: 1px solid transparent; /* always include border so height is same as zotero-clicky */ } /* Visible out-of-scope tags should be grey */ -#tags-toggle label[inScope="false"] +#tags-toggle label[inScope=false]:not([hasColor=true]) { color: #666 !important; } -/* Don't display clicky effect to out-of-scope icons */ -label.zotero-clicky[inScope="false"]:hover, -label.zotero-clicky[inScope="false"]:active +#tags-toggle label[inScope=false][hasColor=true] { - background: inherit !important; + opacity: .6; } #tags-toggle label[draggedOver="true"]