From db0ac723fad1c879501cfa2c3c032eb3d1677664 Mon Sep 17 00:00:00 2001 From: Martynas Bagdonas Date: Thu, 26 May 2022 18:16:40 +0300 Subject: [PATCH] fx-compat: Note editor and links box fixes: - Add links-box component (inside noteEditor.js). - Add related-box component and fix related pane. - Use tagsBox.jsx instead of tagsbox.xml in note editor links box popup. - Remove CSS styles and bindings for noteeditor, relatedbox and tagsbox. --- .../zotero-platform/mac/noteeditor.css | 8 - .../zotero-platform/unix/noteeditor.css | 0 .../zotero-platform/win/noteeditor.css | 0 chrome/content/zotero/bindings/noteeditor.xml | 603 --------- chrome/content/zotero/bindings/relatedbox.xml | 351 ----- chrome/content/zotero/bindings/tagsbox.xml | 1183 ----------------- chrome/content/zotero/contextPane.js | 4 +- chrome/content/zotero/elements/noteEditor.js | 368 +++-- chrome/content/zotero/elements/relatedBox.js | 265 ++++ chrome/content/zotero/note.xhtml | 6 + chrome/content/zotero/zoteroPane.xhtml | 3 +- .../default/zotero/bindings/noteeditor.css | 58 - .../skin/default/zotero/bindings/tagsbox.css | 7 - scss/_noteEditor.scss | 4 + scss/_relatedBox.scss | 2 + scss/components/_noteEditor.scss | 26 + scss/components/_relatedBox.scss | 42 + scss/components/_tagsBox.scss | 4 - scss/noteEditor-mac.scss | 1 + scss/noteEditor-unix.scss | 1 + scss/noteEditor-win.scss | 1 + scss/relatedBox-mac.scss | 1 + scss/relatedBox-unix.scss | 1 + scss/relatedBox-win.scss | 1 + 24 files changed, 634 insertions(+), 2306 deletions(-) delete mode 100644 chrome/content/zotero-platform/mac/noteeditor.css delete mode 100644 chrome/content/zotero-platform/unix/noteeditor.css delete mode 100644 chrome/content/zotero-platform/win/noteeditor.css delete mode 100644 chrome/content/zotero/bindings/noteeditor.xml delete mode 100644 chrome/content/zotero/bindings/relatedbox.xml delete mode 100644 chrome/content/zotero/bindings/tagsbox.xml create mode 100644 chrome/content/zotero/elements/relatedBox.js delete mode 100644 chrome/skin/default/zotero/bindings/noteeditor.css delete mode 100644 chrome/skin/default/zotero/bindings/tagsbox.css create mode 100644 scss/_noteEditor.scss create mode 100644 scss/_relatedBox.scss create mode 100644 scss/components/_noteEditor.scss create mode 100644 scss/components/_relatedBox.scss create mode 100644 scss/noteEditor-mac.scss create mode 100644 scss/noteEditor-unix.scss create mode 100644 scss/noteEditor-win.scss create mode 100644 scss/relatedBox-mac.scss create mode 100644 scss/relatedBox-unix.scss create mode 100644 scss/relatedBox-win.scss diff --git a/chrome/content/zotero-platform/mac/noteeditor.css b/chrome/content/zotero-platform/mac/noteeditor.css deleted file mode 100644 index 9465847767..0000000000 --- a/chrome/content/zotero-platform/mac/noteeditor.css +++ /dev/null @@ -1,8 +0,0 @@ -row > label:first-child -{ - color: #7f7f7f; -} - -textbox[type="styled"] { - border-style: none; -} \ No newline at end of file diff --git a/chrome/content/zotero-platform/unix/noteeditor.css b/chrome/content/zotero-platform/unix/noteeditor.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/chrome/content/zotero-platform/win/noteeditor.css b/chrome/content/zotero-platform/win/noteeditor.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/chrome/content/zotero/bindings/noteeditor.xml b/chrome/content/zotero/bindings/noteeditor.xml deleted file mode 100644 index 8dc4d400cc..0000000000 --- a/chrome/content/zotero/bindings/noteeditor.xml +++ /dev/null @@ -1,603 +0,0 @@ - - - - - - - - - - - - - - false - false - false - false - - - - - - - - - - - - { - // For iframes without chrome priviledges, for unknown reasons, - // dataTransfer.getData() returns empty value for `drop` event - // when dragging something from the outside of Zotero - this._iframe.contentWindow.addEventListener('drop', (event) => { - this._iframe.contentWindow.wrappedJSObject.droppedData = Components.utils.cloneInto({ - 'text/plain': event.dataTransfer.getData('text/plain'), - 'text/html': event.dataTransfer.getData('text/html'), - 'zotero/annotation': event.dataTransfer.getData('zotero/annotation'), - 'zotero/item': event.dataTransfer.getData('zotero/item') - }, this._iframe.contentWindow); - }, true); - this._initialized = true; - }); - - window.fillTooltip = (tooltip) => { - let node = window.document.tooltipNode.closest('*[title]'); - if (!node || !node.getAttribute('title')) { - return false; - } - tooltip.setAttribute('label', node.getAttribute('title')); - return true; - } - - this.saveSync = () => { - if (this._editorInstance) { - this._editorInstance.saveSync(); - } - } - - this.getCurrentInstance = () => { - return this._editorInstance; - } - - this.initEditor = async (state, reloaded) => { - if (this._editorInstance) { - this._editorInstance.uninit(); - } - - // Automatically upgrade editable v1 note before it's loaded - // TODO: Remove this at some point - if (this.editable) { - await Zotero.Notes.upgradeSchemaV1(this._item); - } - - this._editorInstance = new Zotero.EditorInstance(); - await this._editorInstance.init({ - state, - item: this._item, - reloaded, - iframeWindow: document.getAnonymousElementByAttribute(this, 'anonid', 'editor-view').contentWindow, - popup: document.getAnonymousElementByAttribute(this, 'anonid', 'editor-menu'), - onNavigate: this._navigateHandler, - viewMode: this.viewMode, - readOnly: !this.editable, - disableUI: this.mode == 'merge', - onReturn: this._returnHandler, - placeholder: this.placeholder - }); - if (this._onInitCallback) { - this._onInitCallback(); - } - } - - this.onInit = (callback) => { - if (this._editorInstance) { - return callback(); - } - this._onInitCallback = callback; - } - - this.notify = async (event, type, ids, extraData) => { - if (this._editorInstance) { - await this._editorInstance.notify(event, type, ids, extraData); - } - - if (!this.item) return; - // Try to use the state from the item save event - let id = this.item.id; - if (ids.includes(id)) { - if (event == 'delete') { - if (this._returnHandler) { - this._returnHandler(); - } - } - else { - let state = extraData && extraData[id] && extraData[id].state; - if (state) { - if (extraData[id].noteEditorID !== this._editorInstance.instanceID) { - this.initEditor(state, true); - } - } - else { - let curValue = this.item.note; - if (curValue !== this._lastHtmlValue) { - this.initEditor(null, true); - } - } - this._lastHtmlValue = this.item.note; - } - } - - this._id('links-container').hidden = !(this.displayTags && this.displayRelated) || this._hideLinksContainer; - this._id('links-box').refresh(); - } - - this._notifierID = Zotero.Notifier.registerObserver(this, ['item', 'file'], 'noteeditor'); - ]]> - - - - - "view" - - - - - - - - - - - - - - - - - - - - - - - { - // `item` field can be set before the constructor is called - // or noteeditor is attached to dom (which happens in the - // merge dialog i.e.), therefore we wait for the initialization - let n = 0; - while (!this._initialized && !this._destroyed) { - if (n >= 1000) { - throw new Error('Waiting for noteeditor initialization failed'); - } - await Zotero.Promise.delay(10); - n++; - } - - if (this._destroyed) { - return; - } - - this.initEditor(); - this._id('links-box').item = this._item; - })(); - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - { - - })(); - ]]> - - - - - { - let n = 0; - while (!this._editorInstance && n++ < 100) { - await Zotero.Promise.delay(10); - } - await this._editorInstance._initPromise; - this._iframe.focus(); - this._editorInstance.focus(); - })(); - ]]> - - - - - - { - let n = 0; - while (!this._editorInstance && n++ < 100) { - await Zotero.Promise.delay(10); - } - await this._editorInstance._initPromise; - this._iframe.focus(); - try { - this._editorInstance._iframeWindow.document.querySelector('.toolbar-button-return').focus(); - } catch(e) { - } - })(); - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { - let target = event.originalTarget; - if (target.classList.contains('zotero-box-label')) { - this.id('relatedPopup').hidePopup(); - } - }); - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - 0) { - var x = this.boxObject.screenX; - var y = this.boxObject.screenY; - this.id('relatedPopup').openPopupAtScreen(x, y, false); - } - else { - this.id('related').add(); - } - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/chrome/content/zotero/bindings/relatedbox.xml b/chrome/content/zotero/bindings/relatedbox.xml deleted file mode 100644 index aa080d51fc..0000000000 --- a/chrome/content/zotero/bindings/relatedbox.xml +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - - - "view" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Zotero.Items.getIDFromLibraryAndKey(libraryID, key))); - for (let id of ids) { - if (relatedItemIDs.has(id)) { - this.refresh(); - return; - } - } - } - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/chrome/content/zotero/bindings/tagsbox.xml b/chrome/content/zotero/bindings/tagsbox.xml deleted file mode 100644 index 67f74ba1f5..0000000000 --- a/chrome/content/zotero/bindings/tagsbox.xml +++ /dev/null @@ -1,1183 +0,0 @@ - - - - - - - - - - - - - - - false - - - - - - "view" - - - - - - - - - - - - - - - - - collation.compareString(1, a.tag, b.tag)); - - for (let i = 0; i < tags.length; i++) { - r = r + tags[i].tag + ", "; - } - r = r.substr(0,r.length-2); - } - - return r; - ]]> - - - - - - - - - - - - - - - - - - val.split("/")[1] == 'tagColors') && this.item) { - this.reload(); - return; - } - } - else if (type == 'item-tag') { - let itemID, tagID; - - for (let i=0; i parseInt(x)); - if (!this.item || itemID != this.item.id) { - continue; - } - let data = extraData[ids[i]]; - let tagName = data.tag; - let tagType = data.type; - - if (event == 'add') { - var newTabIndex = this.add(tagName, tagType); - if (newTabIndex == -1) { - return; - } - if (this._tabDirection == -1) { - if (this._lastTabIndex > newTabIndex) { - this._lastTabIndex++; - } - } - else if (this._tabDirection == 1) { - if (this._lastTabIndex > newTabIndex) { - this._lastTabIndex++; - } - } - } - else if (event == 'modify') { - let oldTagName = data.old.tag; - this.remove(oldTagName); - this.add(tagName, tagType); - } - else if (event == 'remove') { - var oldTabIndex = this.remove(tagName); - 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(); - return; - } - } - }.bind(this)); - ]]> - - - - - collation.compareString(1, a.tag, b.tag)); - - for (let i=0; i - - - - - - - - - - - - - - - - - - - - - - - - - - 29 ) || firstSpace > 29) { - valueElement.setAttribute('crop', 'end'); - valueElement.setAttribute('value',valueText); - } - else { - // Wrap to multiple lines - valueElement.appendChild(document.createTextNode(valueText)); - } - - // Tag color - var colorData = this._tagColors.get(valueText); - if (colorData) { - valueElement.style.color = colorData.color; - valueElement.style.fontWeight = 'bold'; - } - - return valueElement; - ]]> - - - - - - - - - 1) { - t.setAttribute('multiline', true); - t.setAttribute('rows', rows); - } - // Add auto-complete - else { - t.setAttribute('type', 'autocomplete'); - t.setAttribute('autocompletesearch', 'zotero'); - let params = { - fieldName: fieldName, - libraryID: this.item.libraryID - }; - params.itemID = itemID ? itemID : ''; - t.setAttribute( - 'autocompletesearchparam', JSON.stringify(params) - ); - t.setAttribute('completeselectedindex', true); - } - - var box = elem.parentNode; - box.replaceChild(t, elem); - - t.setAttribute('onblur', "return document.getBindingParent(this).blurHandler(event)"); - t.setAttribute('onkeypress', "return document.getBindingParent(this).handleKeyPress(event)"); - t.setAttribute('onpaste', "return document.getBindingParent(this).handlePaste(event)"); - - this._tabDirection = false; - this._lastTabIndex = tabindex; - - // Prevent error when clicking between a changed field - // and another -- there's probably a better way - if (!t.select) { - return; - } - t.select(); - - return t; - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - val.trim()); - - // Modifying existing tag with a single new one - if (!isNew && tags.length < 2) { - if (value !== "") { - if (oldValue !== value) { - // The existing textbox will be removed in notify() - this.removeRow(row); - this.add(value); - if (event.type != 'blur') { - this._focusField(); - } - try { - this.item.replaceTag(oldValue, value); - yield this.item.saveTx(); - } - catch (e) { - this.reload(); - throw e; - } - } - } - // Existing tag cleared - else { - try { - this.removeRow(row); - if (event.type != 'blur') { - this._focusField(); - } - this.item.removeTag(oldValue); - yield this.item.saveTx(); - } - catch (e) { - this.reload(); - throw e; - } - } - } - // Multiple tags - else if (tags.length > 1) { - var lastTag = row == row.parentNode.lastChild; - - if (!isNew) { - // If old tag isn't in array, remove it - if (tags.indexOf(oldValue) == -1) { - this.item.removeTag(oldValue); - } - // If old tag is staying, restore the textbox - // immediately. This isn't strictly necessary, but it - // makes the transition nicer. - else { - textbox.value = textbox.getAttribute('value'); - this.textboxToLabel(textbox); - } - } - - tags.forEach(tag => this.item.addTag(tag)); - yield this.item.saveTx(); - - if (lastTag) { - this._lastTabIndex = this.item.getTags().length; - } - - this.reload(); - } - // Single tag at end - else { - if (event.type == 'blur') { - this.removeRow(row); - } - else { - textbox.value = ''; - } - this.add(value); - this.item.addTag(value); - try { - yield this.item.saveTx(); - } - catch (e) { - this.reload(); - throw e; - } - } - }.bind(this)); - ]]> - - - - - - { - row.firstChild.nextSibling.click(); - }, 50); - - return row; - ]]> - - - - - - - - - - - - - - 0 - // Ignore textbox at end - && labels[i].tagName != 'textbox') { - 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); - } - - this.updateCount(this.count + 1); - - return newTabIndex; - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js index 00883a0c25..38fba2b853 100644 --- a/chrome/content/zotero/contextPane.js +++ b/chrome/content/zotero/contextPane.js @@ -269,7 +269,7 @@ var ZoteroContextPane = new function () { else { var node = _notesPaneDeck.selectedPanel; if (node.selectedIndex == 0) { - node.querySelector('textbox').focus(); + node.querySelector('search-textbox').focus(); return true; } else { @@ -873,7 +873,7 @@ var ZoteroContextPane = new function () { ); // Related panel var panelRelated = document.createXULElement('tabpanel'); - var relatedBox = document.createXULElement('relatedbox'); + var relatedBox = new (customElements.get('related-box')); relatedBox.setAttribute('flex', '1'); relatedBox.className = 'zotero-editpane-related'; panelRelated.addEventListener('click', (event) => { diff --git a/chrome/content/zotero/elements/noteEditor.js b/chrome/content/zotero/elements/noteEditor.js index 03ebe25108..ec1d865ff9 100644 --- a/chrome/content/zotero/elements/noteEditor.js +++ b/chrome/content/zotero/elements/noteEditor.js @@ -1,7 +1,7 @@ /* ***** BEGIN LICENSE BLOCK ***** - Copyright © 2020 Corporation for Digital Scholarship + Copyright © 2021 Corporation for Digital Scholarship Vienna, Virginia, USA https://www.zotero.org @@ -30,49 +30,21 @@ constructor() { super(); - this.editable = false; - this.displayTags = false; - this.displayRelated = false; - this.displayButton = false; - this.hideLinksContainer = false; - - this.buttonCaption = null; - this.parentClickHandler = null; - this.keyDownHandler = null; - this.commandHandler = null; - this.clickHandler = null; - this.navigateHandler = null; - this.returnHandler = null; - + this._notitle = false; this._mode = 'view'; - this._destroyed = false; - this._noteEditorID = Zotero.Utilities.randomString(); + this._item = null; + this._parentItem = null; this._iframe = null; this._initialized = true; this._editorInstance = null; - this._item = null; - this._parentItem = null; - - this.clickable = false; - this.editable = false; - this.saveOnEdit = false; - this.showTypeMenu = false; - this.hideEmptyFields = false; - this.clickByRow = false; - this.clickByItem = false; - - this.clickHandler = null; - this.blurHandler = null; - this.eventHandlers = []; - - this._mode = 'view'; + this._destroyed = false; this.content = MozXULElement.parseXULToFragment(`