Show colored tags in tag selector in all views
Always show colored tags at the top of the tag selector, regardless of whether they're in the current scope. If not, they're shown with reduced opacity (as an equivalent to the gray style for out-of-scope tags in Display All Tags mode). As a corollary, colored tags are now shown even if they have no associated items and will remain until they're explicitly deleted. Also: - Don't show outline on out-of-scope tags in "Display All Tags" mode
This commit is contained in:
parent
2b7d7ebfbf
commit
6dbe1d1e19
3 changed files with 174 additions and 101 deletions
|
@ -100,21 +100,13 @@
|
|||
</getter>
|
||||
</property>
|
||||
|
||||
<field name="_hasFilter">false</field>
|
||||
<field name="_filter">null</field>
|
||||
<method name="setFilterTags">
|
||||
<field name="_search">null</field>
|
||||
<method name="setSearch">
|
||||
<parameter name="val"/>
|
||||
<parameter name="skipRefresh"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!Zotero.Utilities.isEmpty(val)) {
|
||||
this._hasFilter = true;
|
||||
this._filter = val;
|
||||
}
|
||||
else {
|
||||
this._hasFilter = !!val;
|
||||
this._filter = {};
|
||||
}
|
||||
this._search = val ? val.toLowerCase() : false;
|
||||
|
||||
if (!skipRefresh) {
|
||||
this.refresh();
|
||||
|
@ -128,12 +120,12 @@
|
|||
<property name="scope" onget="return this._scope">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
if (!Zotero.Utilities.isEmpty(val)) {
|
||||
if (val && !Zotero.Utilities.isEmpty(val)) {
|
||||
this._hasScope = true;
|
||||
this._scope = val;
|
||||
}
|
||||
else {
|
||||
this._hasScope = !!val;
|
||||
this._hasScope = false;
|
||||
this._scope = {};
|
||||
}
|
||||
|
||||
|
@ -236,8 +228,34 @@
|
|||
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<orderedTags.length; i++) {
|
||||
let tagObj = orderedTags[i];
|
||||
|
||||
// Skip colored tags in the regular section,
|
||||
// since we add them to the beginning above
|
||||
if (!tagObj.hasColor && tagColorsLowerCase[tagObj.name.toLowerCase()]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tagButton = self._makeClickableTag(orderedTags[i], lastTag, self.editable);
|
||||
if (tagButton) {
|
||||
tagButton.addEventListener('click', function(event) {
|
||||
|
@ -255,36 +273,58 @@
|
|||
self._dirty = false;
|
||||
}
|
||||
|
||||
var searchTags = self._search ? Zotero.Tags.search(self._search) : {};
|
||||
|
||||
// Set attributes
|
||||
var colorTags = {};
|
||||
var labels = tagsToggleBox.getElementsByTagName('label');
|
||||
for (let i=0; i<labels.length; i++) {
|
||||
var tagIDs = labels[i].getAttribute('tagID').split('-');
|
||||
var tagIDs = labels[i].getAttribute('tagID');
|
||||
tagIDs = tagIDs ? tagIDs.split('-') : [];
|
||||
|
||||
let name = labels[i].value;
|
||||
let lcname = name.toLowerCase();
|
||||
|
||||
let colorData = tagColors[name];
|
||||
if (colorData) {
|
||||
labels[i].setAttribute(
|
||||
'style', 'color:' + colorData.color + '; ' + 'font-weight: bold'
|
||||
);
|
||||
}
|
||||
else {
|
||||
labels[i].removeAttribute('style');
|
||||
}
|
||||
|
||||
// Restore selection
|
||||
if (self.selection[labels[i].value]){
|
||||
if (self.selection[name]){
|
||||
labels[i].setAttribute('selected', 'true');
|
||||
}
|
||||
else {
|
||||
labels[i].setAttribute('selected', 'false');
|
||||
}
|
||||
|
||||
// Check tags against filter
|
||||
if (self._hasFilter) {
|
||||
var inFilter = false;
|
||||
for each(var tagID in tagIDs) {
|
||||
if (self._filter[tagID]) {
|
||||
inFilter = true;
|
||||
break;
|
||||
// Check tags against search
|
||||
if (self._search) {
|
||||
var inSearch = false;
|
||||
if (tagIDs.length) {
|
||||
for (let i=0; i<tagIDs.length; i++) {
|
||||
if (searchTags[tagIDs[i]]) {
|
||||
inSearch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For colored tags, compare by name
|
||||
else if (lcname.indexOf(self._search) != -1) {
|
||||
inSearch = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check tags against scope
|
||||
if (self._hasScope) {
|
||||
var inScope = false;
|
||||
for each(var tagID in tagIDs) {
|
||||
if (self._scope[tagID]) {
|
||||
for (let i=0; i<tagIDs.length; i++) {
|
||||
if (self._scope[tagIDs[i]]) {
|
||||
inScope = true;
|
||||
break;
|
||||
}
|
||||
|
@ -292,24 +332,26 @@
|
|||
|
||||
// If tag isn't in scope and is still selected,
|
||||
// deselect it
|
||||
if (!inScope && self.selection[labels[i].value]) {
|
||||
if (!inScope && self.selection[name]) {
|
||||
labels[i].setAttribute('selected', false);
|
||||
delete self.selection[labels[i].value];
|
||||
delete self.selection[name];
|
||||
var doCommand = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If not in filter, hide
|
||||
if (self._hasFilter && !inFilter) {
|
||||
// If not in search, hide
|
||||
if (self._search && !inSearch) {
|
||||
labels[i].setAttribute('hidden', true);
|
||||
}
|
||||
else if (self.filterToScope) {
|
||||
if (self._hasScope && inScope) {
|
||||
labels[i].className = 'zotero-clicky';
|
||||
labels[i].setAttribute('inScope', true);
|
||||
labels[i].setAttribute('hidden', false);
|
||||
empty = false;
|
||||
}
|
||||
else {
|
||||
labels[i].className = '';
|
||||
labels[i].setAttribute('hidden', true);
|
||||
labels[i].setAttribute('inScope', false);
|
||||
}
|
||||
|
@ -317,9 +359,11 @@
|
|||
// Display all
|
||||
else {
|
||||
if (self._hasScope && inScope) {
|
||||
labels[i].className = 'zotero-clicky';
|
||||
labels[i].setAttribute('inScope', true);
|
||||
}
|
||||
else {
|
||||
labels[i].className = '';
|
||||
labels[i].setAttribute('inScope', false);
|
||||
}
|
||||
|
||||
|
@ -327,28 +371,16 @@
|
|||
empty = false;
|
||||
}
|
||||
|
||||
let colorData = tagColors[labels[i].value];
|
||||
// Always show colored tags at top
|
||||
if (colorData) {
|
||||
labels[i].setAttribute(
|
||||
'style', 'color:' + colorData.color + '; ' + 'font-weight: bold'
|
||||
);
|
||||
colorTags[colorData.position] = tagsToggleBox.removeChild(labels[i]);
|
||||
// The HTMLCollection returned by getElementsByTagName() is live,
|
||||
// so since we removed something we need to decrement the counter
|
||||
i--;
|
||||
labels[i].setAttribute('hidden', false);
|
||||
labels[i].setAttribute('hasColor', true);
|
||||
}
|
||||
else {
|
||||
labels[i].removeAttribute('style');
|
||||
labels[i].removeAttribute('hasColor');
|
||||
}
|
||||
}
|
||||
|
||||
// Add color tags to beginning in order
|
||||
var positions = Object.keys(colorTags);
|
||||
positions.sort();
|
||||
for (var i=positions.length-1; i>=0; i--) {
|
||||
tagsToggleBox.insertBefore(colorTags[positions[i]], tagsToggleBox.firstChild);
|
||||
}
|
||||
|
||||
//start tag cloud code
|
||||
|
||||
var tagCloud = Zotero.Prefs.get('tagCloud');
|
||||
|
@ -524,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();
|
||||
|
||||
|
@ -598,7 +635,7 @@
|
|||
if (typeof clear != 'undefined') {
|
||||
if (clear){
|
||||
t.value = '';
|
||||
this.setFilterTags(false);
|
||||
this.setSearch();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
@ -606,7 +643,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
this.setFilterTags(Zotero.Tags.search(t.value));
|
||||
if (t.value) {
|
||||
this.setSearch(t.value);
|
||||
}
|
||||
else {
|
||||
this.setSearch();
|
||||
}
|
||||
return true;
|
||||
]]>
|
||||
</body>
|
||||
|
@ -647,16 +689,9 @@
|
|||
|
||||
|
||||
<method name="rename">
|
||||
<parameter name="tagIDs"/>
|
||||
<parameter name="oldName"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
tagIDs = tagIDs.split('-');
|
||||
// Convert to ints
|
||||
for (var i=0; i<tagIDs.length; i++) {
|
||||
tagIDs[i] = parseInt(tagIDs[i]);
|
||||
}
|
||||
var oldName = Zotero.Tags.getName(tagIDs[0]);
|
||||
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
|
@ -666,16 +701,13 @@
|
|||
Zotero.getString('pane.tagSelector.rename.message'),
|
||||
newName, '', {});
|
||||
|
||||
if (result && newName.value) {
|
||||
// Add other ids with same tag
|
||||
var ids = Zotero.Tags.getIDs(oldName, this.libraryID);
|
||||
|
||||
for (var i=0; i<ids.length; i++) {
|
||||
if (tagIDs.indexOf(ids[i]) == -1) {
|
||||
tagIDs.push(ids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result || !newName.value || oldName == newName.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current tagIDs with the old name
|
||||
var tagIDs = Zotero.Tags.getIDs(oldName, this.libraryID) || [];
|
||||
if (tagIDs.length) {
|
||||
if (this.selection[oldName]) {
|
||||
var wasSelected = true;
|
||||
delete this.selection[oldName];
|
||||
|
@ -696,18 +728,47 @@
|
|||
Q.all(promises)
|
||||
.done();
|
||||
}
|
||||
// Colored tags don't need to exist, so in that case
|
||||
// just rename the color setting
|
||||
else {
|
||||
var self = this;
|
||||
Zotero.Tags.getColor(this.libraryID, oldName)
|
||||
.then(function (color) {
|
||||
if (color) {
|
||||
if (self.selection[oldName]) {
|
||||
var wasSelected = true;
|
||||
delete self.selection[oldName];
|
||||
}
|
||||
|
||||
return Zotero.Tags.setColor(
|
||||
self.libraryID, oldName, false
|
||||
)
|
||||
.then(function () {
|
||||
return Zotero.Tags.setColor(
|
||||
self.libraryID, newName, color
|
||||
)
|
||||
.then(function () {
|
||||
if (wasSelected) {
|
||||
self.selection[newName.value] = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
throw new Error("Can't rename missing tag");
|
||||
}
|
||||
})
|
||||
.done();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="delete">
|
||||
<parameter name="tagIDs"/>
|
||||
<parameter name="name"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
tagIDs = tagIDs.split('-');
|
||||
var oldName = Zotero.Tags.getName(tagIDs[0]);
|
||||
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
|
@ -719,17 +780,26 @@
|
|||
Zotero.DB.beginTransaction();
|
||||
|
||||
// Add other ids with same tag
|
||||
var ids = Zotero.Tags.getIDs(oldName, this.libraryID);
|
||||
var ids = Zotero.Tags.getIDs(name, this.libraryID);
|
||||
var tagIDs = [];
|
||||
for each(var id in ids) {
|
||||
if (tagIDs.indexOf(id) == -1) {
|
||||
tagIDs.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Tags.erase(tagIDs);
|
||||
Zotero.Tags.purge(tagIDs);
|
||||
if (tagIDs.length) {
|
||||
Zotero.Tags.erase(tagIDs);
|
||||
Zotero.Tags.purge(tagIDs);
|
||||
}
|
||||
|
||||
Zotero.DB.commitTransaction()
|
||||
|
||||
// If only a tag color setting, remove that
|
||||
if (!tagIDs.length) {
|
||||
Zotero.Tags.setColor(this.libraryID, name, false);
|
||||
}
|
||||
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -765,10 +835,12 @@
|
|||
}
|
||||
|
||||
var label = document.createElement('label');
|
||||
label.className = 'zotero-clicky';
|
||||
|
||||
label.setAttribute('value', tagName);
|
||||
label.setAttribute('tagID', tagID);
|
||||
// Not used for color tags
|
||||
if (tagID) {
|
||||
label.setAttribute('tagID', tagID);
|
||||
}
|
||||
label.setAttribute('tagType', tagType);
|
||||
if (editable) {
|
||||
label.setAttribute('context', 'tag-menu');
|
||||
|
@ -780,14 +852,12 @@
|
|||
|
||||
|
||||
<method name="_openColorPickerWindow">
|
||||
<parameter name="tagIDs"/>
|
||||
<parameter name="name"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
tagIDs = tagIDs.split('-');
|
||||
|
||||
var io = {
|
||||
libraryID: this.libraryID,
|
||||
name: Zotero.Tags.getName(tagIDs[0])
|
||||
name: name
|
||||
};
|
||||
|
||||
var self = this;
|
||||
|
@ -876,7 +946,8 @@
|
|||
|
||||
// Find a manual tag if there is one
|
||||
var tagID = null;
|
||||
var tagIDs = node.getAttribute('tagID').split(/\-/);
|
||||
var tagIDs = node.getAttribute('tagID');
|
||||
tagIDs = tagIDs ? node.getAttribute('tagID').split(/\-/) : [];
|
||||
var tagTypes = node.getAttribute('tagType').split(/\-/);
|
||||
for (var i=0; i<tagIDs.length; i++) {
|
||||
if (tagTypes[i] == 0) {
|
||||
|
@ -919,9 +990,12 @@
|
|||
<content>
|
||||
<groupbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1">
|
||||
<menupopup id="tag-menu">
|
||||
<menuitem label="&zotero.tagSelector.assignColor;" oncommand="_openColorPickerWindow(document.popupNode.getAttribute('tagID')); event.stopPropagation()"/>
|
||||
<menuitem label="&zotero.tagSelector.renameTag;" oncommand="document.getBindingParent(this).rename(document.popupNode.getAttribute('tagID')); event.stopPropagation()"/>
|
||||
<menuitem label="&zotero.tagSelector.deleteTag;" oncommand="document.getBindingParent(this).delete(document.popupNode.getAttribute('tagID')); event.stopPropagation()"/>
|
||||
<menuitem label="&zotero.tagSelector.assignColor;"
|
||||
oncommand="_openColorPickerWindow(document.popupNode.getAttribute('value')); event.stopPropagation()"/>
|
||||
<menuitem label="&zotero.tagSelector.renameTag;"
|
||||
oncommand="document.getBindingParent(this).rename(document.popupNode.getAttribute('value')); event.stopPropagation()"/>
|
||||
<menuitem label="&zotero.tagSelector.deleteTag;"
|
||||
oncommand="document.getBindingParent(this).delete(document.popupNode.getAttribute('value')); event.stopPropagation()"/>
|
||||
</menupopup>
|
||||
|
||||
<vbox id="no-tags-box" align="center" pack="center" flex="1">
|
||||
|
|
|
@ -470,13 +470,6 @@ Zotero.Tags = new function() {
|
|||
|
||||
tagColors = tagColors || [];
|
||||
|
||||
// Remove colors for tags that don't exist
|
||||
tagColors = tagColors.filter(function (val) {
|
||||
var tagIDs = self.getIDs(val.name, libraryID);
|
||||
// TEMP: handle future getIDs return format change
|
||||
return tagIDs && tagIDs.length;
|
||||
});
|
||||
|
||||
_libraryColors[libraryID] = tagColors;
|
||||
_libraryColorsByName[libraryID] = {};
|
||||
|
||||
|
@ -510,13 +503,6 @@ Zotero.Tags = new function() {
|
|||
var tagColors = _libraryColors[libraryID];
|
||||
var tagIDs = self.getIDs(name, libraryID);
|
||||
|
||||
// Just to be safe, remove colors for tags that don't exist
|
||||
tagColors = tagColors.filter(function (val) {
|
||||
let tagIDs = self.getIDs(val.name, libraryID);
|
||||
// TEMP: handle future getIDs return format change
|
||||
return tagIDs && tagIDs.length;
|
||||
});
|
||||
|
||||
// Unset
|
||||
if (!color) {
|
||||
// Trying to clear color on tag that doesn't have one
|
||||
|
@ -835,14 +821,29 @@ Zotero.Tags = new function() {
|
|||
function erase(ids) {
|
||||
ids = Zotero.flattenArguments(ids);
|
||||
|
||||
var deleted = [];
|
||||
|
||||
Zotero.DB.beginTransaction();
|
||||
for each(var id in ids) {
|
||||
var tag = this.get(id);
|
||||
if (tag) {
|
||||
deleted.push({
|
||||
libraryID: tag.libraryID ? parseInt(tag.libraryID) : 0,
|
||||
name: tag.name
|
||||
});
|
||||
tag.erase();
|
||||
}
|
||||
}
|
||||
Zotero.DB.commitTransaction();
|
||||
|
||||
// Also delete tag color setting
|
||||
//
|
||||
// Note that this isn't done in purge(), so the setting will not
|
||||
// be removed if the tag is just removed from all items without
|
||||
// without being explicitly deleted.
|
||||
for (var i in deleted) {
|
||||
this.setColor(deleted[i].libraryID, deleted[i].name, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,16 +28,14 @@ checkbox
|
|||
}
|
||||
|
||||
/* 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"]
|
||||
|
|
Loading…
Add table
Reference in a new issue