Render markup in item tree, strip when sorting (#2355)

This commit is contained in:
Abe Jellinek 2022-02-19 12:49:35 -08:00 committed by GitHub
parent a45da8df17
commit 13f48ec5c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 17 deletions

View file

@ -41,6 +41,7 @@ const CHILD_INDENT = 12;
const COLORED_TAGS_RE = new RegExp("^[0-" + Zotero.Tags.MAX_COLORED_TAGS + "]{1}$");
const COLUMN_PREFS_FILEPATH = OS.Path.join(Zotero.Profile.dir, "treePrefs.json");
const EMOJI_RE = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;
const HTML_NS = "http://www.w3.org/1999/xhtml";
var ItemTree = class ItemTree extends LibraryTree {
static async init(domEl, opts={}) {
@ -130,7 +131,7 @@ var ItemTree = class ItemTree extends LibraryTree {
this._itemTreeLoadingDeferred.resolve();
// Create an element where we can create drag images to be displayed next to the cursor while dragging
// since for multiple item drags we need to display all the elements
let elem = this._dragImageContainer = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
let elem = this._dragImageContainer = document.createElementNS(HTML_NS, "div");
elem.style.width = "100%";
elem.style.height = "2000px";
elem.style.position = "absolute";
@ -2553,15 +2554,105 @@ var ItemTree = class ItemTree extends LibraryTree {
//
// //////////////////////////////////////////////////////////////////////////////
_titleMarkup = {
'<i>': {
beginsTag: 'i',
inverseStyle: { fontStyle: 'normal' }
},
'</i>': {
endsTag: 'i'
},
'<b>': {
beginsTag: 'b',
inverseStyle: { fontWeight: 'normal' }
},
'</b>': {
endsTag: 'b'
},
'<sub>': {
beginsTag: 'sub'
},
'</sub>': {
endsTag: 'sub'
},
'<sup>': {
beginsTag: 'sup'
},
'</sup>': {
endsTag: 'sup'
},
'<span style="font-variant:small-caps;">': {
beginsTag: 'span',
style: { fontVariant: 'small-caps' }
},
'<span class="nocase">': {
// No effect in item tree
beginsTag: 'span'
},
'</span>': {
endsTag: 'span'
}
};
_renderItemTitle(title, targetNode) {
let markupStack = [];
let nodeStack = [targetNode];
let textContent = '';
for (let token of title.split(/(<[^>]+>)/)) {
if (this._titleMarkup.hasOwnProperty(token)) {
let markup = this._titleMarkup[token];
if (markup.beginsTag) {
let node = document.createElementNS(HTML_NS, markup.beginsTag);
if (markup.style) {
Object.assign(node.style, markup.style);
}
if (markup.inverseStyle && markupStack.some(otherMarkup => otherMarkup.beginsTag === markup.beginsTag)) {
Object.assign(node.style, markup.inverseStyle);
}
markupStack.push({ ...markup, token });
nodeStack.push(node);
continue;
}
else if (markup.endsTag && markupStack.some(otherMarkup => otherMarkup.beginsTag === markup.endsTag)) {
while (markupStack.length) {
let discardedMarkup = markupStack.pop();
let discardedNode = nodeStack.pop();
if (discardedMarkup.beginsTag === markup.endsTag) {
nodeStack[nodeStack.length - 1].append(discardedNode);
break;
}
else {
nodeStack[nodeStack.length - 1].append(discardedMarkup.token, ...discardedNode.childNodes);
}
}
continue;
}
}
nodeStack[nodeStack.length - 1].append(token);
textContent += token;
}
while (markupStack.length) {
let discardedMarkup = markupStack.pop();
let discardedNode = nodeStack.pop();
nodeStack[0].append(discardedMarkup.token, ...discardedNode.childNodes);
}
return textContent;
}
_renderPrimaryCell(index, data, column) {
let span = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
let span = document.createElementNS(HTML_NS, 'span');
span.className = `cell ${column.className}`;
span.classList.add('primary');
// Add twisty, icon, tag swatches and retraction indicator
let twisty;
if (this.isContainerEmpty(index)) {
twisty = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
twisty = document.createElementNS(HTML_NS, 'span');
twisty.classList.add("spacer-twisty");
}
else {
@ -2607,15 +2698,13 @@ var ItemTree = class ItemTree extends LibraryTree {
Zotero.debug(e, 1);
}
let textWithFullStop = data;
let textSpan = document.createElementNS(HTML_NS, 'span');
let textWithFullStop = this._renderItemTitle(data, textSpan);
if (!textWithFullStop.match(/\.$/)) {
textWithFullStop += '.';
}
let textSpanAriaLabel = [textWithFullStop, itemTypeAriaLabel, tagAriaLabel, retractedAriaLabel].join(' ');
let textSpan = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
textSpan.className = "cell-text";
textSpan.innerText = data;
textSpan.setAttribute('aria-label', textSpanAriaLabel);
span.append(twisty, icon, retracted, ...tagSpans, textSpan);
@ -2632,7 +2721,7 @@ var ItemTree = class ItemTree extends LibraryTree {
}
_renderHasAttachmentCell(index, data, column) {
let span = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
let span = document.createElementNS(HTML_NS, 'span');
span.className = `cell ${column.className}`;
if (this.collectionTreeRow.isTrash()) return span;
@ -2757,7 +2846,7 @@ var ItemTree = class ItemTree extends LibraryTree {
div.innerHTML = "";
}
else {
div = document.createElementNS("http://www.w3.org/1999/xhtml", 'div');
div = document.createElementNS(HTML_NS, 'div');
div.className = "row";
}
@ -2769,7 +2858,7 @@ var ItemTree = class ItemTree extends LibraryTree {
if (this._dropRow == index) {
let span;
if (Zotero.DragDrop.currentOrientation != 0) {
span = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
span = document.createElementNS(HTML_NS, 'span');
span.className = Zotero.DragDrop.currentOrientation < 0 ? "drop-before" : "drop-after";
div.appendChild(span);
} else {
@ -3699,7 +3788,7 @@ var ItemTree = class ItemTree extends LibraryTree {
var icon = getDOMElement(iconClsName);
if (!icon) {
Zotero.debug('Could not find tree icon for "' + itemType + '"');
return document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
return document.createElementNS(HTML_NS, 'span');
}
return icon;
}
@ -3710,7 +3799,7 @@ var ItemTree = class ItemTree extends LibraryTree {
}
_getTagSwatch(tag, color) {
let span = document.createElementNS("http://www.w3.org/1999/xhtml", 'span');
let span = document.createElementNS(HTML_NS, 'span');
span.className = 'tag-swatch';
// If only emoji, display directly
//

View file

@ -1688,15 +1688,30 @@ Zotero.Items = function() {
}
this.getSortTitle = function(title) {
if (title === false || title === undefined || title == null) {
this.getSortTitle = function (title) {
if (!title) {
return '';
}
if (typeof title == 'number') {
return title + '';
return title.toString();
}
return title.replace(/^[\[\'\"](.*)[\'\"\]]?$/, '$1')
}
let toRemove = [
'</?i>',
'</?b>',
'</?sub>',
'</?sup>',
'<span style="font-variant:small-caps;">',
'<span class="nocase">',
'</span>',
'\\p{P}'
].map(re => new RegExp(re, 'g'));
for (let re of toRemove) {
title = title.replace(re, '');
}
return title;
};
Zotero.DataObjects.call(this);