diff --git a/chrome/content/zotero/xpcom/editorInstance.js b/chrome/content/zotero/xpcom/editorInstance.js
index 9ca282858f..fbed160690 100644
--- a/chrome/content/zotero/xpcom/editorInstance.js
+++ b/chrome/content/zotero/xpcom/editorInstance.js
@@ -44,7 +44,7 @@ const DOWNLOADED_IMAGE_TYPE = [
];
// Schema version here has to be the same as in note-editor!
-const SCHEMA_VERSION = 5;
+const SCHEMA_VERSION = 6;
class EditorInstance {
constructor() {
@@ -301,7 +301,7 @@ class EditorInstance {
walkFormat(doc.body);
return doc.body.innerHTML;
}
-
+
/**
* @param {Object[]} annotations JSON annotations
* @param {Boolean} skipEmbeddingItemData Do not add itemData to citation items
@@ -325,6 +325,7 @@ class EditorInstance {
let citationHTML = '';
let imageHTML = '';
let highlightHTML = '';
+ let quotedHighlightHTML = '';
let commentHTML = '';
let storedAnnotation = {
@@ -389,23 +390,40 @@ class EditorInstance {
// Text
if (annotation.text) {
let text = this._transformTextToHTML(annotation.text.trim());
- highlightHTML = `“${text}”`;
+ highlightHTML = `${text}`;
+ quotedHighlightHTML = `${Zotero.getString('punctuation.openingQMark')}${text}${Zotero.getString('punctuation.closingQMark')}`;
}
// Note
if (annotation.comment) {
- let comment = this._transformTextToHTML(annotation.comment.trim());
- // Move comment to the next line if it has multiple lines
- commentHTML = (((highlightHTML || imageHTML || citationHTML) && comment.includes('
' : ' ') + comment;
+ commentHTML = this._transformTextToHTML(annotation.comment.trim());
}
-
- if (citationHTML) {
- // Move citation to the next line if highlight has multiple lines or is after image
- citationHTML = ((highlightHTML && highlightHTML.includes('
' : '') + citationHTML;
+
+ let template;
+ if (annotation.type === 'highlight') {
+ template = Zotero.Prefs.get('annotations.noteTemplates.highlight');
}
-
- let otherHTML = [highlightHTML, citationHTML, commentHTML].filter(x => x).join(' ');
- html += '
' + imageHTML + otherHTML + '
\n'; + else if (annotation.type === 'note') { + template = Zotero.Prefs.get('annotations.noteTemplates.note'); + } + else if (annotation.type === 'image') { + template = '{{image}}
{{citation}} {{comment}}
{{comment}}:
{{endif}}{{highlight}}
{{citation}}
+ * {{else}} + *{{highlight}} {{citation}} {{comment}} {{if tags}} #{{tags join=' #'}}{{endif}}
+ * {{endif}} + * + * @param {String} template + * @param {Object} vars + * @returns {String} HTML + */ + generateHTMLFromTemplate: function (template, vars) { + let levels = [{ condition: true }]; + let html = ''; + let parts = template.split(/{{|}}/); + for (let i = 0; i < parts.length; i++) { + let part = parts[i]; + let level = levels[levels.length - 1]; + if (i % 2 === 1) { + let operator = part.split(' ').filter(x => x)[0]; + // Get arguments that are used for 'if' + let args = []; + let match = part.match(/(["'][^"|^']+["']|[^\s"']+)/g); + if (match) { + args = match.map(x => x.replace(/['"](.*)['"]/, '$1')).slice(1); + } + if (operator === 'if') { + level = { condition: false, executed: false, parentCondition: levels[levels.length-1].condition }; + levels.push(level); + } + if (['if', 'elseif'].includes(operator)) { + if (!level.executed) { + level.condition = level.parentCondition && (args[2] ? vars[args[0]].toLowerCase() == args[2].toLowerCase() : !!vars[args[0]]); + level.executed = level.condition; + } + else { + level.condition = false; + } + continue; + } + else if (operator === 'else') { + level.condition = level.parentCondition && !level.executed; + level.executed = level.condition; + continue; + } + else if (operator === 'endif') { + levels.pop(); + continue; + } + if (level.condition) { + // Get attributes i.e. join=" #" + let attrsRegexp = new RegExp(/((\w*) *=+ *(['"])((\\\3|[^\3])*?)\3)|((\w*) *=+ *(\w*))/g); + let attrs = {}; + while ((match = attrsRegexp.exec(part))) { + if (match[4]) { + attrs[match[2]] = match[4]; + } + else { + attrs[match[7]] = match[8]; + } + } + html += (typeof vars[operator] === 'function' ? vars[operator](attrs) : vars[operator]) || ''; + } + } + else if (level.condition) { + html += part; + } + } + return html; } } diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 39927f1a0e..924978b208 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -108,8 +108,8 @@ about.createdBy = %1$S is a project of %2$S and is developed by a [global commun about.openSource = %S is [open-source software] and depends on many [exceptional open-source projects]. about.getInvolved = Want to help? [Get involved] today! -punctuation.openingQMark = " -punctuation.closingQMark = " +punctuation.openingQMark = “ +punctuation.closingQMark = ” punctuation.colon = : punctuation.ellipsis = … diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index 832db2deb6..4e63e598d5 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -193,3 +193,8 @@ pref("extensions.zotero.translators.RIS.import.keepID", false); // Retracted Items pref("extensions.zotero.retractions.enabled", true); pref("extensions.zotero.retractions.recentItems", "[]"); + +// Annotations +pref("extensions.zotero.annotations.noteTemplates.title", "{{highlight quotes='true'}} {{citation}} {{comment}}
"); +pref("extensions.zotero.annotations.noteTemplates.note", "{{citation}} {{comment}}
"); diff --git a/note-editor b/note-editor index 6ba8de80ff..a5ba343501 160000 --- a/note-editor +++ b/note-editor @@ -1 +1 @@ -Subproject commit 6ba8de80ff64558f7cc727355b69eaca0ae3dcad +Subproject commit a5ba3435011938a68799f6b169e2e89b574cfded diff --git a/pdf-reader b/pdf-reader index 4f14537a31..c5b1bc4dfd 160000 --- a/pdf-reader +++ b/pdf-reader @@ -1 +1 @@ -Subproject commit 4f14537a31ed66152d99a949d554b8e7ef7f1260 +Subproject commit c5b1bc4dfd88001f0e92ff82dc264f514eb00984 diff --git a/test/tests/utilities_internalTest.js b/test/tests/utilities_internalTest.js index 70fb73351b..f8122036f9 100644 --- a/test/tests/utilities_internalTest.js +++ b/test/tests/utilities_internalTest.js @@ -522,4 +522,26 @@ describe("Zotero.Utilities.Internal", function () { }); }); }); + + describe("#generateHTMLFromTemplate()", function () { + it("should support variables with attributes", function () { + var vars = { + v1: '1', + v2: (pars) => pars.a1 + pars.a2 + pars.a3, + v3: () => undefined, + }; + var template = `{{ v1}}{{v2 a1= 1 a2 =' 2' a3 = "3 "}}{{v3}}{{v4}}`; + var html = Zotero.Utilities.Internal.generateHTMLFromTemplate(template, vars); + assert.equal(html, '11 23 '); + }); + it("should support nested 'if' statements", function () { + var vars = { + v1: '1', + v2: 'H', + }; + var template = `{{if v1 == '1'}}yes1{{if x}}no{{elseif v2 == h }}yes2{{endif}}{{elseif v2 == 2}}no{{else}}no{{endif}} {{if v2 == 1}}not{{elseif x}}not{{else}}yes3{{ endif}}`; + var html = Zotero.Utilities.Internal.generateHTMLFromTemplate(template, vars); + assert.equal(html, 'yes1yes2 yes3'); + }); + }); })