refactor: seperate by modules
replace: treemodel.js with tree-model
This commit is contained in:
parent
8ce1452df0
commit
27c9553048
|
|
@ -40,7 +40,7 @@ In other type of templates, the default stage is called.
|
|||
|
||||
> variables: subNoteLines: string[], subNoteItem, noteItem
|
||||
|
||||
### QuickNoteV2
|
||||
### QuickNoteV3
|
||||
|
||||
> variables: annotationItem, topItem
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Only the template with specific name will be called.
|
|||
- QuickInsert: Called when inserting a note link to main note.
|
||||
- QuickBackLink: Called when inserting a note link to main note. The template will be inserted to the end of the sub-note and point to the main note by default.
|
||||
- QuickImport: Called when importing a sub-note to main note.
|
||||
- QuickNoteV2: Called when creating a note from an annotation.
|
||||
- QuickNoteV3: Called when creating a note from an annotation.
|
||||
> QuickNote is deprecated since v0.6.25
|
||||
- ExportMDFileName: Called when exporting notes to markdown in batch/linked notes to markdown mode. The rendered template will be file name.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@
|
|||
%knowledgeDTD;
|
||||
]>
|
||||
|
||||
<dialog id="betternotes-export-dialog" windowtype="betternotes-export" title="&zotero.__addonRef__.export.title;" orient="vertical" width="300" height="300" buttons="cancel,accept" ondialogaccept="Zotero.Knowledge4Zotero.export.doAccept();" onload="Zotero.Knowledge4Zotero.export.doLoad(window);" onunload="Zotero.Knowledge4Zotero.export.doUnload();" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" style="padding:2em" persist="screenX screenY width height">
|
||||
<dialog id="betternotes-export-dialog" windowtype="betternotes-export" title="&zotero.__addonRef__.export.title;" orient="vertical" width="300" height="300" buttons="cancel,accept" ondialogaccept="Zotero.Knowledge4Zotero.NoteExportWindow.doAccept();" onload="Zotero.Knowledge4Zotero.NoteExportWindow.doLoad(window);" onunload="Zotero.Knowledge4Zotero.NoteExportWindow.doUnload();" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" style="padding:2em" persist="screenX screenY width height">
|
||||
<script src="chrome://zotero/content/include.js" />
|
||||
<vbox flex="1">
|
||||
<groupbox flex="1">
|
||||
<caption label="&zotero.__addonRef__.export.option.label;"></caption>
|
||||
<rows flex="1">
|
||||
<row>
|
||||
<checkbox id="__addonRef__-export-embedLink" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.singlefile.enable.label;" checked="true" oncommand="Zotero.Knowledge4Zotero.export.doUpdate(event)" />
|
||||
<checkbox id="__addonRef__-export-embedLink" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.singlefile.enable.label;" checked="true" oncommand="Zotero.Knowledge4Zotero.NoteExportWindow.doUpdate(event)" />
|
||||
<label value="&zotero.__addonRef__.export.link.enable.label;" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.singlefile.enable.label;" />
|
||||
</row>
|
||||
<row>
|
||||
|
|
@ -31,15 +31,15 @@
|
|||
<caption label="&zotero.__addonRef__.export.markdown.label;"></caption>
|
||||
<rows flex="1">
|
||||
<row>
|
||||
<checkbox id="__addonRef__-export-enablefile" checked="true" oncommand="Zotero.Knowledge4Zotero.export.doUpdate(event)" />
|
||||
<checkbox id="__addonRef__-export-enablefile" checked="true" oncommand="Zotero.Knowledge4Zotero.NoteExportWindow.doUpdate(event)" />
|
||||
<label value="&zotero.__addonRef__.export.file.enable.label;" />
|
||||
</row>
|
||||
<row>
|
||||
<checkbox id="__addonRef__-export-enablesingle" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.link.enable.label;" checked="false" oncommand="Zotero.Knowledge4Zotero.export.doUpdate(event)" />
|
||||
<checkbox id="__addonRef__-export-enablesingle" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.link.enable.label;" checked="false" oncommand="Zotero.Knowledge4Zotero.NoteExportWindow.doUpdate(event)" />
|
||||
<label value="&zotero.__addonRef__.export.singlefile.enable.label;" tooltiptext="&zotero.__addonRef__.export.cannotworkwith.label;&zotero.__addonRef__.export.link.enable.label;" />
|
||||
</row>
|
||||
<row>
|
||||
<checkbox id="__addonRef__-export-enableautosync" tooltiptext="&zotero.__addonRef__.export.workwith.label;&zotero.__addonRef__.export.singlefile.enable.label;" checked="false" oncommand="Zotero.Knowledge4Zotero.export.doUpdate(event)" />
|
||||
<checkbox id="__addonRef__-export-enableautosync" tooltiptext="&zotero.__addonRef__.export.workwith.label;&zotero.__addonRef__.export.singlefile.enable.label;" checked="false" oncommand="Zotero.Knowledge4Zotero.NoteExportWindow.doUpdate(event)" />
|
||||
<label value="&zotero.__addonRef__.export.enableautosync.enable.label;" tooltiptext="Only work with &zotero.__addonRef__.export.singlefile.enable.label;" />
|
||||
</row>
|
||||
<row>
|
||||
|
|
|
|||
|
|
@ -22,36 +22,31 @@
|
|||
<key id="key_open_betternotes" class="key-type-betternotes" key="O" modifiers="accel" command="cmd_open_betternotes" />
|
||||
<key id="key_export_betternotes" class="key-type-betternotes" key="E" modifiers="accel" command="cmd_export_betternotes" />
|
||||
<key id="key_sync_betternotes" class="key-type-betternotes" key="S" modifiers="accel,shift" command="cmd_sync_betternotes" />
|
||||
<key id="key_indent_betternotes" class="key-type-betternotes" keycode="VK_TAB" command="cmd_indent_betternotes" />
|
||||
<key id="key_unindent_betternotes" class="key-type-betternotes" keycode="VK_TAB" modifiers="shift" command="cmd_unindent_betternotes" />
|
||||
</keyset>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<command id="cmd_new_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'createWorkspace'});" />
|
||||
<command id="cmd_open_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'selectMainKnowledge'});" />
|
||||
<command id="cmd_open_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'selectMainNote'});" />
|
||||
<command id="cmd_open_betternotesWindow" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openWorkspaceInWindow'});" />
|
||||
<command id="cmd_export_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'export', content: {editorInstance: {_item: false}}});" />
|
||||
<command id="cmd_sync_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'sync'});" />
|
||||
<command id="cmd_sync_manager_betternotes" oncommand="Zotero.Knowledge4Zotero.syncList.openSyncList();" />
|
||||
<command id="cmd_sync_manager_betternotes" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.openSyncList();" />
|
||||
<command id="cmd_editTemplate_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'editTemplate'});" />
|
||||
<command id="cmd_addheading_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'addHeading'});" />
|
||||
<command id="cmd_indent_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'indentHeading'});" />
|
||||
<command id="cmd_unindent_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'unindentHeading'});" />
|
||||
<!-- <command id="cmd_importlink_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'importLink'});" />
|
||||
<command id="cmd_updatelink_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'updateLink'});" /> -->
|
||||
<command id="cmd_autoannotation_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'updateAutoAnnotation'});" />
|
||||
<command id="cmd_convertmd_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'convertMD'});" />
|
||||
<command id="cmd_convertasciidoc_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'convertAsciiDoc'});" />
|
||||
<command id="cmd_treeview_betternotes" oncommand="Zotero.Knowledge4Zotero.views.switchView(1);" />
|
||||
<command id="cmd_mindmap_betternotes" oncommand="Zotero.Knowledge4Zotero.views.switchView(2);" />
|
||||
<command id="cmd_bubblemap_betternotes" oncommand="Zotero.Knowledge4Zotero.views.switchView(3);" />
|
||||
<command id="cmd_treeview_betternotes" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(1);" />
|
||||
<command id="cmd_mindmap_betternotes" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(2);" />
|
||||
<command id="cmd_bubblemap_betternotes" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(3);" />
|
||||
<command id="cmd_guide_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openUserGuide'});" />
|
||||
<command id="cmd_about_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openAbout'});" />
|
||||
</commandset>
|
||||
|
||||
<popup id="zotero-itemmenu">
|
||||
<menuseparator />
|
||||
<menuitem id="zotero-itemmenu-__addonRef__-setMainKnowledge" class="menuitem-iconic popup-type-single-note" label="&zotero.__addonRef__.itemmenu.setMainKnowledge.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setMainKnowledge', content: {params: {itemID: ZoteroPane.getSelectedItems()[0].id}}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
|
||||
<menuitem id="zotero-itemmenu-__addonRef__-setMainNote" class="menuitem-iconic popup-type-single-note" label="&zotero.__addonRef__.itemmenu.setMainNote.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'setMainNote', content: {params: {itemID: ZoteroPane.getSelectedItems()[0].id}}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
|
||||
<menuitem id="zotero-itemmenu-__addonRef__-exportNote" class="menuitem-iconic popup-type-single" label="&zotero.__addonRef__.itemmenu.exportNote.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'exportNotes', content: {}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
|
||||
<menuitem id="zotero-itemmenu-__addonRef__-exportNotes" class="menuitem-iconic popup-type-multiple" label="&zotero.__addonRef__.itemmenu.exportNotes.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'exportNotes', content: {}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
|
||||
</popup>
|
||||
|
|
@ -68,22 +63,18 @@
|
|||
|
||||
<menupopup id="menu_EditPopup">
|
||||
<menu id="menu_insertTextTemplate_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.insertTextTemplate;">
|
||||
<menupopup id="menu_insertTextTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Text');" />
|
||||
<menupopup id="menu_insertTextTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Text');" />
|
||||
</menu>
|
||||
<menu id="menu_insertNoteTemplate_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.insertNoteTemplate;">
|
||||
<menupopup id="menu_insertNoteTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Note');" />
|
||||
<menupopup id="menu_insertNoteTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Note');" />
|
||||
</menu>
|
||||
<menu id="menu_insertItemTemplate_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.insertItemTemplate;">
|
||||
<menupopup id="menu_insertItemTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Item');" />
|
||||
<menupopup id="menu_insertItemTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Item');" />
|
||||
</menu>
|
||||
<menuitem id="menu_editTemplate_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.editTemplate;" command="cmd_editTemplate_betternotes" />
|
||||
<menu id="menu_citeSetting_betternotes" class="menu-type-betternotes menu-betternotes" label="&zotero.__addonRef__.workspace.menu.citeSetting;">
|
||||
<menupopup id="menu_citeSettingPopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateCitationStyleMenu();" />
|
||||
<menupopup id="menu_citeSettingPopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateCitationStyleMenu();" />
|
||||
</menu>
|
||||
<menuseparator class="menu-type-betternotes menu-betternotes" />
|
||||
<menuitem id="menu_addheading_betternotes" class="menu-type-betternotes menu-betternotes" label="&zotero.__addonRef__.workspace.menu.addheading;" command="cmd_addheading_betternotes" />
|
||||
<menuitem id="menu_indent_betternotes" class="menu-type-betternotes menu-betternotes" label="&zotero.__addonRef__.workspace.menu.indent;" command="cmd_indent_betternotes" key="key_indent_betternotes" />
|
||||
<menuitem id="menu_unindent_betternotes" class="menu-type-betternotes menu-betternotes" label="&zotero.__addonRef__.workspace.menu.unindent;" command="cmd_unindent_betternotes" key="key_unindent_betternotes" />
|
||||
<!-- <menuitem id="menu_importlink_betternotes" class="menu-type-betternotes" label="&zotero.__addonRef__.workspace.menu.importLink;" command="cmd_importlink_betternotes" />
|
||||
<menuitem id="menu_updatelink_betternotes" class="menu-type-betternotes" label="&zotero.__addonRef__.workspace.menu.updateLink;" command="cmd_updatelink_betternotes" /> -->
|
||||
<menuseparator class="menu-betternotes" />
|
||||
|
|
@ -107,7 +98,7 @@
|
|||
<menupopup id="menu_HelpPopup">
|
||||
<menuseparator class="menu-betternotes" />
|
||||
<menu id="menu_ocrsetting_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.OCRSetting;">
|
||||
<menupopup id="menu_ocrsettingpopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateOCRStyleMenu();">
|
||||
<menupopup id="menu_ocrsettingpopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateOCRStyleMenu();">
|
||||
<menuitem id="menu_ocr_bing_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.OCRBing;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setOCREngine', content: {params: {engine: 'bing'}}})" type="checkbox" />
|
||||
<menuitem id="menu_ocr_mathpix_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.OCRMathpix;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setOCREngine', content: {params: {engine: 'mathpix'}}})" type="checkbox" />
|
||||
<menuitem id="menu_ocr_xunfei_betternotes" class="menu-betternotes" label="&zotero.__addonRef__.workspace.menu.OCRXunfei;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setOCREngine', content: {params: {engine: 'xunfei'}}})" type="checkbox" />
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
%knowledgeDTD;
|
||||
]>
|
||||
|
||||
<dialog id="betternotes-sync-dialog" windowtype="betternotes-sync" title="&zotero.__addonRef__.sync.title;" orient="vertical" width="300" height="300" buttons="cancel,accept,help" ondialogaccept="Zotero.Knowledge4Zotero.sync.doAccept();" ondialoghelp="Zotero.Knowledge4Zotero.sync.doExport();" onload="Zotero.Knowledge4Zotero.sync.doLoad(window);" onunload="Zotero.Knowledge4Zotero.sync.doUnload();" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" style="padding:2em" persist="screenX screenY width height" buttonlabelhelp="&zotero.__addonRef__.sync.export.label;">
|
||||
<dialog id="betternotes-sync-dialog" windowtype="betternotes-sync" title="&zotero.__addonRef__.sync.title;" orient="vertical" width="300" height="300" buttons="cancel,accept,help" ondialogaccept="Zotero.Knowledge4Zotero.SyncInfoWindow.doAccept();" ondialoghelp="Zotero.Knowledge4Zotero.SyncInfoWindow.doExport();" onload="Zotero.Knowledge4Zotero.SyncInfoWindow.doLoad(window);" onunload="Zotero.Knowledge4Zotero.SyncInfoWindow.doUnload();" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" style="padding:2em" persist="screenX screenY width height" buttonlabelhelp="&zotero.__addonRef__.sync.export.label;">
|
||||
<script src="chrome://zotero/content/include.js" />
|
||||
<vbox flex="1">
|
||||
<label value="&zotero.__addonRef__.sync.path.label;" />
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
<label id="__addonRef__-sync-lastsync" />
|
||||
<hbox>
|
||||
<checkbox id="__addonRef__-sync-enable" label="&zotero.__addonRef__.sync.enable.label;" checked="true" />
|
||||
<button flex="0" label="&zotero.__addonRef__.sync.dosync.label;" oncommand="Zotero.Knowledge4Zotero.sync.doSync(null, true)"></button>
|
||||
<button flex="0" label="&zotero.__addonRef__.sync.synclist.label;" oncommand="Zotero.Knowledge4Zotero.syncList.openSyncList()"></button>
|
||||
<button flex="0" label="&zotero.__addonRef__.sync.dosync.label;" oncommand="Zotero.Knowledge4Zotero.SyncController.doSync(null, true)"></button>
|
||||
<button flex="0" label="&zotero.__addonRef__.sync.synclist.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.openSyncList()"></button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</dialog>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
%knowledgeDTD;
|
||||
]>
|
||||
|
||||
<window id="zotero-knowledge-sync-list" onload="Zotero.Knowledge4Zotero.syncList.doLoad(window);" onresize="Zotero.Knowledge4Zotero.syncList.doUpdate();" orient="vertical" width="600" height="350" title="&zotero.__addonRef__.syncList.title;" persist="screenX screenY width height" windowtype="zotero:knowledgeSyncList" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<window id="zotero-knowledge-sync-list" onload="Zotero.Knowledge4Zotero.SyncListWindow.doLoad(window);" onresize="Zotero.Knowledge4Zotero.SyncListWindow.doUpdate();" orient="vertical" width="600" height="350" title="&zotero.__addonRef__.syncList.title;" persist="screenX screenY width height" windowtype="zotero:knowledgeSyncList" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<script src="chrome://zotero/content/include.js" />
|
||||
|
||||
<keyset>
|
||||
|
|
@ -39,11 +39,11 @@
|
|||
</listcols>
|
||||
</listbox>
|
||||
<hbox flex="0">
|
||||
<button id="doupdate" label="&zotero.__addonRef__.syncList.doupdate.label;" oncommand="Zotero.Knowledge4Zotero.syncList.doUpdate();"></button>
|
||||
<button id="changesyncperiod" label="&zotero.__addonRef__.syncList.changesyncperiod.label;" oncommand="Zotero.Knowledge4Zotero.syncList.changeSyncPeriod();"></button>
|
||||
<button id="dosync" label="&zotero.__addonRef__.syncList.dosync.label;" oncommand="Zotero.Knowledge4Zotero.syncList.doSync();"></button>
|
||||
<button id="changesync" label="&zotero.__addonRef__.syncList.changesync.label;" oncommand="Zotero.Knowledge4Zotero.syncList.changeSync();"></button>
|
||||
<button id="removesync" label="&zotero.__addonRef__.syncList.removesync.label;" oncommand="Zotero.Knowledge4Zotero.syncList.removeSync();"></button>
|
||||
<button id="doupdate" label="&zotero.__addonRef__.syncList.doupdate.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.doUpdate();"></button>
|
||||
<button id="changesyncperiod" label="&zotero.__addonRef__.syncList.changesyncperiod.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.changeSyncPeriod();"></button>
|
||||
<button id="dosync" label="&zotero.__addonRef__.syncList.dosync.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.doSync();"></button>
|
||||
<button id="changesync" label="&zotero.__addonRef__.syncList.changesync.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.changeSync();"></button>
|
||||
<button id="removesync" label="&zotero.__addonRef__.syncList.removesync.label;" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.removeSync();"></button>
|
||||
<checkbox id="related" label="&zotero.__addonRef__.syncList.related.label;"></checkbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
%knowledgeDTD;
|
||||
]>
|
||||
|
||||
<window id="zotero-knowledge-workspace" orient="vertical" width="1000" height="350" title="&zotero.__addonRef__.workspace.title;" persist="screenX screenY width height sizemode" windowtype="zotero:knowledgeWorkspace" onload="Zotero.Knowledge4Zotero.knowledge._workspacePromise.resolve()" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<window id="zotero-knowledge-workspace" orient="vertical" width="1000" height="350" title="&zotero.__addonRef__.workspace.title;" persist="screenX screenY width height sizemode" windowtype="zotero:knowledgeWorkspace" onload="Zotero.Knowledge4Zotero.WorkspaceWindow._workspacePromise.resolve()" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<script src="chrome://zotero/content/include.js" />
|
||||
|
||||
|
|
@ -34,25 +34,22 @@
|
|||
<key id="key_unindent" keycode="VK_TAB" modifiers="shift" command="cmd_unindent_betternotes" />
|
||||
</keyset>
|
||||
<command id="cmd_new" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'createWorkspace'});" />
|
||||
<command id="cmd_open" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'selectMainKnowledge'});" />
|
||||
<command id="cmd_open" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'selectMainNote'});" />
|
||||
<command id="cmd_openWindow" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openWorkspaceInWindow'});" />
|
||||
<command id="cmd_export" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'export', content: {editorInstance: {_item: false}}});" />
|
||||
<command id="cmd_sync_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'sync'});" />
|
||||
<command id="cmd_sync_manager_betternotes" oncommand="Zotero.Knowledge4Zotero.syncList.openSyncList();" />
|
||||
<command id="cmd_sync_manager_betternotes" oncommand="Zotero.Knowledge4Zotero.SyncListWindow.openSyncList();" />
|
||||
<command id="cmd_close" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'closeWorkspace'});" />
|
||||
<!-- <command id="cmd_insertNotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'insertNotes'});" /> -->
|
||||
<command id="cmd_editTemplate" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'editTemplate'});" />
|
||||
<command id="cmd_addheading" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'addHeading'});" />
|
||||
<command id="cmd_indent_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'indentHeading'});" />
|
||||
<command id="cmd_unindent_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'unindentHeading'});" />
|
||||
<!-- <command id="cmd_importlink_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'importLink'});" />
|
||||
<command id="cmd_updatelink_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'updateLink'});" /> -->
|
||||
<command id="cmd_autoannotation_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'updateAutoAnnotation', content: {event: event}});" />
|
||||
<command id="cmd_convertmd_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'convertMD'});" />
|
||||
<command id="cmd_convertasciidoc_betternotes" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'convertAsciiDoc'});" />
|
||||
<command id="cmd_treeview" oncommand="Zotero.Knowledge4Zotero.views.switchView(1);" />
|
||||
<command id="cmd_mindmap" oncommand="Zotero.Knowledge4Zotero.views.switchView(2);" />
|
||||
<command id="cmd_bubblemap" oncommand="Zotero.Knowledge4Zotero.views.switchView(3);" />
|
||||
<command id="cmd_treeview" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(1);" />
|
||||
<command id="cmd_mindmap" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(2);" />
|
||||
<command id="cmd_bubblemap" oncommand="Zotero.Knowledge4Zotero.WorkspaceOutline.switchView(3);" />
|
||||
<command id="cmd_guide" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openUserGuide'});" />
|
||||
<command id="cmd_about" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent({type: 'openAbout'});" />
|
||||
|
||||
|
|
@ -73,22 +70,18 @@
|
|||
<menupopup id="menu_EditPopup">
|
||||
<!-- <menuitem id="menu_insertNotes" label="&zotero.__addonRef__.workspace.menu.insertNotes;" key="key_insertNotes" accesskey="I" command="cmd_insertNotes" /> -->
|
||||
<menu id="menu_insertTextTemplate" label="&zotero.__addonRef__.workspace.menu.insertTextTemplate;">
|
||||
<menupopup id="menu_insertTextTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Text');" />
|
||||
<menupopup id="menu_insertTextTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Text');" />
|
||||
</menu>
|
||||
<menu id="menu_insertNoteTemplate" label="&zotero.__addonRef__.workspace.menu.insertNoteTemplate;">
|
||||
<menupopup id="menu_insertNoteTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Note');" />
|
||||
<menupopup id="menu_insertNoteTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Note');" />
|
||||
</menu>
|
||||
<menu id="menu_insertItemTemplate" label="&zotero.__addonRef__.workspace.menu.insertItemTemplate;">
|
||||
<menupopup id="menu_insertItemTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateTemplateMenu('Item');" />
|
||||
<menupopup id="menu_insertItemTemplatePopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Item');" />
|
||||
</menu>
|
||||
<menuitem id="menu_editTemplate" label="&zotero.__addonRef__.workspace.menu.editTemplate;" command="cmd_editTemplate" />
|
||||
<menu id="menu_citeSetting_betternotes" class="menu-type-betternotes" label="&zotero.__addonRef__.workspace.menu.citeSetting;">
|
||||
<menupopup id="menu_citeSettingPopup" onpopupshowing="Zotero.Knowledge4Zotero.views.updateCitationStyleMenu();" />
|
||||
<menupopup id="menu_citeSettingPopup" onpopupshowing="Zotero.Knowledge4Zotero.ZoteroViews.updateCitationStyleMenu();" />
|
||||
</menu>
|
||||
<menuseparator />
|
||||
<menuitem id="menu_addheading" label="&zotero.__addonRef__.workspace.menu.addheading;" command="cmd_addheading" />
|
||||
<menuitem id="menu_indent" label="&zotero.__addonRef__.workspace.menu.indent;" command="cmd_indent_betternotes" key="key_indent" />
|
||||
<menuitem id="menu_unindent" label="&zotero.__addonRef__.workspace.menu.unindent;" command="cmd_unindent_betternotes" key="key_unindent" />
|
||||
<!-- <menuitem id="menu_importlink_betternotes" class="menu-type-betternotes" label="&zotero.__addonRef__.workspace.menu.importLink;" command="cmd_importlink_betternotes" />
|
||||
<menuitem id="menu_updatelink_betternotes" class="menu-type-betternotes" label="&zotero.__addonRef__.workspace.menu.updateLink;" command="cmd_updatelink_betternotes" /> -->
|
||||
<menuseparator />
|
||||
|
|
@ -99,7 +92,7 @@
|
|||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="view-menu" label="&viewMenu.label;" accesskey="&viewMenu.accesskey;" onpopupshowing="Zotero.Knowledge4Zotero.views.updateViewMenu();">
|
||||
<menu id="view-menu" label="&viewMenu.label;" accesskey="&viewMenu.accesskey;" onpopupshowing="Zotero.Knowledge4Zotero.WorkspaceMenu.updateViewMenu();">
|
||||
<menupopup id="menu_ViewPopup">
|
||||
<menuitem id="menu_openWindow" label="&zotero.__addonRef__.workspace.menu.openWindow;" command="cmd_openWindow" />
|
||||
<menuseparator />
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<!ENTITY zotero.__addonRef__.workspace.menu.guide "Better Notes User Guide">
|
||||
<!ENTITY zotero.__addonRef__.workspace.menu.about "About Better Notes">
|
||||
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.setMainKnowledge.label "Set Main Note">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.setMainNote.label "Set Main Note">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.exportNote.label "Export Note and SubNotes">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.exportNotes.label "Export Notes and SubNotes to Markdown">
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<!ENTITY zotero.__addonRef__.workspace.menu.guide "Better Notes用户指引">
|
||||
<!ENTITY zotero.__addonRef__.workspace.menu.about "关于Better Notes">
|
||||
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.setMainKnowledge.label "设置为主笔记">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.setMainNote.label "设置为主笔记">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.exportNote.label "导出笔记及条目子笔记">
|
||||
<!ENTITY zotero.__addonRef__.itemmenu.exportNotes.label "导出笔记及条目子笔记为Markdown">
|
||||
|
||||
|
|
|
|||
78
src/addon.ts
78
src/addon.ts
|
|
@ -1,34 +1,68 @@
|
|||
import AddonEvents from "./events";
|
||||
import AddonViews from "./views";
|
||||
import AddonEvents from "./zotero/events";
|
||||
import ZoteroViews from "./zotero/views";
|
||||
import ReaderViews from "./reader/annotationButton";
|
||||
import WorkspaceOutline from "./workspace/workspaceOutline";
|
||||
import EditorViews from "./editor/editorUI";
|
||||
import AddonWizard from "./wizard";
|
||||
import AddonExport from "./export";
|
||||
import Knowledge from "./knowledge";
|
||||
import AddonTemplate from "./template";
|
||||
import AddonSync from "./sync";
|
||||
import AddonSyncList from "./syncList";
|
||||
import AddonParse from "./parse";
|
||||
import NoteExportWindow from "./editor/noteExportWindow";
|
||||
import { TemplateController, TemplateAPI } from "./template/templateController";
|
||||
import SyncInfoWindow from "./sync/syncInfoWindow";
|
||||
import SyncListWindow from "./sync/syncListWindow";
|
||||
import NoteParse from "./editor/noteParse";
|
||||
import WorkspaceWindow from "./workspace/workspaceWindow";
|
||||
import WorkspaceMenu from "./workspace/workspaceMenu";
|
||||
import NoteUtils from "./editor/noteUtils";
|
||||
import NoteExport from "./editor/noteExportController";
|
||||
import SyncController from "./sync/syncController";
|
||||
import TemplateWindow from "./template/templateWindow";
|
||||
|
||||
class Knowledge4Zotero {
|
||||
public events: AddonEvents;
|
||||
public views: AddonViews;
|
||||
// Zotero UI
|
||||
public ZoteroViews: ZoteroViews;
|
||||
// Reader UI
|
||||
public ReaderViews: ReaderViews;
|
||||
// Workspace UI
|
||||
public WorkspaceOutline: WorkspaceOutline;
|
||||
public WorkspaceWindow: WorkspaceWindow;
|
||||
public WorkspaceMenu: WorkspaceMenu;
|
||||
// First-run wizard
|
||||
public wizard: AddonWizard;
|
||||
public export: AddonExport;
|
||||
public parse: AddonParse;
|
||||
public sync: AddonSync;
|
||||
public syncList: AddonSyncList;
|
||||
public template: AddonTemplate;
|
||||
public knowledge: Knowledge;
|
||||
// Sync tools
|
||||
public SyncInfoWindow: SyncInfoWindow;
|
||||
public SyncListWindow: SyncListWindow;
|
||||
public SyncController: SyncController;
|
||||
// Template
|
||||
public TemplateWindow: TemplateWindow;
|
||||
public TemplateController: TemplateController;
|
||||
// Just for template API consistency
|
||||
public knowledge: TemplateAPI;
|
||||
// Note tools
|
||||
public NoteUtils: NoteUtils;
|
||||
public NoteExport: NoteExport;
|
||||
public NoteExportWindow: NoteExportWindow;
|
||||
public NoteParse: NoteParse;
|
||||
public EditorViews: EditorViews;
|
||||
|
||||
constructor() {
|
||||
this.events = new AddonEvents(this);
|
||||
this.views = new AddonViews(this);
|
||||
this.ZoteroViews = new ZoteroViews(this);
|
||||
this.ReaderViews = new ReaderViews(this);
|
||||
this.WorkspaceOutline = new WorkspaceOutline(this);
|
||||
this.WorkspaceWindow = new WorkspaceWindow(this);
|
||||
this.WorkspaceMenu = new WorkspaceMenu(this);
|
||||
this.EditorViews = new EditorViews(this);
|
||||
this.wizard = new AddonWizard(this);
|
||||
this.export = new AddonExport(this);
|
||||
this.parse = new AddonParse(this);
|
||||
this.sync = new AddonSync(this);
|
||||
this.syncList = new AddonSyncList(this);
|
||||
this.template = new AddonTemplate(this);
|
||||
this.knowledge = new Knowledge(this);
|
||||
this.SyncInfoWindow = new SyncInfoWindow(this);
|
||||
this.SyncListWindow = new SyncListWindow(this);
|
||||
this.SyncController = new SyncController(this);
|
||||
this.TemplateWindow = new TemplateWindow(this);
|
||||
this.TemplateController = new TemplateController(this);
|
||||
this.NoteUtils = new NoteUtils(this);
|
||||
this.NoteExport = new NoteExport(this);
|
||||
this.NoteExportWindow = new NoteExportWindow(this);
|
||||
this.NoteParse = new NoteParse(this);
|
||||
this.knowledge = new TemplateAPI(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,867 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { CopyHelper, EditorMessage } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class EditorViews extends AddonBase {
|
||||
icons: object;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this.icons = {
|
||||
addToNoteEnd: `<svg t="1651124422933" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3269" width="24" height="24"><path d="M896.00324 352c70.7 0 128-57.3 128-128 0-70.6-57.4-128-128-128-70.7 0-128 57.3-128 128 0 18.8 4.1 36.7 11.3 52.8 2.7 6 1.4 13.1-3.3 17.8l-24.2 24.2c-5.7 5.7-14.9 6.3-21.2 1.2-38.1-30.1-86.3-48-138.6-48-18.8 0-37.1 2.3-54.6 6.7-6.9 1.7-14.1-1.4-17.7-7.5l-6.6-11.4c-3.4-5.8-2.7-13.1 1.6-18.3 18.6-22.6 29.7-51.6 29.3-83.2C543.10324 89 486.30324 32.6 417.00324 32c-70.6-0.6-128.1 56.1-129 126.3-0.9 69.5 56.5 128.6 126 129.6 9.4 0.1 18.5-0.7 27.4-2.5 6.8-1.4 13.6 1.7 17.1 7.7l2.2 3.8c4 7 2.2 15.9-4.2 20.7-42.4 32.3-73 79.4-84 133.6-1.5 7.4-8.1 12.7-15.7 12.7h-94.1c-6.6 0-12.6-4-14.9-10.2-18.1-48-64.3-82.2-118.5-82.8C58.70324 370.3 0.50324 427.6 0.00324 498.1-0.49676 569.2 57.00324 627 128.00324 627c56.7 0 104.8-36.9 121.6-87.9 2.2-6.6 8.3-11.1 15.2-11.1h92c7.6 0 14.2 5.4 15.7 12.9 9.5 46.7 33.5 88 67 119.2 5.4 5 6.6 13.2 2.9 19.6l-21.7 37.6c-3.7 6.3-11.1 9.4-18.2 7.4-11.1-3.1-22.7-4.7-34.8-4.7-69.7 0.1-127 56.8-127.8 126.6-0.8 71.7 57.4 130 129.1 129.4 69.5-0.6 126.3-57.3 126.9-126.8 0.3-28-8.5-53.9-23.5-75.1-3.6-5.1-3.9-11.8-0.8-17.2l24.9-43.1c3.9-6.7 12-9.7 19.3-7 23.7 8.6 49.3 13.2 76 13.2 34.9 0 67.9-8 97.3-22.2 7.6-3.7 16.7-0.9 20.9 6.4l37 64c-26.3 23.5-43 57.7-43 95.8 0 70.9 58 128.5 128.9 128 69.7-0.5 126.2-56.7 127.1-126.3 0.9-70.1-57-129.3-127.1-129.7-6.2 0-12.3 0.4-18.3 1.2-6.5 0.9-12.8-2.2-16.1-7.8l-39.2-67.9c-3.4-5.9-2.7-13.3 1.7-18.4 34.2-39.3 54.9-90.7 54.9-147 0-38.9-9.9-75.5-27.4-107.4-3.4-6.2-2.2-13.9 2.8-18.9l28.4-28.4c4.9-4.9 12.4-6 18.7-2.9 17.4 8.6 36.9 13.5 57.6 13.5z m0-192c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zM128.00324 563c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z m240 349c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z m464-112c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zM416.00324 224c-35.3 0-64-28.7-64-64s28.7-64 64-64 64 28.7 64 64-28.7 64-64 64z m289.1 385.1C674.90324 639.4 634.70324 656 592.00324 656s-82.9-16.6-113.1-46.9C448.60324 578.9 432.00324 538.7 432.00324 496s16.6-82.9 46.9-113.1C509.10324 352.6 549.30324 336 592.00324 336s82.9 16.6 113.1 46.9C735.40324 413.1 752.00324 453.3 752.00324 496s-16.6 82.9-46.9 113.1z" p-id="3270" fill="currentColor"></path></svg>`,
|
||||
addCitation: `<svg t="1652702140873" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2080" width="24" height="24"><path d="M479.615429 372.021945l0 155.216107c-8.769734 78.782298-47.084365 113.813139-114.89068 124.738979L364.724749 599.455841c21.849634-2.15406 36.108383-18.566868 42.673915-49.239448l0-22.978341-72.204485 0L335.194178 372.021945 479.615429 372.021945zM688.806845 372.021945l0 155.216107c-8.769734 76.628238-47.084365 111.608937-114.891703 124.738979L573.915142 599.455841c8.720615-2.15406 17.49035-8.719592 26.261107-19.695574 8.720615-10.92584 14.207583-20.773116 16.412808-29.543873l0-22.978341-71.120804 0L545.468253 372.021945 688.806845 372.021945z" p-id="2081" fill="currentColor"></path></svg>`,
|
||||
notMainKnowledge: `<svg t="1651124314636" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1689" width="24" height="24"><path d="M877.44 383.786667L624.426667 117.333333C594.986667 86.186667 554.88 69.12 512 69.12s-82.986667 17.066667-112.426667 48.213333L146.56 383.786667a148.266667 148.266667 0 0 0-40.746667 102.4v302.08c0 85.76 69.76 155.52 155.52 155.52h501.546667c85.76 0 155.52-69.76 155.52-155.52V485.973333c0-38.186667-14.506667-74.453333-40.96-102.186666z m-44.373333 404.266666c0 38.826667-31.573333 70.186667-70.186667 70.186667H261.333333c-38.826667 0-70.186667-31.573333-70.186666-70.186667V485.973333c0-16.213333 6.186667-31.786667 17.28-43.52L461.44 176c13.226667-13.866667 31.146667-21.546667 50.56-21.546667s37.333333 7.68 50.56 21.76l253.013333 266.453334c11.306667 11.733333 17.28 27.306667 17.28 43.52v301.866666z" p-id="1690" fill="currentColor"></path><path d="M608 687.786667h-192c-23.466667 0-42.666667 19.2-42.666667 42.666666s19.2 42.666667 42.666667 42.666667h192c23.466667 0 42.666667-19.2 42.666667-42.666667s-19.2-42.666667-42.666667-42.666666z" p-id="1691" fill="currentColor"></path></svg>`,
|
||||
isMainKnowledge: `<svg t="1651124352868" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1850" width="24" height="24"><path d="M877.44 388.053333L624.426667 121.813333C594.986667 90.666667 554.88 73.386667 512 73.386667s-82.986667 17.066667-112.426667 48.213333L146.56 388.053333a148.266667 148.266667 0 0 0-40.746667 102.4v302.08c0 85.76 69.76 155.52 155.52 155.52h501.546667c85.76 0 155.52-69.76 155.52-155.52V490.453333c0-38.4-14.506667-74.666667-40.96-102.4zM608 777.386667h-192c-23.466667 0-42.666667-19.2-42.666667-42.666667s19.2-42.666667 42.666667-42.666667h192c23.466667 0 42.666667 19.2 42.666667 42.666667s-19.2 42.666667-42.666667 42.666667z" p-id="1851" fill="currentColor"></path></svg>`,
|
||||
openAttachment: `<svg t="1651595553273" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7641" width="24" height="24"><path d="M950.857143 537.892571a293.924571 293.924571 0 0 0-73.142857-59.904V292.571429l-146.285715-146.285715H146.285714v731.428572h331.702857c15.945143 27.538286 36.205714 52.224 59.904 73.142857H146.285714a73.142857 73.142857 0 0 1-73.142857-73.142857V146.285714a73.142857 73.142857 0 0 1 73.142857-73.142857h621.714286l182.857143 182.857143v281.892571z m-93.549714 266.166858l82.505142 82.541714a37.668571 37.668571 0 0 1-53.211428 53.211428l-82.541714-82.505142a188.233143 188.233143 0 1 1 53.248-53.248z m-47.213715-101.449143a109.714286 109.714286 0 1 0-219.428571 0 109.714286 109.714286 0 0 0 219.428571 0zM202.605714 286.354286h49.371429v24.137143h0.731428c6.326857-10.24 14.372571-17.664 24.137143-22.308572s20.48-6.948571 32.182857-6.948571c14.884571 0 27.684571 2.816 38.4 8.411428 10.715429 5.595429 19.638857 13.056 26.697143 22.308572 7.058286 9.252571 12.324571 20.041143 15.725715 32.365714 3.401143 12.324571 5.12 25.161143 5.12 38.582857 0 12.690286-1.718857 24.868571-5.12 36.571429-3.401143 11.702857-8.594286 22.052571-15.542858 31.085714s-15.616 16.201143-25.965714 21.577143c-10.349714 5.376-22.491429 8.045714-36.388571 8.045714-11.702857 0-22.491429-2.377143-32.365715-7.131428a61.257143 61.257143 0 0 1-24.32-21.028572h-0.731428v89.6H202.605714V286.354286z m358.4 164.937143h-0.731428c-6.107429 10.24-14.08 17.627429-23.954286 22.125714s-21.028571 6.765714-33.462857 6.765714a80.822857 80.822857 0 0 1-37.302857-8.228571 74.898286 74.898286 0 0 1-26.514286-22.308572 101.229714 101.229714 0 0 1-15.725714-32.365714 135.862857 135.862857 0 0 1-5.302857-38.034286c0-12.690286 1.755429-24.941714 5.302857-36.754285 3.547429-11.812571 8.777143-22.235429 15.725714-31.268572s15.652571-16.274286 26.148571-21.76c10.496-5.485714 22.674286-8.228571 36.571429-8.228571 11.227429 0 21.869714 2.377143 32 7.131428s18.102857 11.776 23.954286 21.028572h0.731428v-95.085715h51.931429V475.428571h-49.371429v-24.137142z m99.84-130.194286h-31.085714v-34.742857h31.085714v-14.628572c0-16.822857 5.229714-30.610286 15.725715-41.325714 10.496-10.715429 26.331429-16.091429 47.542857-16.091429 4.644571 0 9.252571 0.182857 13.897143 0.548572 4.644571 0.365714 9.142857 0.658286 13.531428 0.914286v38.765714c-6.107429-0.731429-12.434286-1.097143-19.017143-1.097143-7.058286 0-12.141714 1.645714-15.177143 4.937143-3.035429 3.291429-4.571429 8.850286-4.571428 16.64v11.337143h35.84v34.742857h-35.84V475.428571h-51.931429V321.097143z m-362.788571 120.32c8.521143 0 15.652571-1.718857 21.394286-5.12 5.741714-3.401143 10.349714-7.862857 13.897142-13.348572 3.547429-5.485714 6.034286-11.885714 7.497143-19.2 1.462857-7.314286 2.194286-14.738286 2.194286-22.308571 0-7.570286-0.804571-14.994286-2.377143-22.308571a59.392 59.392 0 0 0-7.862857-19.565715 43.812571 43.812571 0 0 0-14.08-13.897143 39.314286 39.314286 0 0 0-21.028571-5.302857c-8.521143 0-15.652571 1.755429-21.394286 5.302857a42.678857 42.678857 0 0 0-13.897143 13.714286c-3.547429 5.595429-6.034286 12.068571-7.497143 19.382857-1.462857 7.314286-2.194286 14.884571-2.194286 22.674286 0 7.570286 0.804571 14.994286 2.377143 22.308571 1.572571 7.314286 4.132571 13.714286 7.68 19.2 3.547429 5.485714 8.228571 9.947429 14.08 13.348572 5.851429 3.401143 12.909714 5.12 21.211429 5.12z m262.217143-61.074286c0-7.789714-0.731429-15.286857-2.194286-22.491428a54.966857 54.966857 0 0 0-7.497143-19.017143 42.203429 42.203429 0 0 0-13.714286-13.348572 40.228571 40.228571 0 0 0-21.211428-5.12c-8.521143 0-15.725714 1.718857-21.577143 5.12-5.851429 3.401143-10.532571 7.936-14.08 13.531429a59.794286 59.794286 0 0 0-7.68 19.2 104.228571 104.228571 0 0 0-2.377143 22.491428c0 7.314286 0.841143 14.628571 2.56 21.942858 1.718857 7.314286 4.461714 13.824 8.228572 19.565714 3.766857 5.741714 8.521143 10.349714 14.262857 13.897143 5.741714 3.547429 12.617143 5.302857 20.662857 5.302857 8.521143 0 15.652571-1.718857 21.394286-5.12 5.741714-3.401143 10.313143-7.972571 13.714285-13.714286a61.44 61.44 0 0 0 7.314286-19.565714c1.462857-7.314286 2.194286-14.884571 2.194286-22.674286z" p-id="7642" fill="currentColor"></path></svg>`,
|
||||
switchEditor: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:currentColor;}.cls-2{filter:invert(100%)}</style></defs><rect class="cls-1" width="24" height="24"/><path class="cls-2" d="M9,7.1H2.33L2.14,9.56H2.4c.15-1.77.32-2.14,2-2.14a3.39,3.39,0,0,1,.59,0c.23,0,.23.16.23.41v5.77c0,.37,0,.53-1.15.53H3.61v.34c.45,0,1.56,0,2.06,0s1.64,0,2.09,0v-.34H7.32c-1.15,0-1.15-.16-1.15-.53V7.86c0-.22,0-.37.19-.41a3.9,3.9,0,0,1,.63,0c1.65,0,1.81.37,2,2.14h.27L9,7.1Z"/><path class="cls-2" d="M14.91,14.15h-.27c-.28,1.68-.53,2.48-2.41,2.48H10.78c-.52,0-.54-.08-.54-.44V13.27h1c1.06,0,1.19.35,1.19,1.28h.27v-2.9h-.27c0,.94-.13,1.28-1.19,1.28h-1V10.3c0-.36,0-.44.54-.44h1.41c1.68,0,2,.61,2.14,2.13h.27l-.3-2.46H8.14v.33H8.4c.84,0,.86.12.86.52v5.73c0,.4,0,.52-.86.52H8.14V17h6.31Z"/><path class="cls-2" d="M18.22,10.27l1.5-2.2a1.67,1.67,0,0,1,1.58-.71V7H18.69v.33c.44,0,.68.25.68.5a.37.37,0,0,1-.1.26L18,10,16.61,7.85a.46.46,0,0,1-.07-.16c0-.13.24-.32.7-.33V7c-.37,0-1.18,0-1.59,0s-1,0-1.43,0v.33h.21c.6,0,.81.08,1,.38l2,3-1.79,2.64a1.67,1.67,0,0,1-1.58.73v.34H16.7v-.34c-.5,0-.69-.31-.69-.51s0-.14.11-.26l1.55-2.3,1.73,2.62s.06.09.06.12-.24.32-.72.33v.34c.39,0,1.19,0,1.6,0s1,0,1.42,0v-.34h-.2c-.58,0-.81-.06-1-.4l-2.3-3.49Z"/></svg>`,
|
||||
export: `<svg t="1651322116327" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11894" width="24" height="24"><path d="M849.2 599v217H178.5V599c-0.7-23.7-20.1-42.7-44-42.7s-43.3 19-44 42.7v252.5c0 28.9 23.6 52.5 52.5 52.5h741.7c28.9 0 52.5-23.6 52.5-52.5V599c-0.7-23.7-20.1-42.7-44-42.7s-43.3 19-44 42.7z" fill="currentColor" p-id="11895"></path><path d="M482.7 135.4l-164 164c-17.1 17.1-17.1 45.1 0 62.2s45.1 17.1 62.2 0l85.7-85.7v314.8c0 26 21.3 47.2 47.2 47.2 26 0 47.2-21.3 47.2-47.2V276l85.7 85.7c17.1 17.1 45.1 17.1 62.2 0s17.1-45.1 0-62.2l-164-164c-17.1-17.2-45.1-17.2-62.2-0.1z" fill="currentColor" p-id="11896"></path></svg>`,
|
||||
close: `<svg t="1651331457107" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12754" width="24" height="24"><path d="M557.311759 513.248864l265.280473-263.904314c12.54369-12.480043 12.607338-32.704421 0.127295-45.248112-12.512727-12.576374-32.704421-12.607338-45.248112-0.127295L512.127295 467.904421 249.088241 204.063755c-12.447359-12.480043-32.704421-12.54369-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.280796l262.975407 263.775299-265.151458 263.744335c-12.54369 12.480043-12.607338 32.704421-0.127295 45.248112 6.239161 6.271845 14.463432 9.440452 22.687703 9.440452 8.160624 0 16.319527-3.103239 22.560409-9.311437l265.216826-263.807983 265.440452 266.240344c6.239161 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.311759 513.248864z" fill="currentColor" p-id="12755"></path></svg>`,
|
||||
};
|
||||
}
|
||||
|
||||
public async initEditor(instance: Zotero.EditorInstance) {
|
||||
const noteItem = instance._item;
|
||||
const mainNote = this._Addon.WorkspaceWindow.getWorkspaceNote();
|
||||
|
||||
const isMainNote = noteItem.id === mainNote.id;
|
||||
const isPreviewNote =
|
||||
noteItem.id === this._Addon.WorkspaceWindow.previewItemID;
|
||||
const isPrint = this._Addon.NoteExport._pdfNoteId === noteItem.id;
|
||||
|
||||
const _window = instance._iframeWindow;
|
||||
|
||||
const setMainNoteDropDown: Element = await this.addEditorButton(
|
||||
instance,
|
||||
"knowledge-start",
|
||||
isMainNote
|
||||
? "isMainKnowledge"
|
||||
: isPreviewNote
|
||||
? "openAttachment"
|
||||
: "notMainKnowledge",
|
||||
isMainNote
|
||||
? "Edit the Main Note in Workspace"
|
||||
: isPreviewNote
|
||||
? "Open Note Attachments"
|
||||
: "Open Workspace",
|
||||
isPreviewNote ? "openAttachment" : "openWorkspace",
|
||||
"start"
|
||||
);
|
||||
|
||||
if (setMainNoteDropDown && !isPreviewNote) {
|
||||
setMainNoteDropDown.classList.add("more-dropdown");
|
||||
setMainNoteDropDown.addEventListener("mouseover", async (e) => {
|
||||
if (setMainNoteDropDown.getElementsByClassName("popup").length > 0) {
|
||||
return;
|
||||
}
|
||||
const recentIds = (
|
||||
Zotero.Prefs.get("Knowledge4Zotero.recentMainNoteIds") as string
|
||||
).split(",");
|
||||
// Add current note
|
||||
recentIds.splice(0, 0, String(noteItem.id));
|
||||
// Remove main note and duplicate notes
|
||||
const recentMainNotes = Zotero.Items.get(
|
||||
new Array(
|
||||
...new Set(
|
||||
recentIds.filter(
|
||||
(id) =>
|
||||
Number(id) !==
|
||||
parseInt(
|
||||
Zotero.Prefs.get(
|
||||
"Knowledge4Zotero.mainKnowledgeID"
|
||||
) as string
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
) as Zotero.Item[];
|
||||
const buttons = recentMainNotes.map((item) => {
|
||||
return {
|
||||
id: `knowledge-setmainnote-popup-${item.id}`,
|
||||
rank: 0,
|
||||
text: item.getNoteTitle(),
|
||||
eventType: "setRecentMainNote",
|
||||
};
|
||||
});
|
||||
const popup: Element = await this.addEditorPopup(
|
||||
instance,
|
||||
"knowledge-setmainnote-popup",
|
||||
buttons,
|
||||
setMainNoteDropDown,
|
||||
"left"
|
||||
);
|
||||
const titleNode = _window.document.createElement("div");
|
||||
titleNode.innerHTML = "Set Recent Main Notes";
|
||||
titleNode.title = "Click item to set it main note";
|
||||
titleNode.style.textAlign = "center";
|
||||
popup.childNodes[0].before(
|
||||
titleNode,
|
||||
_window.document.createElement("hr")
|
||||
);
|
||||
setMainNoteDropDown.addEventListener("mouseleave", (e) => {
|
||||
popup.remove();
|
||||
});
|
||||
setMainNoteDropDown.addEventListener("click", (e) => {
|
||||
popup.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
const addLinkDropDown: Element = await this.addEditorButton(
|
||||
instance,
|
||||
"knowledge-addlink",
|
||||
"addToNoteEnd",
|
||||
"Add Link of Current Note to Main Note",
|
||||
"addToNoteEnd",
|
||||
"middle"
|
||||
);
|
||||
if (addLinkDropDown) {
|
||||
addLinkDropDown.classList.add("more-dropdown");
|
||||
// If the editor initialization fails, the addLinkDropDown does not exist
|
||||
if (isMainNote) {
|
||||
// This is a main knowledge, hide all buttons except the export button and add title
|
||||
addLinkDropDown.innerHTML = "";
|
||||
const header = _window.document.createElement("div");
|
||||
header.setAttribute("title", "This is a Main Note");
|
||||
header.innerHTML = "Main Note";
|
||||
header.setAttribute("style", "font-size: medium");
|
||||
addLinkDropDown.append(header);
|
||||
} else {
|
||||
const normalHintText =
|
||||
"Insert at the end of section.\nHold shift to insert before section.";
|
||||
const shiftHintText =
|
||||
"Insert before section.\nRelease shift to insert at the end of section.";
|
||||
addLinkDropDown.addEventListener(
|
||||
"mouseover",
|
||||
async (e: KeyboardEvent) => {
|
||||
if (addLinkDropDown.getElementsByClassName("popup").length > 0) {
|
||||
return;
|
||||
}
|
||||
let isShift = e.shiftKey;
|
||||
const hintWindow = this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Bi-directional Link",
|
||||
isShift ? shiftHintText : normalHintText,
|
||||
"default",
|
||||
// Disable auto close
|
||||
-1
|
||||
);
|
||||
|
||||
const getButtonParams = () => {
|
||||
const buttonParam: any[] = [];
|
||||
for (let node of nodes) {
|
||||
buttonParam.push({
|
||||
id: `knowledge-addlink-popup-${
|
||||
isShift ? node.model.lineIndex - 1 : node.model.endIndex
|
||||
}`,
|
||||
text: node.model.name,
|
||||
rank: node.model.rank,
|
||||
eventType: "addToNote",
|
||||
});
|
||||
}
|
||||
return buttonParam;
|
||||
};
|
||||
|
||||
const nodes = this._Addon.NoteUtils.getNoteTreeAsList(
|
||||
this._Addon.WorkspaceWindow.getWorkspaceNote()
|
||||
);
|
||||
const buttonParam = getButtonParams();
|
||||
const popup: HTMLElement = await this.addEditorPopup(
|
||||
instance,
|
||||
"knowledge-addlink-popup",
|
||||
// [{ id: ''; icon: string; eventType: string }],
|
||||
buttonParam,
|
||||
addLinkDropDown
|
||||
);
|
||||
popup.style.backgroundColor = isShift ? "#f0f9fe" : "";
|
||||
const leaveAction = (e?) => {
|
||||
ob?.disconnect();
|
||||
popup?.remove();
|
||||
hintWindow?.close();
|
||||
addLinkDropDown?.removeEventListener("mouseleave", leaveAction);
|
||||
addLinkDropDown?.removeEventListener("click", leaveAction);
|
||||
_window.document?.removeEventListener("keydown", keyAction);
|
||||
_window.document?.removeEventListener("keyup", keyAction);
|
||||
};
|
||||
addLinkDropDown.addEventListener("mouseleave", leaveAction);
|
||||
addLinkDropDown.addEventListener("click", leaveAction);
|
||||
// Observe the popup remove triggered by button click
|
||||
const ob = new MutationObserver((e) => {
|
||||
console.log(e);
|
||||
if (e[0].removedNodes) {
|
||||
leaveAction();
|
||||
}
|
||||
});
|
||||
ob.observe(addLinkDropDown, { childList: true });
|
||||
const keyAction = (e: KeyboardEvent) => {
|
||||
if (isShift === e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
isShift = e.shiftKey;
|
||||
console.log(hintWindow);
|
||||
popup.style.backgroundColor = isShift ? "#f0f9fe" : "";
|
||||
this._Addon.ZoteroViews.changeProgressWindowDescription(
|
||||
hintWindow,
|
||||
isShift ? shiftHintText : normalHintText
|
||||
);
|
||||
const buttonParam = getButtonParams();
|
||||
for (const i in popup.children) {
|
||||
popup.children[i].id = buttonParam[i].id;
|
||||
}
|
||||
};
|
||||
_window.document.addEventListener("keydown", keyAction);
|
||||
_window.document.addEventListener("keyup", keyAction);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const addCitationButton = await this.addEditorButton(
|
||||
instance,
|
||||
"knowledge-addcitation",
|
||||
"addCitation",
|
||||
"Insert Citations",
|
||||
"addCitation",
|
||||
"middle",
|
||||
"builtin"
|
||||
);
|
||||
|
||||
let topItem = noteItem.parentItem;
|
||||
while (topItem && !topItem.isRegularItem()) {
|
||||
topItem = topItem.parentItem;
|
||||
}
|
||||
if (addCitationButton) {
|
||||
addCitationButton.classList.add("more-dropdown");
|
||||
if (topItem) {
|
||||
addCitationButton.addEventListener("mouseover", async (e) => {
|
||||
if (addCitationButton.getElementsByClassName("popup").length > 0) {
|
||||
return;
|
||||
}
|
||||
const popup: Element = await this.addEditorPopup(
|
||||
instance,
|
||||
"knowledge-addcitation-popup",
|
||||
[
|
||||
{
|
||||
id: `knowledge-addcitation-popup-${topItem.id}`,
|
||||
rank: 0,
|
||||
text: topItem.getField("title"),
|
||||
eventType: "insertCitation",
|
||||
},
|
||||
],
|
||||
addCitationButton
|
||||
);
|
||||
addCitationButton.addEventListener("mouseleave", (e) => {
|
||||
popup.remove();
|
||||
});
|
||||
addCitationButton.addEventListener("click", (e) => {
|
||||
popup.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addCitationButton.addEventListener("click", async (e) => {
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("insertCitation", {
|
||||
params: {
|
||||
noteItem: noteItem,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
await this.addEditorButton(
|
||||
instance,
|
||||
"knowledge-end",
|
||||
isPreviewNote ? "close" : "export",
|
||||
isPreviewNote ? "Close Preview" : "Export with linked notes",
|
||||
isPreviewNote ? "closePreview" : "export",
|
||||
"end"
|
||||
);
|
||||
|
||||
// Title style only for normal window
|
||||
if (!isPrint) {
|
||||
const style = _window.document.createElement("style");
|
||||
style.innerHTML = `
|
||||
.primary-editor h1::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3E%E6%9C%AA%E6%A0%87%E9%A2%98-1%3C%2Ftitle%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M12.29%2C16.8H11.14V12.33H6.07V16.8H4.92V7H6.07v4.3h5.07V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M18.05%2C16.8H16.93V8.41a4%2C4%2C0%2C0%2C1-.9.53%2C6.52%2C6.52%2C0%2C0%2C1-1.14.44l-.32-1a8.2%2C8.2%2C0%2C0%2C0%2C1.67-.67%2C6.31%2C6.31%2C0%2C0%2C0%2C1.39-1h.42Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor h2::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22a%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M14.14%2C16.8v-.48a4.1%2C4.1%2C0%2C0%2C1%2C.14-1.11%2C2.86%2C2.86%2C0%2C0%2C1%2C.45-.91%2C5.49%2C5.49%2C0%2C0%2C1%2C.83-.86c.33-.29.75-.61%2C1.24-1a7.43%2C7.43%2C0%2C0%2C0%2C.9-.73%2C3.9%2C3.9%2C0%2C0%2C0%2C.57-.7%2C2.22%2C2.22%2C0%2C0%2C0%2C.3-.66%2C2.87%2C2.87%2C0%2C0%2C0%2C.11-.77%2C1.89%2C1.89%2C0%2C0%2C0-.47-1.32%2C1.66%2C1.66%2C0%2C0%2C0-1.28-.5A3.17%2C3.17%2C0%2C0%2C0%2C15.7%2C8a3.49%2C3.49%2C0%2C0%2C0-1.08.76l-.68-.65a4.26%2C4.26%2C0%2C0%2C1%2C1.39-1A4%2C4%2C0%2C0%2C1%2C17%2C6.84a2.62%2C2.62%2C0%2C0%2C1%2C2.83%2C2.67%2C3.58%2C3.58%2C0%2C0%2C1-.15%2C1%2C3.09%2C3.09%2C0%2C0%2C1-.41.9%2C5.53%2C5.53%2C0%2C0%2C1-.67.81%2C9%2C9%2C0%2C0%2C1-.95.79c-.46.32-.84.59-1.13.82a4.68%2C4.68%2C0%2C0%2C0-.71.64%2C2%2C2%2C0%2C0%2C0-.38.6%2C2.08%2C2.08%2C0%2C0%2C0-.11.69h4.88v1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22a%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor h3::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16.14l.51-.8a4.75%2C4.75%2C0%2C0%2C0%2C1.1.52%2C4.27%2C4.27%2C0%2C0%2C0%2C1.12.16%2C2.29%2C2.29%2C0%2C0%2C0%2C1.64-.52A1.77%2C1.77%2C0%2C0%2C0%2C19%2C14.17a1.7%2C1.7%2C0%2C0%2C0-.68-1.48%2C3.6%2C3.6%2C0%2C0%2C0-2.06-.48H15.4v-1h.77A3%2C3%2C0%2C0%2C0%2C18%2C10.81a1.65%2C1.65%2C0%2C0%2C0%2C.6-1.41%2C1.47%2C1.47%2C0%2C0%2C0-.47-1.19A1.67%2C1.67%2C0%2C0%2C0%2C17%2C7.79a3.33%2C3.33%2C0%2C0%2C0-2.08.73l-.59-.75a4.4%2C4.4%2C0%2C0%2C1%2C1.28-.71A4.35%2C4.35%2C0%2C0%2C1%2C17%2C6.84a2.84%2C2.84%2C0%2C0%2C1%2C2%2C.65%2C2.21%2C2.21%2C0%2C0%2C1%2C.74%2C1.78%2C2.35%2C2.35%2C0%2C0%2C1-.49%2C1.5%2C2.7%2C2.7%2C0%2C0%2C1-1.46.89v0a2.74%2C2.74%2C0%2C0%2C1%2C1.65.74%2C2.15%2C2.15%2C0%2C0%2C1%2C.66%2C1.65%2C2.64%2C2.64%2C0%2C0%2C1-.9%2C2.12%2C3.44%2C3.44%2C0%2C0%2C1-2.34.78%2C5.3%2C5.3%2C0%2C0%2C1-1.48-.2A5%2C5%2C0%2C0%2C1%2C14%2C16.14Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor h4::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M19.43%2C6.92v6.59h1.05v1.05H19.43V16.9H18.31V14.56H13.66v-1c.43-.49.87-1%2C1.31-1.57s.87-1.13%2C1.27-1.7S17%2C9.14%2C17.36%2C8.57a16.51%2C16.51%2C0%2C0%2C0%2C.86-1.65Zm-4.49%2C6.59h3.37V8.63c-.34.61-.67%2C1.15-1%2C1.63s-.6.91-.87%2C1.3-.56.74-.81%2C1Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor h5::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M14%2C16l.58-.76a3.67%2C3.67%2C0%2C0%2C0%2C1%2C.58A3.44%2C3.44%2C0%2C0%2C0%2C16.8%2C16a2.17%2C2.17%2C0%2C0%2C0%2C1.58-.6A2%2C2%2C0%2C0%2C0%2C19%2C13.88a1.85%2C1.85%2C0%2C0%2C0-.64-1.5%2C2.83%2C2.83%2C0%2C0%2C0-1.86-.54c-.27%2C0-.55%2C0-.86%2C0s-.58%2C0-.81.06L15.17%2C7H19.7V8H16.14l-.2%2C2.88.47%2C0h.43a3.5%2C3.5%2C0%2C0%2C1%2C2.43.79%2C2.74%2C2.74%2C0%2C0%2C1%2C.88%2C2.16%2C3%2C3%2C0%2C0%2C1-.94%2C2.3%2C3.41%2C3.41%2C0%2C0%2C1-2.4.87%2C4.45%2C4.45%2C0%2C0%2C1-1.5-.24A4.81%2C4.81%2C0%2C0%2C1%2C14%2C16Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor h6::before {
|
||||
margin-left: -64px !important;
|
||||
padding-left: 40px !important;
|
||||
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2218px%22%20height%3D%2218px%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2015.56%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23666%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M11.17%2C16.8H10V12.33H5V16.8H3.8V7H5v4.3H10V7h1.15Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M20.18%2C13.7a3.24%2C3.24%2C0%2C0%2C1-.88%2C2.38%2C2.94%2C2.94%2C0%2C0%2C1-2.2.9%2C2.69%2C2.69%2C0%2C0%2C1-2.31-1.17A5.59%2C5.59%2C0%2C0%2C1%2C14%2C12.49a12.18%2C12.18%2C0%2C0%2C1%2C.2-2.14%2C5.16%2C5.16%2C0%2C0%2C1%2C.84-2A3.65%2C3.65%2C0%2C0%2C1%2C16.27%2C7.2%2C3.71%2C3.71%2C0%2C0%2C1%2C18%2C6.84%2C3.14%2C3.14%2C0%2C0%2C1%2C19%2C7a3.59%2C3.59%2C0%2C0%2C1%2C1%2C.5l-.56.77a2.3%2C2.3%2C0%2C0%2C0-1.49-.48A2.3%2C2.3%2C0%2C0%2C0%2C16.79%2C8a3%2C3%2C0%2C0%2C0-.92.85%2C3.79%2C3.79%2C0%2C0%2C0-.56%2C1.25%2C6.56%2C6.56%2C0%2C0%2C0-.19%2C1.65h0a2.61%2C2.61%2C0%2C0%2C1%2C1-.84%2C2.91%2C2.91%2C0%2C0%2C1%2C1.23-.28%2C2.63%2C2.63%2C0%2C0%2C1%2C2%2C.85A3.09%2C3.09%2C0%2C0%2C1%2C20.18%2C13.7ZM19%2C13.78a2.28%2C2.28%2C0%2C0%2C0-.5-1.62%2C1.67%2C1.67%2C0%2C0%2C0-1.29-.54%2C2%2C2%2C0%2C0%2C0-1.5.58%2C2%2C2%2C0%2C0%2C0-.56%2C1.4%2C2.65%2C2.65%2C0%2C0%2C0%2C.55%2C1.74%2C1.85%2C1.85%2C0%2C0%2C0%2C2.78.1A2.38%2C2.38%2C0%2C0%2C0%2C19%2C13.78Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3Cpath%20class%3D%22cls-1%22%20d%3D%22M21%2C5a2.25%2C2.25%2C0%2C0%2C1%2C2.25%2C2.25v9.56A2.25%2C2.25%2C0%2C0%2C1%2C21%2C19H3A2.25%2C2.25%2C0%2C0%2C1%2C.75%2C16.78V7.22A2.25%2C2.25%2C0%2C0%2C1%2C3%2C5H21m0-.75H3a3%2C3%2C0%2C0%2C0-3%2C3v9.56a3%2C3%2C0%2C0%2C0%2C3%2C3H21a3%2C3%2C0%2C0%2C0%2C3-3V7.22a3%2C3%2C0%2C0%2C0-3-3Z%22%20transform%3D%22translate(0%20-4.22)%22%2F%3E%3C%2Fsvg%3E") !important;
|
||||
}
|
||||
.primary-editor > p, .primary-editor h1, .primary-editor h2, .primary-editor h3, .primary-editor h4, .primary-editor h5, .primary-editor h6, .primary-editor pre, .primary-editor blockquote, .primary-editor table, .primary-editor ul, .primary-editor ol, .primary-editor hr{
|
||||
max-width: unset
|
||||
}
|
||||
`;
|
||||
_window.document.body.append(style);
|
||||
}
|
||||
|
||||
if (!_window.document.getElementById("betternotes-script")) {
|
||||
const messageScript = _window.document.createElement("script");
|
||||
messageScript.id = "betternotes-script";
|
||||
messageScript.innerHTML = `
|
||||
window.addEventListener('message', async (e)=>{
|
||||
if(e.data.type === "exportPDF"){
|
||||
console.log("exportPDF");
|
||||
const container = document.getElementById("editor-container");
|
||||
container.style.display = "none";
|
||||
|
||||
const fullPageStyle = document.createElement("style");
|
||||
fullPageStyle.innerHTML =
|
||||
"@page { margin: 0; } @media print{ body { height : auto; -webkit-print-color-adjust: exact; color-adjust: exact; }}";
|
||||
document.body.append(fullPageStyle);
|
||||
|
||||
let t = 0;
|
||||
let imageFlag = false;
|
||||
while(!imageFlag && t < 500){
|
||||
await new Promise(function (resolve) {
|
||||
setTimeout(resolve, 10);
|
||||
});
|
||||
imageFlag = !Array.prototype.find.call(document.querySelectorAll('img'), e=>(!e.getAttribute('src') || e.style.display === 'none'));
|
||||
t += 1;
|
||||
}
|
||||
|
||||
const editNode = document.querySelector(".primary-editor");
|
||||
const printNode = editNode.cloneNode(true);
|
||||
printNode.style.padding = "20px";
|
||||
document.body.append(printNode);
|
||||
|
||||
let printFlag = false;
|
||||
window.onafterprint = (e) => {
|
||||
console.log('Print Dialog Closed..');
|
||||
printFlag = true;
|
||||
document.title = "Printed";
|
||||
};
|
||||
window.onmouseover = (e) => {
|
||||
if (printFlag) {
|
||||
document.title = "Printed";
|
||||
printNode.remove();
|
||||
container.style.removeProperty('display');
|
||||
}
|
||||
};
|
||||
document.title = printNode.firstChild.innerText;
|
||||
console.log(document.title);
|
||||
window.print();
|
||||
}
|
||||
}, false)
|
||||
`;
|
||||
_window.document.head.append(messageScript);
|
||||
}
|
||||
|
||||
const moreDropdown: HTMLElement = Array.prototype.filter.call(
|
||||
_window.document.querySelectorAll(".more-dropdown"),
|
||||
(e) => !e.id.includes("knowledge")
|
||||
)[0];
|
||||
if (!moreDropdown.getAttribute("ob")) {
|
||||
moreDropdown.setAttribute("ob", "true");
|
||||
const dropdownOb = new MutationObserver((e) => {
|
||||
if (
|
||||
e[0].addedNodes.length &&
|
||||
(e[0].addedNodes[0] as HTMLElement).classList.contains("popup")
|
||||
) {
|
||||
const dropdownPopup = moreDropdown.querySelector(".popup");
|
||||
if (dropdownPopup) {
|
||||
const refreshButton = _window.document.createElement("button");
|
||||
refreshButton.classList.add("option");
|
||||
refreshButton.innerText = "Refresh Editor";
|
||||
refreshButton.addEventListener("click", (e) => {
|
||||
instance.init({
|
||||
item: instance._item,
|
||||
viewMode: instance._viewMode,
|
||||
readOnly: instance._readOnly,
|
||||
disableUI: instance._disableUI,
|
||||
onReturn: instance._onReturn,
|
||||
iframeWindow: instance._iframeWindow,
|
||||
popup: instance._popup,
|
||||
state: instance._state,
|
||||
});
|
||||
});
|
||||
const previewButton = _window.document.createElement("button");
|
||||
previewButton.classList.add("option");
|
||||
previewButton.innerText = "Preview in Workspace";
|
||||
previewButton.addEventListener("click", (e) => {
|
||||
this._Addon.WorkspaceWindow.setWorkspaceNote(
|
||||
"preview",
|
||||
instance._item
|
||||
);
|
||||
});
|
||||
const copyLinkButton = _window.document.createElement("button");
|
||||
copyLinkButton.classList.add("option");
|
||||
copyLinkButton.innerText = "Copy Note Link";
|
||||
copyLinkButton.addEventListener("click", (e) => {
|
||||
const link = this._Addon.NoteUtils.getNoteLink(noteItem);
|
||||
const linkTemplate =
|
||||
this._Addon.TemplateController.renderTemplate(
|
||||
"[QuickInsert]",
|
||||
"link, subNoteItem, noteItem",
|
||||
[link, noteItem, noteItem]
|
||||
);
|
||||
new CopyHelper()
|
||||
.addText(link, "text/unicode")
|
||||
.addText(linkTemplate, "text/html")
|
||||
.copy();
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
"Note Link Copied"
|
||||
);
|
||||
});
|
||||
|
||||
const copyLinkAtLineButton =
|
||||
_window.document.createElement("button");
|
||||
copyLinkAtLineButton.classList.add("option");
|
||||
copyLinkAtLineButton.innerText = "Copy Note Link of Current Line";
|
||||
copyLinkAtLineButton.addEventListener("click", (e) => {
|
||||
const link = this._Addon.NoteUtils.getNoteLink(noteItem, {
|
||||
withLine: true,
|
||||
});
|
||||
const linkTemplate =
|
||||
this._Addon.TemplateController.renderTemplate(
|
||||
"[QuickInsert]",
|
||||
"link, subNoteItem, noteItem",
|
||||
[link, noteItem, noteItem]
|
||||
);
|
||||
new CopyHelper()
|
||||
.addText(link, "text/unicode")
|
||||
.addText(linkTemplate, "text/html")
|
||||
.copy();
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Note Link of Line ${
|
||||
this._Addon.NoteUtils.currentLine[noteItem.id] + 1
|
||||
} Copied`
|
||||
);
|
||||
});
|
||||
dropdownPopup.append(
|
||||
previewButton,
|
||||
refreshButton,
|
||||
copyLinkButton,
|
||||
copyLinkAtLineButton
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
dropdownOb.observe(moreDropdown, { childList: true });
|
||||
}
|
||||
}
|
||||
|
||||
public getEditorElement(_document: Document): Element {
|
||||
let editor = _document.querySelector(".primary-editor");
|
||||
return editor;
|
||||
}
|
||||
|
||||
public async addEditorToolBar(editorInstances: Zotero.EditorInstance) {
|
||||
await editorInstances._initPromise;
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const _document = editorInstances._iframeWindow.document;
|
||||
const knowledgeToolBar = _document.createElement("div");
|
||||
knowledgeToolBar.setAttribute("id", "knowledge-tools");
|
||||
knowledgeToolBar.setAttribute("class", "toolbar");
|
||||
const start = _document.createElement("div");
|
||||
start.setAttribute("id", "knowledge-tools-start");
|
||||
start.setAttribute("class", "start");
|
||||
const middle = _document.createElement("div");
|
||||
middle.setAttribute("id", "knowledge-tools-middle");
|
||||
middle.setAttribute("class", "middle");
|
||||
const end = _document.createElement("div");
|
||||
end.setAttribute("id", "knowledge-tools-end");
|
||||
end.setAttribute("class", "end");
|
||||
knowledgeToolBar.append(start, middle, end);
|
||||
_document
|
||||
.getElementsByClassName("editor")[0]
|
||||
.childNodes[0].before(knowledgeToolBar);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
public async addEditorButton(
|
||||
editorInstances: Zotero.EditorInstance,
|
||||
id: string,
|
||||
icon: string,
|
||||
title: string,
|
||||
eventType: string,
|
||||
position: "start" | "middle" | "end",
|
||||
target: "knowledge" | "builtin" = "knowledge"
|
||||
) {
|
||||
// Use Zotero.Notes._editorInstances to find current opened note editor
|
||||
await editorInstances._initPromise;
|
||||
|
||||
const _document = editorInstances._iframeWindow.document;
|
||||
if (_document.getElementById(id)) {
|
||||
return;
|
||||
}
|
||||
let knowledgeToolBar = _document.getElementById("knowledge-tools");
|
||||
if (!knowledgeToolBar) {
|
||||
await this.addEditorToolBar(editorInstances);
|
||||
}
|
||||
let toolbar: HTMLElement;
|
||||
if (target === "knowledge") {
|
||||
toolbar = _document.getElementById(`knowledge-tools-${position}`);
|
||||
} else {
|
||||
toolbar = Array.prototype.find.call(
|
||||
_document.getElementsByClassName(position),
|
||||
(e) => e.getAttribute("id") !== `knowledge-tools-${position}`
|
||||
);
|
||||
}
|
||||
const dropdown = _document.createElement("div");
|
||||
dropdown.setAttribute("class", "dropdown");
|
||||
dropdown.setAttribute("id", id);
|
||||
const button = _document.createElement("button");
|
||||
button.setAttribute("class", "toolbar-button");
|
||||
button.setAttribute("title", title);
|
||||
button.setAttribute("eventType", eventType);
|
||||
button.innerHTML = this.icons[icon];
|
||||
dropdown.append(button);
|
||||
toolbar.append(dropdown);
|
||||
const message = new EditorMessage("", {
|
||||
itemID: editorInstances._item.id,
|
||||
editorInstances: editorInstances,
|
||||
});
|
||||
dropdown.addEventListener("click", (e: XUL.XULEvent) => {
|
||||
message.type = e.target.getAttribute("eventType");
|
||||
message.content.event = e as XUL.XULEvent;
|
||||
message.content.editorInstance = editorInstances;
|
||||
this._Addon.events.onEditorEvent(message);
|
||||
});
|
||||
return dropdown;
|
||||
}
|
||||
|
||||
public async addEditorPopup(
|
||||
editorInstances: Zotero.EditorInstance,
|
||||
id: string,
|
||||
buttons: { id: string; text: string; rank: number; eventType: string }[],
|
||||
parentDropDown: Element,
|
||||
align: "center" | "left" | "right" = "center"
|
||||
) {
|
||||
// Use Zotero.Notes._editorInstances to find current opened note editor
|
||||
await editorInstances._initPromise;
|
||||
|
||||
const _document = editorInstances._iframeWindow.document;
|
||||
let knowledgeToolBar = _document.getElementById("knowledge-tools");
|
||||
if (!knowledgeToolBar) {
|
||||
await this.addEditorToolBar(editorInstances);
|
||||
}
|
||||
const popup = _document.createElement("div");
|
||||
popup.setAttribute("class", "popup");
|
||||
popup.setAttribute("id", id);
|
||||
for (let buttonParam of buttons) {
|
||||
const button = _document.createElement("button");
|
||||
button.setAttribute("class", "option");
|
||||
button.setAttribute(
|
||||
"style",
|
||||
`text-indent: ${(buttonParam.rank - 1) * 5}px;`
|
||||
);
|
||||
button.setAttribute("id", buttonParam.id);
|
||||
button.setAttribute("eventType", buttonParam.eventType);
|
||||
button.innerHTML =
|
||||
buttonParam.text.length > 30
|
||||
? `${buttonParam.text.slice(0, 30)}...`
|
||||
: buttonParam.text;
|
||||
popup.append(button);
|
||||
const message = new EditorMessage("", {
|
||||
itemID: editorInstances._item.id,
|
||||
editorInstances: editorInstances,
|
||||
});
|
||||
button.addEventListener("click", (e: XUL.XULEvent) => {
|
||||
message.type = e.target.getAttribute("eventType");
|
||||
message.content.event = e as XUL.XULEvent;
|
||||
message.content.editorInstance = editorInstances;
|
||||
this._Addon.events.onEditorEvent(message);
|
||||
e.stopPropagation();
|
||||
popup.remove();
|
||||
});
|
||||
}
|
||||
parentDropDown.append(popup);
|
||||
Zotero.debug(popup.offsetWidth);
|
||||
let style: string = "";
|
||||
if (align === "center") {
|
||||
style = `right: -${popup.offsetWidth / 2 - 15}px;`;
|
||||
} else if (align === "left") {
|
||||
style = "left: 0; right: auto;";
|
||||
} else if (align === "right") {
|
||||
style = "right: 0;";
|
||||
}
|
||||
popup.setAttribute("style", style);
|
||||
return popup;
|
||||
}
|
||||
|
||||
public async updateEditorPopupButtons(_window: Window, link: string) {
|
||||
const note: Zotero.Item = link
|
||||
? (await this._Addon.NoteUtils.getNoteFromLink(link)).item
|
||||
: undefined;
|
||||
const mainNote = this._Addon.WorkspaceWindow.getWorkspaceNote();
|
||||
// If the note is invalid, we remove the buttons
|
||||
if (note) {
|
||||
let insertButton = _window.document.getElementById("insert-note-link");
|
||||
if (insertButton) {
|
||||
insertButton.remove();
|
||||
}
|
||||
insertButton = _window.document.createElement("button");
|
||||
insertButton.setAttribute("id", "insert-note-link");
|
||||
insertButton.setAttribute(
|
||||
"title",
|
||||
`Import Linked Note: ${note.getNoteTitle()}`
|
||||
);
|
||||
insertButton.innerHTML = `<svg t="1652008007954" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10521" width="16" height="16"><path d="M574.3 896H159.7c-17.6 0-31.9-14.3-31.9-32V160c0-17.7 14.3-32 31.9-32h382.7v160c0 35.3 28.6 64 63.8 64h159.5v192c0 17.7 14.3 32 31.9 32 17.6 0 31.9-14.3 31.9-32V270.2c0-8.5-3.3-16.6-9.3-22.6L647.4 73.4c-6-6-14.1-9.4-22.6-9.4h-497C92.6 64 64 92.7 64 128v768c0 35.3 28.6 64 63.8 64h446.5c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM638.1 288c-17.6 0-31.9-14.3-31.9-32V128l159.5 160H638.1z" p-id="10522"></path><path d="M418.8 673H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h193.3c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM608.2 481H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32h382.7c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32zM225.5 353h191.4c17.6 0 31.9-14.3 31.9-32s-14.3-32-31.9-32H225.5c-17.6 0-31.9 14.3-31.9 32s14.3 32 31.9 32zM862.7 959.4c-23.6 0-47-8.8-64.8-26.6l-24.4-24.4c-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0l24.4 24.4c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3L749.2 702.6c-11.3-11.4-30.7-10.4-43.2 2.1-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4 12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0c-36.2-36.3-35.2-96.3 2.1-133.8 37.4-37.5 97.2-38.4 133.4-2.1l139.1 139.5c36.2 36.3 35.2 96.3-2.1 133.8-19 19.2-43.9 28.8-68.6 28.8z" p-id="10523"></path><path d="M696.3 883.1c-23.6 0-47-8.8-64.8-26.6l-139-139.6c-17.7-17.8-27.2-41.7-26.6-67.2 0.6-25 10.8-48.6 28.7-66.6 17.9-17.9 41.5-28.2 66.4-28.8 25.5-0.6 49.3 8.9 67 26.6l24.4 24.4c12.5 12.5 12.5 32.8 0 45.3s-32.7 12.5-45.1 0l-24.4-24.4c-5.3-5.3-12.5-8.1-20.4-7.9-8.4 0.2-16.5 3.8-22.8 10-6.2 6.3-9.8 14.4-10 22.8-0.2 7.9 2.6 15.1 7.9 20.4L676.7 811c11.3 11.4 30.7 10.4 43.2-2.1 12.5-12.5 13.4-31.9 2.1-43.3-12.5-12.5-12.5-32.8 0-45.3s32.7-12.5 45.1 0c36.2 36.3 35.3 96.3-2.1 133.8-19.1 19.3-44 29-68.7 29z" p-id="10524"></path></svg>`;
|
||||
insertButton.addEventListener("click", async (e) => {
|
||||
let newLines = [];
|
||||
const convertResult = await this._Addon.NoteUtils.convertNoteLines(
|
||||
note,
|
||||
[],
|
||||
true
|
||||
);
|
||||
const subNoteLines = convertResult.lines;
|
||||
// Prevent note to be too long
|
||||
if (subNoteLines.join("\n").length > 100000) {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
"The linked note is too long. Import ignored."
|
||||
);
|
||||
return;
|
||||
}
|
||||
const templateText =
|
||||
await this._Addon.TemplateController.renderTemplateAsync(
|
||||
"[QuickImport]",
|
||||
"subNoteLines, subNoteItem, noteItem",
|
||||
[subNoteLines, note, mainNote]
|
||||
);
|
||||
newLines.push(templateText);
|
||||
const newLineString = newLines.join("\n");
|
||||
const notifyFlag: ZoteroPromise = Zotero.Promise.defer();
|
||||
const notifierName = "insertLinkWait";
|
||||
this._Addon.events.addNotifyListener(
|
||||
notifierName,
|
||||
(
|
||||
event: string,
|
||||
type: string,
|
||||
ids: Array<number>,
|
||||
extraData: object
|
||||
) => {
|
||||
if (
|
||||
event === "modify" &&
|
||||
type === "item" &&
|
||||
ids.includes(mainNote.id)
|
||||
) {
|
||||
notifyFlag.resolve();
|
||||
this._Addon.events.removeNotifyListener(notifierName);
|
||||
}
|
||||
}
|
||||
);
|
||||
await this._Addon.NoteUtils.modifyLineInNote(
|
||||
mainNote,
|
||||
(oldLine: string) => {
|
||||
Zotero.debug(oldLine);
|
||||
const params = this._Addon.NoteParse.parseParamsFromLink(link);
|
||||
const newLink = !params.ignore
|
||||
? link + (link.includes("?") ? "&ignore=1" : "?ignore=1")
|
||||
: link;
|
||||
const linkIndex =
|
||||
this._Addon.NoteParse.parseLinkIndexInText(oldLine);
|
||||
Zotero.debug(linkIndex);
|
||||
return `${oldLine.slice(0, linkIndex[0])}${newLink}${oldLine.slice(
|
||||
linkIndex[1]
|
||||
)}\n${newLineString}`;
|
||||
},
|
||||
this._Addon.NoteUtils.currentLine[mainNote.id],
|
||||
true
|
||||
);
|
||||
// wait the first modify finish
|
||||
await notifyFlag.promise;
|
||||
let hasAttachemnts = false;
|
||||
for (const _n of [note, ...convertResult.subNotes]) {
|
||||
if ((Zotero.Items.get(_n.getAttachments()) as Zotero.Item[]).length) {
|
||||
hasAttachemnts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasAttachemnts) {
|
||||
await Zotero.DB.executeTransaction(async () => {
|
||||
await Zotero.Notes.copyEmbeddedImages(note, mainNote);
|
||||
for (const subNote of convertResult.subNotes) {
|
||||
await Zotero.Notes.copyEmbeddedImages(subNote, mainNote);
|
||||
}
|
||||
});
|
||||
await this._Addon.NoteUtils.scrollWithRefresh(
|
||||
this._Addon.NoteUtils.currentLine[mainNote.id]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let updateButton = _window.document.getElementById("update-note-link");
|
||||
if (updateButton) {
|
||||
updateButton.remove();
|
||||
}
|
||||
updateButton = _window.document.createElement("button");
|
||||
updateButton.setAttribute("id", "update-note-link");
|
||||
updateButton.setAttribute(
|
||||
"title",
|
||||
`Update Link Text: ${note.getNoteTitle()}`
|
||||
);
|
||||
updateButton.innerHTML = `<svg t="1652685521153" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7063" width="16" height="16"><path d="M271.914667 837.418667C182.314667 756.522667 128 637.653333 128 508.714667 128 304.896 263.338667 129.834667 450.986667 85.333333L469.333333 170.026667c-150.016 35.584-258.304 175.658667-258.304 338.688 0 106.069333 45.866667 203.562667 121.258667 268.373333L426.666667 682.666667v256H170.666667l101.248-101.248zM727.082667 168.917333C831.530667 249.045333 896 377.088 896 517.077333c0 202.922667-135.338667 377.258667-322.986667 421.589334L554.666667 854.357333c150.016-35.456 258.304-174.933333 258.304-337.322666 0-117.12-56.405333-223.786667-146.901334-287.146667L554.666667 341.333333V85.333333h256l-83.584 83.584z" p-id="7064"></path></svg>`;
|
||||
updateButton.addEventListener("click", async (e) => {
|
||||
Zotero.debug("ZBN: Update Link Text");
|
||||
const noteLines = this._Addon.NoteUtils.getLinesInNote(mainNote);
|
||||
let line = noteLines[this._Addon.NoteUtils.currentLine[mainNote.id]];
|
||||
Zotero.debug(line);
|
||||
|
||||
let linkStart = line.search(/<a /g);
|
||||
let linkEnd = line.search(/<\/a>/g) + 4;
|
||||
let beforeLink = line.slice(0, linkStart);
|
||||
let afterLink = line.slice(linkEnd);
|
||||
let linkPart = line.slice(linkStart, linkEnd);
|
||||
let link = this._Addon.NoteParse.parseLinkInText(linkPart);
|
||||
let currentNote: Zotero.Item;
|
||||
if (link) {
|
||||
currentNote = (await this._Addon.NoteUtils.getNoteFromLink(link))
|
||||
.item;
|
||||
}
|
||||
|
||||
while (
|
||||
linkPart &&
|
||||
(!link || !currentNote || currentNote.id !== note.id)
|
||||
) {
|
||||
line = afterLink;
|
||||
beforeLink = beforeLink + linkPart;
|
||||
line = afterLink;
|
||||
|
||||
linkStart = line.search(/<a /g);
|
||||
linkEnd = line.search(/<\/a>/g) + 4;
|
||||
beforeLink = beforeLink + line.slice(0, linkStart);
|
||||
afterLink = line.slice(linkEnd);
|
||||
linkPart = line.slice(linkStart, linkEnd);
|
||||
link = this._Addon.NoteParse.parseLinkInText(linkPart);
|
||||
if (link) {
|
||||
currentNote = (await this._Addon.NoteUtils.getNoteFromLink(link))
|
||||
.item;
|
||||
}
|
||||
}
|
||||
if (!linkPart) {
|
||||
return;
|
||||
}
|
||||
beforeLink = beforeLink + linkPart.slice(0, linkPart.search(/>/) + 1);
|
||||
afterLink = "</a>" + afterLink;
|
||||
const newLine = `${beforeLink}${currentNote.getNoteTitle()}${afterLink}`;
|
||||
Zotero.debug(newLine);
|
||||
noteLines[this._Addon.NoteUtils.currentLine[mainNote.id]] = newLine;
|
||||
|
||||
await this._Addon.NoteUtils.setLinesToNote(mainNote, noteLines);
|
||||
this._Addon.NoteUtils.scrollWithRefresh(
|
||||
this._Addon.NoteUtils.currentLine[mainNote.id]
|
||||
);
|
||||
});
|
||||
|
||||
let previewContainer =
|
||||
_window.document.getElementById("note-link-preview");
|
||||
if (previewContainer) {
|
||||
previewContainer.remove();
|
||||
}
|
||||
previewContainer = _window.document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"div"
|
||||
);
|
||||
previewContainer.id = "note-link-preview";
|
||||
previewContainer.setAttribute(
|
||||
"style",
|
||||
"width: 98%;height: 300px;position: absolute;background: white;bottom: 36px;overflow: hidden;box-shadow: 0 0 5px 5px rgba(0,0,0,0.2);border-radius: 5px;cursor: pointer;opacity: 0.9;"
|
||||
);
|
||||
previewContainer.className = "ProseMirror primary-editor";
|
||||
previewContainer.innerHTML =
|
||||
await this._Addon.NoteParse.parseNoteStyleHTML(note);
|
||||
previewContainer.addEventListener("click", (e) => {
|
||||
this._Addon.WorkspaceWindow.setWorkspaceNote("preview", note);
|
||||
});
|
||||
const linkPopup = _window.document.querySelector(".link-popup");
|
||||
if (linkPopup) {
|
||||
linkPopup.append(insertButton, updateButton, previewContainer);
|
||||
previewContainer
|
||||
.querySelector("div[data-schema-version]")
|
||||
.childNodes.forEach((node) => {
|
||||
if ((node as Element).setAttribute) {
|
||||
(node as Element).setAttribute("style", "margin: 0");
|
||||
} else {
|
||||
node.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const insertLink = _window.document.querySelector("#insert-note-link");
|
||||
if (insertLink) {
|
||||
insertLink.remove();
|
||||
}
|
||||
|
||||
const updateLink = _window.document.querySelector("#update-note-link");
|
||||
if (updateLink) {
|
||||
updateLink.remove();
|
||||
}
|
||||
|
||||
const previewContainer =
|
||||
_window.document.querySelector("#note-link-preview");
|
||||
if (previewContainer) {
|
||||
previewContainer.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async scrollToLine(
|
||||
instance: Zotero.EditorInstance,
|
||||
lineIndex: number
|
||||
) {
|
||||
await instance._initPromise;
|
||||
let editorElement = this.getEditorElement(instance._iframeWindow.document);
|
||||
const eleList = [];
|
||||
const diveTagNames = ["OL", "UL", "LI"];
|
||||
|
||||
const nodes = Array.from(editorElement.children);
|
||||
for (let i in nodes) {
|
||||
const ele = nodes[i];
|
||||
if (diveTagNames.includes(ele.tagName)) {
|
||||
this._Addon.NoteParse.parseListElements(
|
||||
ele as HTMLElement,
|
||||
eleList,
|
||||
diveTagNames
|
||||
);
|
||||
} else {
|
||||
eleList.push(ele);
|
||||
}
|
||||
}
|
||||
console.log(eleList, lineIndex);
|
||||
if (lineIndex >= eleList.length) {
|
||||
lineIndex = eleList.length - 1;
|
||||
} else if (lineIndex < 0) {
|
||||
lineIndex = 0;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const scrollNum = eleList[lineIndex].offsetTop;
|
||||
(editorElement.parentNode as HTMLElement).scrollTo(0, scrollNum);
|
||||
}
|
||||
|
||||
public scrollToPosition(instance: Zotero.EditorInstance, offset: number) {
|
||||
let editorElement = this.getEditorElement(instance._iframeWindow.document);
|
||||
// @ts-ignore
|
||||
(editorElement.parentNode as HTMLElement).scrollTo(0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditorViews;
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { pick } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class NoteExport extends AddonBase {
|
||||
_exportPath: string;
|
||||
_exportFileInfo: Array<{
|
||||
link: string;
|
||||
id: number;
|
||||
note: Zotero.Item;
|
||||
filename: string;
|
||||
}>;
|
||||
_pdfNoteId: number;
|
||||
_pdfPrintPromise: ZoteroPromise;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this._pdfNoteId = -1;
|
||||
this._exportFileInfo = [];
|
||||
}
|
||||
|
||||
async exportNoteToFile(
|
||||
note: Zotero.Item,
|
||||
convertNoteLinks: boolean = true,
|
||||
saveMD: boolean = true,
|
||||
saveNote: boolean = false,
|
||||
doCopy: boolean = false,
|
||||
savePDF: boolean = false
|
||||
) {
|
||||
if (!saveMD && !saveNote && !doCopy && !savePDF) {
|
||||
return;
|
||||
}
|
||||
this._exportFileInfo = [];
|
||||
|
||||
let newNote: Zotero.Item;
|
||||
if (convertNoteLinks || saveNote) {
|
||||
const noteID = await ZoteroPane_Local.newNote();
|
||||
newNote = Zotero.Items.get(noteID) as Zotero.Item;
|
||||
const rootNoteIds = [note.id];
|
||||
|
||||
const convertResult = await this._Addon.NoteUtils.convertNoteLines(
|
||||
note,
|
||||
rootNoteIds,
|
||||
convertNoteLinks
|
||||
);
|
||||
|
||||
await this._Addon.NoteUtils.setLinesToNote(newNote, convertResult.lines);
|
||||
Zotero.debug(convertResult.subNotes);
|
||||
|
||||
await Zotero.DB.executeTransaction(async () => {
|
||||
await Zotero.Notes.copyEmbeddedImages(note, newNote);
|
||||
for (const subNote of convertResult.subNotes) {
|
||||
await Zotero.Notes.copyEmbeddedImages(subNote, newNote);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
newNote = note;
|
||||
}
|
||||
|
||||
if (saveMD) {
|
||||
const filename = await pick(
|
||||
Zotero.getString("fileInterface.export"),
|
||||
"save",
|
||||
[["MarkDown File(*.md)", "*.md"]],
|
||||
`${newNote.getNoteTitle()}.md`
|
||||
);
|
||||
if (filename) {
|
||||
this._exportPath =
|
||||
Zotero.File.pathToFile(filename).parent.path + "/attachments";
|
||||
// Convert to unix format
|
||||
this._exportPath = this._exportPath.replace(/\\/g, "/");
|
||||
await this._export(newNote, filename, false);
|
||||
}
|
||||
}
|
||||
if (doCopy) {
|
||||
if (!convertNoteLinks) {
|
||||
Zotero_File_Interface.exportItemsToClipboard(
|
||||
[newNote],
|
||||
Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT
|
||||
);
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
"Note Copied"
|
||||
);
|
||||
} else {
|
||||
alert(
|
||||
"Select all in the new note window and copy-paste to other applications."
|
||||
);
|
||||
ZoteroPane.openNoteWindow(newNote.id);
|
||||
alert(
|
||||
"Waiting for paste finish...\nImages may not be copied correctly if OK is pressed before paste."
|
||||
);
|
||||
}
|
||||
}
|
||||
if (savePDF) {
|
||||
console.log(newNote);
|
||||
let _w: Window;
|
||||
let t = 0;
|
||||
this._pdfNoteId = newNote.id;
|
||||
this._pdfPrintPromise = Zotero.Promise.defer();
|
||||
ZoteroPane.selectItem(note.id);
|
||||
do {
|
||||
ZoteroPane.openNoteWindow(newNote.id);
|
||||
_w = ZoteroPane.findNoteWindow(newNote.id);
|
||||
console.log(_w);
|
||||
await Zotero.Promise.delay(10);
|
||||
t += 1;
|
||||
} while (!_w && t < 500);
|
||||
ZoteroPane.selectItem(note.id);
|
||||
_w.resizeTo(900, 650);
|
||||
const checkPrint = () => {
|
||||
try {
|
||||
const editor: any = _w.document.querySelector("#zotero-note-editor");
|
||||
const instance: Zotero.EditorInstance = editor.getCurrentInstance();
|
||||
console.log(instance._iframeWindow.document.title);
|
||||
if (instance._iframeWindow.document.title === "Printed") {
|
||||
this._pdfPrintPromise.resolve();
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
setTimeout(checkPrint, 300);
|
||||
};
|
||||
checkPrint();
|
||||
await this._pdfPrintPromise.promise;
|
||||
console.log("print finish detected");
|
||||
const closeFlag = _w.confirm(
|
||||
"Printing finished. Do you want to close the preview window?"
|
||||
);
|
||||
if (closeFlag) {
|
||||
_w.close();
|
||||
}
|
||||
}
|
||||
if (!saveNote) {
|
||||
if (newNote.id !== note.id) {
|
||||
const _w: Window = ZoteroPane.findNoteWindow(newNote.id);
|
||||
if (_w) {
|
||||
_w.close();
|
||||
}
|
||||
await Zotero.Items.erase(newNote.id);
|
||||
}
|
||||
} else {
|
||||
ZoteroPane.openNoteWindow(newNote.id);
|
||||
}
|
||||
}
|
||||
|
||||
async exportNotesToFile(
|
||||
notes: Zotero.Item[],
|
||||
useEmbed: boolean,
|
||||
useSync: boolean = false
|
||||
) {
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
this._exportFileInfo = [];
|
||||
const filepath = await pick(
|
||||
Zotero.getString(useSync ? "sync.sync" : "fileInterface.export") +
|
||||
" MarkDown",
|
||||
"folder"
|
||||
);
|
||||
|
||||
if (!filepath) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._exportPath = Zotero.File.pathToFile(filepath).path + "/attachments";
|
||||
// Convert to unix format
|
||||
this._exportPath = this._exportPath.replace(/\\/g, "/");
|
||||
|
||||
notes = notes.filter((n) => n && n.getNote);
|
||||
|
||||
if (useEmbed) {
|
||||
for (const note of notes) {
|
||||
let newNote: Zotero.Item;
|
||||
if (this._Addon.NoteParse.parseLinkInText(note.getNote())) {
|
||||
const noteID = await ZoteroPane_Local.newNote();
|
||||
newNote = Zotero.Items.get(noteID) as Zotero.Item;
|
||||
const rootNoteIds = [note.id];
|
||||
|
||||
const convertResult = await this._Addon.NoteUtils.convertNoteLines(
|
||||
note,
|
||||
rootNoteIds,
|
||||
true
|
||||
);
|
||||
|
||||
await this._Addon.NoteUtils.setLinesToNote(
|
||||
newNote,
|
||||
convertResult.lines
|
||||
);
|
||||
Zotero.debug(convertResult.subNotes);
|
||||
|
||||
await Zotero.DB.executeTransaction(async () => {
|
||||
await Zotero.Notes.copyEmbeddedImages(note, newNote);
|
||||
for (const subNote of convertResult.subNotes) {
|
||||
await Zotero.Notes.copyEmbeddedImages(subNote, newNote);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
newNote = note;
|
||||
}
|
||||
|
||||
let filename = `${
|
||||
Zotero.File.pathToFile(filepath).path
|
||||
}/${this._getFileName(note)}`;
|
||||
filename = filename.replace(/\\/g, "/");
|
||||
|
||||
await this._export(newNote, filename, newNote.id !== note.id);
|
||||
}
|
||||
} else {
|
||||
// Export every linked note as a markdown file
|
||||
// Find all linked notes that need to be exported
|
||||
let allNoteIds: number[] = notes.map((n) => n.id);
|
||||
for (const note of notes) {
|
||||
const linkMatches = note
|
||||
.getNote()
|
||||
.match(/zotero:\/\/note\/\w+\/\w+\//g);
|
||||
if (!linkMatches) {
|
||||
continue;
|
||||
}
|
||||
const subNoteIds = (
|
||||
await Promise.all(
|
||||
linkMatches.map(async (link) =>
|
||||
this._Addon.NoteUtils.getNoteFromLink(link)
|
||||
)
|
||||
)
|
||||
)
|
||||
.filter((res) => res.item)
|
||||
.map((res) => res.item.id);
|
||||
allNoteIds = allNoteIds.concat(subNoteIds);
|
||||
}
|
||||
allNoteIds = Array.from(new Set(allNoteIds));
|
||||
const allNoteItems: Zotero.Item[] = Zotero.Items.get(
|
||||
allNoteIds
|
||||
) as Zotero.Item[];
|
||||
const noteLinkDict = allNoteItems.map((_note) => {
|
||||
return {
|
||||
link: this._Addon.NoteUtils.getNoteLink(_note),
|
||||
id: _note.id,
|
||||
note: _note,
|
||||
filename: this._getFileName(_note),
|
||||
};
|
||||
});
|
||||
this._exportFileInfo = noteLinkDict;
|
||||
|
||||
for (const noteInfo of noteLinkDict) {
|
||||
let exportPath = `${Zotero.File.pathToFile(filepath).path}/${
|
||||
noteInfo.filename
|
||||
}`;
|
||||
await this._export(noteInfo.note, exportPath, false);
|
||||
if (useSync) {
|
||||
this._Addon.SyncController.updateNoteSyncStatus(
|
||||
noteInfo.note,
|
||||
Zotero.File.pathToFile(filepath).path,
|
||||
noteInfo.filename
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async syncNotesToFile(notes: Zotero.Item[], filepath: string) {
|
||||
this._exportPath = Zotero.File.pathToFile(filepath).path + "/attachments";
|
||||
// Convert to unix format
|
||||
this._exportPath = this._exportPath.replace(/\\/g, "/");
|
||||
|
||||
// Export every linked note as a markdown file
|
||||
// Find all linked notes that need to be exported
|
||||
let allNoteIds: number[] = notes.map((n) => n.id);
|
||||
for (const note of notes) {
|
||||
const linkMatches = note.getNote().match(/zotero:\/\/note\/\w+\/\w+\//g);
|
||||
if (!linkMatches) {
|
||||
continue;
|
||||
}
|
||||
const subNoteIds = (
|
||||
await Promise.all(
|
||||
linkMatches.map(async (link) =>
|
||||
this._Addon.NoteUtils.getNoteFromLink(link)
|
||||
)
|
||||
)
|
||||
)
|
||||
.filter((res) => res.item)
|
||||
.map((res) => res.item.id);
|
||||
allNoteIds = allNoteIds.concat(subNoteIds);
|
||||
}
|
||||
allNoteIds = new Array(...new Set(allNoteIds));
|
||||
// console.log(allNoteIds);
|
||||
const allNoteItems: Zotero.Item[] = Zotero.Items.get(
|
||||
allNoteIds
|
||||
) as Zotero.Item[];
|
||||
const noteLinkDict = allNoteItems.map((_note) => {
|
||||
return {
|
||||
link: this._Addon.NoteUtils.getNoteLink(_note),
|
||||
id: _note.id,
|
||||
note: _note,
|
||||
filename: this._getFileName(_note),
|
||||
};
|
||||
});
|
||||
this._exportFileInfo = noteLinkDict;
|
||||
|
||||
for (const note of notes) {
|
||||
const syncInfo = this._Addon.SyncController.getNoteSyncStatus(note);
|
||||
let exportPath = `${decodeURIComponent(
|
||||
syncInfo.path
|
||||
)}/${decodeURIComponent(syncInfo.filename)}`;
|
||||
await this._export(note, exportPath, false);
|
||||
this._Addon.SyncController.updateNoteSyncStatus(note);
|
||||
}
|
||||
}
|
||||
|
||||
private async _export(
|
||||
note: Zotero.Item,
|
||||
filename: string,
|
||||
deleteAfterExport: boolean
|
||||
) {
|
||||
const hasImage = note.getNote().includes("<img");
|
||||
if (hasImage) {
|
||||
await Zotero.File.createDirectoryIfMissingAsync(
|
||||
OS.Path.join(...this._exportPath.split(/\//))
|
||||
);
|
||||
}
|
||||
|
||||
filename = filename.replace(/\\/g, "/");
|
||||
filename = OS.Path.join(...filename.split(/\//));
|
||||
if (!Zotero.isWin && filename.charAt(0) !== "/") {
|
||||
filename = "/" + filename;
|
||||
}
|
||||
const content: string = await this._Addon.NoteParse.parseNoteToMD(note);
|
||||
console.log(
|
||||
`Exporting MD file: ${filename}, content length: ${content.length}`
|
||||
);
|
||||
await Zotero.File.putContentsAsync(filename, content);
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Note Saved to ${filename}`
|
||||
);
|
||||
if (deleteAfterExport) {
|
||||
const _w: Window = ZoteroPane.findNoteWindow(note.id);
|
||||
if (_w) {
|
||||
_w.close();
|
||||
}
|
||||
await Zotero.Items.erase(note.id);
|
||||
}
|
||||
}
|
||||
|
||||
private _getFileName(noteItem: Zotero.Item) {
|
||||
return (
|
||||
this._Addon.TemplateController.renderTemplate("[ExportMDFileName]", "noteItem", [
|
||||
noteItem,
|
||||
]) as string
|
||||
).replace(/\\/g, "-");
|
||||
}
|
||||
}
|
||||
|
||||
export default NoteExport;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import Knowledge4Zotero from "./addon";
|
||||
import AddonBase from "./module";
|
||||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class AddonExport extends AddonBase {
|
||||
class NoteExportWindow extends AddonBase {
|
||||
private io: {
|
||||
dataIn: any;
|
||||
dataOut: any;
|
||||
|
|
@ -224,4 +224,4 @@ class AddonExport extends AddonBase {
|
|||
}
|
||||
}
|
||||
|
||||
export default AddonExport;
|
||||
export default NoteExportWindow;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import AddonBase from "./module";
|
||||
import AddonBase from "../module";
|
||||
import { HTML2Markdown, Markdown2HTML } from "./convertMD";
|
||||
import TurndownService = require("turndown");
|
||||
const turndownPluginGfm = require("turndown-plugin-gfm");
|
||||
const TreeModel = require("./treemodel");
|
||||
const TreeModel = require("tree-model");
|
||||
const asciidoctor = require("asciidoctor")();
|
||||
const seedrandom = require("seedrandom");
|
||||
|
||||
class AddonParse extends AddonBase {
|
||||
class NoteParse extends AddonBase {
|
||||
private getDOMParser(): DOMParser {
|
||||
if (Zotero.platformMajorVersion > 60) {
|
||||
return new DOMParser();
|
||||
|
|
@ -35,18 +35,8 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
|
||||
public parseNoteTree(note: Zotero.Item): TreeModel.Node<object> {
|
||||
const noteLines = this._Addon.knowledge.getLinesInNote(note);
|
||||
const noteLines = this._Addon.NoteUtils.getLinesInNote(note);
|
||||
let tree = new TreeModel();
|
||||
/*
|
||||
tree-model/index.js: line 40
|
||||
TreeModel.prototype.parse = function (model) {
|
||||
var i, childCount, node;
|
||||
Annotate the line 40 of:
|
||||
|
||||
// if (!(model instanceof Object)) {
|
||||
// throw new TypeError('Model must be of type object.');
|
||||
// }
|
||||
*/
|
||||
let root = tree.parse({
|
||||
id: -1,
|
||||
rank: 0,
|
||||
|
|
@ -74,7 +64,7 @@ class AddonParse extends AddonBase {
|
|||
link = lineElement.slice(lineElement.search(/href="/g) + 6);
|
||||
link = link.slice(0, link.search(/"/g));
|
||||
}
|
||||
name = this._Addon.parse.parseLineText(lineElement);
|
||||
name = this._Addon.NoteParse.parseLineText(lineElement);
|
||||
|
||||
// Find parent node
|
||||
let parentNode = lastNode;
|
||||
|
|
@ -206,7 +196,7 @@ class AddonParse extends AddonBase {
|
|||
const diveTagNames = ["OL", "UL", "LI"];
|
||||
for (const e of doc.children) {
|
||||
if (diveTagNames.includes(e.tagName)) {
|
||||
const innerLines = this.parseListElements(e);
|
||||
const innerLines = this.parseListElements(e as HTMLElement);
|
||||
currentLineIndex += innerLines.length;
|
||||
currentElement = innerLines[innerLines.length - 1];
|
||||
elements = elements.concat(innerLines);
|
||||
|
|
@ -219,9 +209,9 @@ class AddonParse extends AddonBase {
|
|||
return elements;
|
||||
}
|
||||
|
||||
parseHTMLLineElement(doc: HTMLElement, lineIndex: number): Element {
|
||||
parseHTMLLineElement(doc: HTMLElement, lineIndex: number): HTMLElement {
|
||||
let currentLineIndex = 0;
|
||||
let currentElement: Element;
|
||||
let currentElement: HTMLElement;
|
||||
|
||||
const diveTagNames = ["OL", "UL", "LI"];
|
||||
for (const e of doc.children) {
|
||||
|
|
@ -229,7 +219,7 @@ class AddonParse extends AddonBase {
|
|||
break;
|
||||
}
|
||||
if (diveTagNames.includes(e.tagName)) {
|
||||
const innerLines = this.parseListElements(e);
|
||||
const innerLines = this.parseListElements(e as HTMLElement);
|
||||
if (currentLineIndex + innerLines.length > lineIndex) {
|
||||
// The target line is inside the line list
|
||||
for (const _e of innerLines) {
|
||||
|
|
@ -245,7 +235,7 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
} else {
|
||||
currentLineIndex += 1;
|
||||
currentElement = e;
|
||||
currentElement = e as HTMLElement;
|
||||
// console.log(currentLineIndex, e);
|
||||
}
|
||||
}
|
||||
|
|
@ -283,13 +273,13 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
let annotationJSONList = [];
|
||||
for (const annot of annotations) {
|
||||
const annotJson = await this._Addon.parse.parseAnnotation(annot);
|
||||
const annotJson = await this._Addon.NoteParse.parseAnnotation(annot);
|
||||
if (ignoreComment && annotJson.comment) {
|
||||
annotJson.comment = "";
|
||||
}
|
||||
annotationJSONList.push(annotJson);
|
||||
}
|
||||
await this._Addon.knowledge.importImagesToNote(note, annotationJSONList);
|
||||
await this._Addon.NoteUtils.importImagesToNote(note, annotationJSONList);
|
||||
const html =
|
||||
Zotero.EditorInstanceUtilities.serializeAnnotations(
|
||||
annotationJSONList
|
||||
|
|
@ -297,7 +287,7 @@ class AddonParse extends AddonBase {
|
|||
return html;
|
||||
}
|
||||
|
||||
async parseNoteStyleHTML(item: Zotero.Item, lineCount: 5) {
|
||||
async parseNoteStyleHTML(item: Zotero.Item, lineCount: number = 5) {
|
||||
if (!item.isNote()) {
|
||||
throw new Error("Item is not a note");
|
||||
}
|
||||
|
|
@ -396,8 +386,8 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
|
||||
parseListElements(
|
||||
e: Element,
|
||||
eleList: Element[] = undefined,
|
||||
e: HTMLElement,
|
||||
eleList: HTMLElement[] = undefined,
|
||||
tags: string[] = ["OL", "UL", "LI"]
|
||||
) {
|
||||
if (!eleList) {
|
||||
|
|
@ -405,7 +395,7 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
for (let _e of e.children) {
|
||||
if (tags.includes(_e.tagName)) {
|
||||
this.parseListElements(_e, eleList);
|
||||
this.parseListElements(_e as HTMLElement, eleList);
|
||||
} else {
|
||||
eleList.push(e);
|
||||
}
|
||||
|
|
@ -413,8 +403,7 @@ class AddonParse extends AddonBase {
|
|||
return eleList;
|
||||
}
|
||||
|
||||
parseNoteHTML(note: Zotero.Item): Element {
|
||||
note = note || this._Addon.knowledge.getWorkspaceNote();
|
||||
parseNoteHTML(note: Zotero.Item): HTMLElement {
|
||||
if (!note) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -425,7 +414,7 @@ class AddonParse extends AddonBase {
|
|||
let parser = this.getDOMParser();
|
||||
let doc = parser.parseFromString(noteText, "text/html");
|
||||
|
||||
let metadataContainer: Element = doc.querySelector(
|
||||
let metadataContainer: HTMLElement = doc.querySelector(
|
||||
"body > div[data-schema-version]"
|
||||
);
|
||||
return metadataContainer;
|
||||
|
|
@ -573,7 +562,7 @@ class AddonParse extends AddonBase {
|
|||
Zotero.debug(oldFile);
|
||||
let ext = oldFile.split(".").pop();
|
||||
let newAbsPath = OS.Path.join(
|
||||
...`${this._Addon.knowledge._exportPath}/${imgKey}.${ext}`.split(/\//)
|
||||
...`${this._Addon.NoteExport._exportPath}/${imgKey}.${ext}`.split(/\//)
|
||||
);
|
||||
if (!Zotero.isWin && newAbsPath.charAt(0) !== "/") {
|
||||
newAbsPath = "/" + newAbsPath;
|
||||
|
|
@ -697,7 +686,7 @@ class AddonParse extends AddonBase {
|
|||
);
|
||||
},
|
||||
|
||||
replacement: function (content, node: HTMLElement, options) {
|
||||
replacement: (content, node: HTMLElement, options) => {
|
||||
var href = node.getAttribute("href");
|
||||
const cleanAttribute = (attribute) =>
|
||||
attribute ? attribute.replace(/(\n+\s*)+/g, "\n") : "";
|
||||
|
|
@ -705,14 +694,9 @@ class AddonParse extends AddonBase {
|
|||
if (title) title = ' "' + title + '"';
|
||||
if (href.search(/zotero:\/\/note\/\w+\/\w+\//g) !== -1) {
|
||||
// A note link should be converted if it is in the _exportFileDict
|
||||
var _Zotero = Components.classes["@zotero.org/Zotero;1"].getService(
|
||||
Components.interfaces.nsISupports
|
||||
).wrappedJSObject;
|
||||
const noteInfo =
|
||||
_Zotero.Knowledge4Zotero.knowledge._exportFileDict &&
|
||||
_Zotero.Knowledge4Zotero.knowledge._exportFileDict.find((i) =>
|
||||
href.includes(i.link)
|
||||
);
|
||||
const noteInfo = this._Addon.NoteExport._exportFileInfo.find((i) =>
|
||||
href.includes(i.link)
|
||||
);
|
||||
if (noteInfo) {
|
||||
href = `./${noteInfo.filename}`;
|
||||
}
|
||||
|
|
@ -726,4 +710,4 @@ class AddonParse extends AddonBase {
|
|||
}
|
||||
}
|
||||
|
||||
export default AddonParse;
|
||||
export default NoteParse;
|
||||
|
|
@ -0,0 +1,709 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class NoteUtils extends AddonBase {
|
||||
public currentLine: any;
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this.currentLine = [];
|
||||
}
|
||||
|
||||
public getLinesInNote(note: Zotero.Item): string[] {
|
||||
if (!note) {
|
||||
return [];
|
||||
}
|
||||
let noteText: string = note.getNote();
|
||||
return this._Addon.NoteParse.parseHTMLLines(noteText);
|
||||
}
|
||||
|
||||
public async setLinesToNote(note: Zotero.Item, noteLines: string[]) {
|
||||
if (!note) {
|
||||
return [];
|
||||
}
|
||||
let noteText: string = note.getNote();
|
||||
let containerIndex = noteText.search(/data-schema-version="8">/g);
|
||||
if (containerIndex === -1) {
|
||||
note.setNote(
|
||||
`<div data-schema-version="8">${noteLines.join("\n")}</div>`
|
||||
);
|
||||
} else {
|
||||
let noteHead = noteText.substring(0, containerIndex);
|
||||
note.setNote(
|
||||
`${noteHead}data-schema-version="8">${noteLines.join("\n")}</div>`
|
||||
);
|
||||
}
|
||||
|
||||
await note.saveTx();
|
||||
}
|
||||
|
||||
public async addLineToNote(
|
||||
note: Zotero.Item,
|
||||
text: string,
|
||||
lineIndex: number,
|
||||
forceMetadata: boolean = false,
|
||||
position: "before" | "after" = "after"
|
||||
) {
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
let noteLines = this.getLinesInNote(note);
|
||||
if (lineIndex < 0) {
|
||||
lineIndex = this.currentLine[note.id];
|
||||
lineIndex = lineIndex && lineIndex >= 0 ? lineIndex : noteLines.length;
|
||||
} else if (lineIndex >= noteLines.length) {
|
||||
lineIndex = noteLines.length;
|
||||
}
|
||||
Zotero.debug(
|
||||
`insert to ${lineIndex}, it used to be ${noteLines[lineIndex]}`
|
||||
);
|
||||
Zotero.debug(text);
|
||||
|
||||
const editorInstance = this._Addon.WorkspaceWindow.getEditorInstance(note);
|
||||
if (editorInstance && !forceMetadata) {
|
||||
// The note is opened. Add line via note editor
|
||||
console.log("Add note line via note editor");
|
||||
const _document = editorInstance._iframeWindow.document;
|
||||
const currentElement = this._Addon.NoteParse.parseHTMLLineElement(
|
||||
_document.querySelector(".primary-editor"),
|
||||
lineIndex
|
||||
);
|
||||
const frag = _document.createDocumentFragment();
|
||||
const temp = _document.createElement("div");
|
||||
temp.innerHTML = text;
|
||||
while (temp.firstChild) {
|
||||
frag.appendChild(temp.firstChild);
|
||||
}
|
||||
position === "after"
|
||||
? currentElement.after(frag)
|
||||
: currentElement.before(frag);
|
||||
this._Addon.EditorViews.scrollToPosition(
|
||||
editorInstance,
|
||||
currentElement.offsetTop
|
||||
);
|
||||
} else {
|
||||
// The note editor does not exits yet. Fall back to modify the metadata
|
||||
console.log("Add note line via note metadata");
|
||||
|
||||
// insert after/before current line
|
||||
if (position === "after") {
|
||||
lineIndex += 1;
|
||||
}
|
||||
noteLines.splice(lineIndex, 0, text);
|
||||
await this.setLinesToNote(note, noteLines);
|
||||
if (this._Addon.WorkspaceWindow.getWorkspaceNote().id === note.id) {
|
||||
await this.scrollWithRefresh(lineIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _dataURLtoBlob(dataurl: string) {
|
||||
let parts = dataurl.split(",");
|
||||
let matches = parts[0]?.match(/:(.*?);/);
|
||||
if (!matches || !matches[1]) {
|
||||
return;
|
||||
}
|
||||
let mime = matches[1];
|
||||
if (parts[0].indexOf("base64") !== -1) {
|
||||
let bstr = atob(parts[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
|
||||
return new (Zotero.getMainWindow().Blob)([u8arr], { type: mime });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async _importImage(note: Zotero.Item, src, download = false) {
|
||||
let blob;
|
||||
if (src.startsWith("data:")) {
|
||||
blob = this._dataURLtoBlob(src);
|
||||
} else if (download) {
|
||||
let res;
|
||||
|
||||
try {
|
||||
res = await Zotero.HTTP.request("GET", src, { responseType: "blob" });
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
blob = res.response;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
let attachment = await Zotero.Attachments.importEmbeddedImage({
|
||||
blob,
|
||||
parentItemID: note.id,
|
||||
saveOptions: {},
|
||||
});
|
||||
|
||||
return attachment.key;
|
||||
}
|
||||
|
||||
public async importImagesToNote(note: Zotero.Item, annotations: any) {
|
||||
for (let annotation of annotations) {
|
||||
if (annotation.image) {
|
||||
annotation.imageAttachmentKey = await this._importImage(
|
||||
note,
|
||||
annotation.image
|
||||
);
|
||||
}
|
||||
delete annotation.image;
|
||||
}
|
||||
}
|
||||
|
||||
public async addAnnotationsToNote(
|
||||
note: Zotero.Item,
|
||||
annotations: Zotero.Item[],
|
||||
lineIndex: number
|
||||
) {
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
const html = await this._Addon.NoteParse.parseAnnotationHTML(
|
||||
note,
|
||||
annotations
|
||||
);
|
||||
await this.addLineToNote(note, html, lineIndex);
|
||||
return html;
|
||||
}
|
||||
|
||||
public addLinkToNote(
|
||||
targetNote: Zotero.Item,
|
||||
linkedNote: Zotero.Item,
|
||||
lineIndex: number,
|
||||
sectionName: string
|
||||
) {
|
||||
if (!targetNote) {
|
||||
return;
|
||||
}
|
||||
if (!linkedNote.isNote()) {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
"Not a note item"
|
||||
);
|
||||
return;
|
||||
}
|
||||
const link = this.getNoteLink(linkedNote);
|
||||
const linkText = linkedNote.getNoteTitle().trim();
|
||||
|
||||
const linkTemplate = this._Addon.TemplateController.renderTemplate(
|
||||
"[QuickInsert]",
|
||||
"link, subNoteItem, noteItem, sectionName, lineIndex",
|
||||
[link, linkedNote, targetNote, sectionName, lineIndex]
|
||||
);
|
||||
|
||||
this.addLineToNote(targetNote, linkTemplate, lineIndex);
|
||||
|
||||
const backLinkTemplate = this._Addon.TemplateController.renderTemplate(
|
||||
"[QuickBackLink]",
|
||||
"subNoteItem, noteItem, sectionName, lineIndex",
|
||||
[linkedNote, targetNote, sectionName, lineIndex],
|
||||
false
|
||||
);
|
||||
|
||||
if (backLinkTemplate) {
|
||||
this.addLineToNote(linkedNote, backLinkTemplate, -1);
|
||||
}
|
||||
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Link is added to workspace${lineIndex >= 0 ? ` line ${lineIndex}` : ""}`
|
||||
);
|
||||
}
|
||||
|
||||
public getNoteLink(
|
||||
note: Zotero.Item,
|
||||
options: {
|
||||
ignore?: boolean;
|
||||
withLine?: boolean;
|
||||
} = { ignore: false, withLine: false }
|
||||
) {
|
||||
let libraryID = note.libraryID;
|
||||
let library = Zotero.Libraries.get(libraryID);
|
||||
let groupID: string;
|
||||
if (library.libraryType === "user") {
|
||||
groupID = "u";
|
||||
} else if (library.libraryType === "group") {
|
||||
groupID = `${library.id}`;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
let noteKey = note.key;
|
||||
let link = `zotero://note/${groupID}/${noteKey}/`;
|
||||
const addParam = (link: string, param: string): string => {
|
||||
const lastChar = link[link.length - 1];
|
||||
if (lastChar === "/") {
|
||||
link += "?";
|
||||
} else if (lastChar !== "?" && lastChar !== "&") {
|
||||
link += "&";
|
||||
}
|
||||
return `${link}${param}`;
|
||||
};
|
||||
if (options.ignore || options.withLine) {
|
||||
if (options.ignore) {
|
||||
link = addParam(link, "ignore=1");
|
||||
}
|
||||
if (options.withLine) {
|
||||
if (!this.currentLine[note.id]) {
|
||||
this.currentLine[note.id] = 0;
|
||||
}
|
||||
link = addParam(link, `line=${this.currentLine[note.id]}`);
|
||||
}
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
public getAnnotationLink(annotation: Zotero.Item) {
|
||||
let position = JSON.parse(annotation.annotationPosition);
|
||||
let openURI: string;
|
||||
|
||||
const attachment = annotation.parentItem;
|
||||
let libraryID = attachment.libraryID;
|
||||
let library = Zotero.Libraries.get(libraryID);
|
||||
if (library.libraryType === "user") {
|
||||
openURI = `zotero://open-pdf/library/items/${attachment.key}`;
|
||||
} else if (library.libraryType === "group") {
|
||||
openURI = `zotero://open-pdf/groups/${library.id}/items/${attachment.key}`;
|
||||
} else {
|
||||
openURI = "";
|
||||
}
|
||||
|
||||
openURI +=
|
||||
"?page=" +
|
||||
(position.pageIndex + 1) +
|
||||
(annotation.key ? "&annotation=" + annotation.key : "");
|
||||
|
||||
return openURI;
|
||||
}
|
||||
|
||||
async modifyLineInNote(
|
||||
note: Zotero.Item,
|
||||
text: string | Function,
|
||||
lineIndex: number,
|
||||
forceMetadata: boolean = false
|
||||
) {
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
let noteLines = this.getLinesInNote(note);
|
||||
if (lineIndex < 0 || lineIndex >= noteLines.length) {
|
||||
return;
|
||||
}
|
||||
if (typeof text === "string") {
|
||||
noteLines[lineIndex] = text;
|
||||
} else if (typeof text === "function") {
|
||||
noteLines[lineIndex] = text(noteLines[lineIndex]);
|
||||
}
|
||||
const editorInstance = this._Addon.WorkspaceWindow.getEditorInstance(note);
|
||||
if (editorInstance && !forceMetadata) {
|
||||
// The note is opened. Add line via note editor
|
||||
console.log("Modify note line via note editor");
|
||||
const _document = editorInstance._iframeWindow.document;
|
||||
const currentElement: HTMLElement =
|
||||
this._Addon.NoteParse.parseHTMLLineElement(
|
||||
_document.querySelector(".primary-editor"),
|
||||
lineIndex
|
||||
);
|
||||
const frag = _document.createDocumentFragment();
|
||||
const temp = _document.createElement("div");
|
||||
temp.innerHTML = noteLines[lineIndex];
|
||||
while (temp.firstChild) {
|
||||
frag.appendChild(temp.firstChild);
|
||||
}
|
||||
currentElement.replaceWith(frag);
|
||||
this._Addon.EditorViews.scrollToPosition(
|
||||
editorInstance,
|
||||
currentElement.offsetTop
|
||||
);
|
||||
} else {
|
||||
await this.setLinesToNote(note, noteLines);
|
||||
await this.scrollWithRefresh(lineIndex);
|
||||
}
|
||||
}
|
||||
|
||||
async changeHeadingLineInNote(
|
||||
note: Zotero.Item,
|
||||
rankChange: number,
|
||||
lineIndex: number
|
||||
) {
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
const noteLines = this.getLinesInNote(note);
|
||||
if (lineIndex < 0 || lineIndex >= noteLines.length) {
|
||||
return;
|
||||
}
|
||||
const headerStartReg = new RegExp("<h[1-6]>");
|
||||
const headerStopReg = new RegExp("</h[1-6]>");
|
||||
let headerStart = noteLines[lineIndex].search(headerStartReg);
|
||||
if (headerStart === -1) {
|
||||
return;
|
||||
}
|
||||
let lineRank = parseInt(noteLines[lineIndex][headerStart + 2]) + rankChange;
|
||||
if (lineRank > 6) {
|
||||
lineRank = 6;
|
||||
} else if (lineRank < 1) {
|
||||
lineRank = 1;
|
||||
}
|
||||
this.modifyLineInNote(
|
||||
note,
|
||||
noteLines[lineIndex]
|
||||
.replace(headerStartReg, `<h${lineRank}>`)
|
||||
.replace(headerStopReg, `</h${lineRank}>`),
|
||||
lineIndex
|
||||
);
|
||||
}
|
||||
|
||||
moveHeaderLineInNote(
|
||||
note: Zotero.Item,
|
||||
currentNode: TreeModel.Node<object>,
|
||||
targetNode: TreeModel.Node<object>,
|
||||
as: "child" | "before" | "after"
|
||||
) {
|
||||
if (!note || targetNode.getPath().indexOf(currentNode) >= 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let targetIndex = 0;
|
||||
let targetRank = 1;
|
||||
|
||||
let lines = this.getLinesInNote(note);
|
||||
|
||||
if (as === "child") {
|
||||
targetIndex = targetNode.model.endIndex;
|
||||
targetRank = targetNode.model.rank === 6 ? 6 : targetNode.model.rank + 1;
|
||||
} else if (as === "before") {
|
||||
targetIndex = targetNode.model.lineIndex;
|
||||
targetRank =
|
||||
targetNode.model.rank === 7
|
||||
? targetNode.parent.model.rank === 6
|
||||
? 6
|
||||
: targetNode.parent.model.rank + 1
|
||||
: targetNode.model.rank;
|
||||
} else if (as === "after") {
|
||||
targetIndex = targetNode.model.endIndex;
|
||||
targetRank =
|
||||
targetNode.model.rank === 7
|
||||
? targetNode.parent.model.rank === 6
|
||||
? 6
|
||||
: targetNode.parent.model.rank + 1
|
||||
: targetNode.model.rank;
|
||||
}
|
||||
|
||||
let rankChange = targetRank - currentNode.model.rank;
|
||||
|
||||
Zotero.debug(`move to ${targetIndex}`);
|
||||
|
||||
let movedLines = lines.splice(
|
||||
currentNode.model.lineIndex,
|
||||
currentNode.model.endIndex - currentNode.model.lineIndex
|
||||
);
|
||||
|
||||
let headerReg = /<\/?h[1-6]>/g;
|
||||
for (const i in movedLines) {
|
||||
movedLines[i] = movedLines[i].replace(headerReg, (e) => {
|
||||
let rank = parseInt(e.slice(-2, -1));
|
||||
rank += rankChange;
|
||||
if (rank > 6) {
|
||||
rank = 6;
|
||||
}
|
||||
if (rank < 1) {
|
||||
rank = 1;
|
||||
}
|
||||
return `${e.slice(0, -2)}${rank}>`;
|
||||
});
|
||||
}
|
||||
let newLines = lines
|
||||
.slice(0, targetIndex)
|
||||
.concat(movedLines, lines.slice(targetIndex));
|
||||
this.setLinesToNote(note, newLines);
|
||||
}
|
||||
|
||||
getNoteTree(note: Zotero.Item): TreeModel.Node<object> {
|
||||
// See http://jnuno.com/tree-model-js
|
||||
if (!note) {
|
||||
return undefined;
|
||||
}
|
||||
return this._Addon.NoteParse.parseNoteTree(note);
|
||||
}
|
||||
|
||||
getNoteTreeAsList(
|
||||
note: Zotero.Item,
|
||||
filterRoot: boolean = true,
|
||||
filterLink: boolean = true
|
||||
): TreeModel.Node<object>[] {
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
return this.getNoteTree(note).all(
|
||||
(node) =>
|
||||
(!filterRoot || node.model.lineIndex >= 0) &&
|
||||
(!filterLink || node.model.rank <= 6)
|
||||
);
|
||||
}
|
||||
|
||||
getNoteTreeNodeById(
|
||||
note: Zotero.Item,
|
||||
id: number,
|
||||
root: TreeModel.Node<object> = undefined
|
||||
) {
|
||||
root = root || this.getNoteTree(note);
|
||||
return root.first(function (node) {
|
||||
return node.model.id === id;
|
||||
});
|
||||
}
|
||||
|
||||
getNoteTreeNodesByRank(
|
||||
note: Zotero.Item,
|
||||
rank: number,
|
||||
root: TreeModel.Node<object> = undefined
|
||||
) {
|
||||
root = root || this.getNoteTree(note);
|
||||
return root.all(function (node) {
|
||||
return node.model.rank === rank;
|
||||
});
|
||||
}
|
||||
|
||||
getLineParentNode(
|
||||
note: Zotero.Item,
|
||||
lineIndex: number = -1
|
||||
): TreeModel.Node<object> {
|
||||
if (lineIndex < 0) {
|
||||
lineIndex = this.currentLine[note.id];
|
||||
lineIndex =
|
||||
lineIndex && lineIndex >= 0
|
||||
? lineIndex
|
||||
: this.getLinesInNote(note).length;
|
||||
}
|
||||
let nodes = this.getNoteTreeAsList(note);
|
||||
if (!nodes.length || nodes[0].model.lineIndex > lineIndex) {
|
||||
// There is no parent node
|
||||
return undefined;
|
||||
} else if (nodes[nodes.length - 1].model.lineIndex <= lineIndex) {
|
||||
return nodes[nodes.length - 1];
|
||||
} else {
|
||||
for (let i = 0; i < nodes.length - 1; i++) {
|
||||
if (
|
||||
nodes[i].model.lineIndex <= lineIndex &&
|
||||
nodes[i + 1].model.lineIndex > lineIndex
|
||||
) {
|
||||
return nodes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async scrollWithRefresh(lineIndex: number) {
|
||||
await Zotero.Promise.delay(500);
|
||||
let editorInstance =
|
||||
await this._Addon.WorkspaceWindow.getWorkspaceEditorInstance();
|
||||
if (!editorInstance) {
|
||||
return;
|
||||
}
|
||||
this._Addon.EditorViews.scrollToLine(editorInstance, lineIndex);
|
||||
}
|
||||
|
||||
async convertNoteLines(
|
||||
currentNote: Zotero.Item,
|
||||
rootNoteIds: number[],
|
||||
convertNoteLinks: boolean = true
|
||||
): Promise<{ lines: string[]; subNotes: Zotero.Item[] }> {
|
||||
Zotero.debug(`convert note ${currentNote.id}`);
|
||||
|
||||
let subNotes: Zotero.Item[] = [];
|
||||
const [..._rootNoteIds] = rootNoteIds;
|
||||
_rootNoteIds.push(currentNote.id);
|
||||
|
||||
let newLines: string[] = [];
|
||||
const noteLines = this.getLinesInNote(currentNote);
|
||||
for (let i in noteLines) {
|
||||
newLines.push(noteLines[i]);
|
||||
// Convert Link
|
||||
if (convertNoteLinks) {
|
||||
let link = this._Addon.NoteParse.parseLinkInText(noteLines[i]);
|
||||
while (link) {
|
||||
const linkIndex = noteLines[i].indexOf(link);
|
||||
const params = this._Addon.NoteParse.parseParamsFromLink(link);
|
||||
if (
|
||||
params.ignore ||
|
||||
// Ignore links that are not in <a>
|
||||
!noteLines[i].slice(linkIndex - 8, linkIndex).includes("href")
|
||||
) {
|
||||
Zotero.debug("ignore link");
|
||||
noteLines[i] = noteLines[i].substring(
|
||||
noteLines[i].search(/zotero:\/\/note\//g)
|
||||
);
|
||||
noteLines[i] = noteLines[i].substring(
|
||||
noteLines[i].search(/<\/a>/g) + "</a>".length
|
||||
);
|
||||
link = this._Addon.NoteParse.parseLinkInText(noteLines[i]);
|
||||
continue;
|
||||
}
|
||||
Zotero.debug("convert link");
|
||||
let res = await this.getNoteFromLink(link);
|
||||
const subNote = res.item;
|
||||
if (subNote && _rootNoteIds.indexOf(subNote.id) === -1) {
|
||||
Zotero.debug(`Knowledge4Zotero: Exporting sub-note ${link}`);
|
||||
const convertResult = await this.convertNoteLines(
|
||||
subNote,
|
||||
_rootNoteIds,
|
||||
convertNoteLinks
|
||||
);
|
||||
const subNoteLines = convertResult.lines;
|
||||
|
||||
const templateText =
|
||||
await this._Addon.TemplateController.renderTemplateAsync(
|
||||
"[QuickImport]",
|
||||
"subNoteLines, subNoteItem, noteItem",
|
||||
[subNoteLines, subNote, currentNote]
|
||||
);
|
||||
newLines.push(templateText);
|
||||
subNotes.push(subNote);
|
||||
subNotes = subNotes.concat(convertResult.subNotes);
|
||||
}
|
||||
noteLines[i] = noteLines[i].substring(
|
||||
noteLines[i].search(/zotero:\/\/note\//g)
|
||||
);
|
||||
noteLines[i] = noteLines[i].substring(
|
||||
noteLines[i].search(/<\/a>/g) + "</a>".length
|
||||
);
|
||||
link = this._Addon.NoteParse.parseLinkInText(noteLines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Zotero.debug(subNotes);
|
||||
return { lines: newLines, subNotes: subNotes };
|
||||
}
|
||||
|
||||
async getNoteFromLink(uri: string) {
|
||||
const params = this._Addon.NoteParse.parseParamsFromLink(uri);
|
||||
if (!params.libraryID) {
|
||||
return {
|
||||
item: false,
|
||||
infoText: "Library does not exist or access denied.",
|
||||
};
|
||||
}
|
||||
Zotero.debug(params);
|
||||
let item = await Zotero.Items.getByLibraryAndKeyAsync(
|
||||
params.libraryID,
|
||||
params.noteKey
|
||||
);
|
||||
if (!item || !item.isNote()) {
|
||||
return {
|
||||
item: false,
|
||||
args: params,
|
||||
infoText: "Note does not exist or is not a note.",
|
||||
};
|
||||
}
|
||||
return {
|
||||
item: item,
|
||||
args: params,
|
||||
infoText: "OK",
|
||||
};
|
||||
}
|
||||
|
||||
public async onSelectionChange(editor: Zotero.EditorInstance) {
|
||||
// Update current line index
|
||||
const _window = editor._iframeWindow;
|
||||
const selection = _window.document.getSelection();
|
||||
if (!selection || !selection.focusNode) {
|
||||
return;
|
||||
}
|
||||
const realElement = selection.focusNode.parentElement;
|
||||
let focusNode = selection.focusNode as XUL.Element;
|
||||
if (!focusNode || !realElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
function getChildIndex(node) {
|
||||
return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
|
||||
}
|
||||
|
||||
// Make sure this is a direct child node of editor
|
||||
try {
|
||||
while (
|
||||
focusNode.parentElement &&
|
||||
(!focusNode.parentElement.className ||
|
||||
focusNode.parentElement.className.indexOf("primary-editor") === -1)
|
||||
) {
|
||||
focusNode = focusNode.parentNode as XUL.Element;
|
||||
}
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!focusNode.parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
let currentLineIndex = getChildIndex(focusNode);
|
||||
|
||||
// Parse list
|
||||
const diveTagNames = ["OL", "UL", "LI"];
|
||||
|
||||
// Find list elements before current line
|
||||
const listElements = Array.prototype.filter.call(
|
||||
Array.prototype.slice.call(
|
||||
focusNode.parentElement.childNodes,
|
||||
0,
|
||||
currentLineIndex
|
||||
),
|
||||
(e) => diveTagNames.includes(e.tagName)
|
||||
);
|
||||
|
||||
for (const e of listElements) {
|
||||
currentLineIndex += this._Addon.NoteParse.parseListElements(e).length - 1;
|
||||
}
|
||||
|
||||
// Find list index if current line is inside a list
|
||||
if (diveTagNames.includes(focusNode.tagName)) {
|
||||
const eleList = this._Addon.NoteParse.parseListElements(focusNode);
|
||||
for (const i in eleList) {
|
||||
if (realElement.parentElement === eleList[i]) {
|
||||
currentLineIndex += Number(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Zotero.debug(`Knowledge4Zotero: line ${currentLineIndex} selected.`);
|
||||
console.log(currentLineIndex);
|
||||
Zotero.debug(
|
||||
`Current Element: ${focusNode.outerHTML}; Real Element: ${realElement.outerHTML}`
|
||||
);
|
||||
this.currentLine[editor._item.id] = currentLineIndex;
|
||||
if (realElement.tagName === "A") {
|
||||
let link = (realElement as HTMLLinkElement).href;
|
||||
let linkedNote = (await this.getNoteFromLink(link)).item;
|
||||
if (linkedNote) {
|
||||
let t = 0;
|
||||
let linkPopup = _window.document.querySelector(".link-popup");
|
||||
while (
|
||||
!(
|
||||
linkPopup &&
|
||||
(linkPopup.querySelector("a") as unknown as HTMLLinkElement)
|
||||
.href === link
|
||||
) &&
|
||||
t < 100
|
||||
) {
|
||||
t += 1;
|
||||
linkPopup = _window.document.querySelector(".link-popup");
|
||||
await Zotero.Promise.delay(30);
|
||||
}
|
||||
await this._Addon.EditorViews.updateEditorPopupButtons(
|
||||
editor._iframeWindow,
|
||||
link
|
||||
);
|
||||
} else {
|
||||
await this._Addon.EditorViews.updateEditorPopupButtons(
|
||||
editor._iframeWindow,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default NoteUtils;
|
||||
2322
src/events.ts
2322
src/events.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,33 +0,0 @@
|
|||
export async function pick(title: string, mode: 'open' | 'save' | 'folder', filters?: [string, string][], suggestion?: string): Promise<string> {
|
||||
const fp = Components.classes['@mozilla.org/filepicker;1'].createInstance(Components.interfaces.nsIFilePicker)
|
||||
|
||||
if (suggestion) fp.defaultString = suggestion
|
||||
|
||||
mode = {
|
||||
open: Components.interfaces.nsIFilePicker.modeOpen,
|
||||
save: Components.interfaces.nsIFilePicker.modeSave,
|
||||
folder: Components.interfaces.nsIFilePicker.modeGetFolder,
|
||||
}[mode]
|
||||
|
||||
fp.init(window, title, mode)
|
||||
|
||||
for (const [label, ext] of (filters || [])) {
|
||||
fp.appendFilter(label, ext)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return new Zotero.Promise(resolve => {
|
||||
fp.open(userChoice => {
|
||||
switch (userChoice) {
|
||||
case Components.interfaces.nsIFilePicker.returnOK:
|
||||
case Components.interfaces.nsIFilePicker.returnReplace:
|
||||
resolve(fp.file.path)
|
||||
break
|
||||
|
||||
default: // aka returnCancel
|
||||
resolve('')
|
||||
break
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
1202
src/knowledge.ts
1202
src/knowledge.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,8 @@
|
|||
import Knowledge4Zotero from "./addon";
|
||||
|
||||
class AddonBase {
|
||||
protected _Addon: any;
|
||||
constructor(parent: any) {
|
||||
protected _Addon: Knowledge4Zotero;
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
this._Addon = parent;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,340 @@
|
|||
const CryptoJS = require("crypto-js");
|
||||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
import { EditorMessage } from "../utils";
|
||||
|
||||
class ReaderViews extends AddonBase {
|
||||
icons: object;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this.icons = {
|
||||
createNote: `<svg t="1651630304116" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14011" width="16" height="16"><path d="M791.30324 369.7c-5 5-6.2 12.7-2.8 18.9 17.5 31.9 27.4 68.5 27.4 107.4 0 56.2-20.7 107.6-54.9 147-4.5 5.1-5.1 12.6-1.8 18.4l39.2 67.9c3.3 5.7 9.6 8.7 16.1 7.8 6-0.8 12.1-1.2 18.3-1.2 70.1 0.5 128 59.7 127.1 129.7-0.9 69.7-57.4 125.9-127.1 126.4-70.9 0.5-128.9-57.1-128.9-128 0-38.1 16.7-72.3 43.1-95.8l-37-64c-4.2-7.3-13.3-10-20.9-6.4-29.3 14.2-62.3 22.2-97.2 22.2-26.7 0-52.3-4.7-76-13.2-7.3-2.6-15.4 0.3-19.3 7l-24.9 43.1c-3.1 5.4-2.8 12.1 0.8 17.2 15 21.2 23.7 47.1 23.5 75.1-0.7 69.5-57.5 126.2-127 126.8-71.6 0.6-129.8-57.7-129.1-129.4 0.8-69.7 58-126.5 127.8-126.6 12 0 23.7 1.6 34.8 4.7 7 2 14.5-1.1 18.2-7.4l21.7-37.6c3.7-6.4 2.5-14.6-2.9-19.6-33.6-31.2-57.5-72.6-67-119.2-1.5-7.5-8-12.9-15.7-12.9h-92c-6.9 0-13.1 4.5-15.2 11.1C232.80324 590.2 184.70324 627 128.00324 627 57.00324 627-0.49676 569.2 0.00324 498.1 0.40324 427.5 58.60324 370.3 129.20324 371c54.2 0.5 100.4 34.8 118.5 82.8C250.00324 460 256.00324 464 262.60324 464h94.1c7.6 0 14.2-5.3 15.7-12.7 11-54.2 41.5-101.3 84-133.6 6.4-4.9 8.2-13.8 4.2-20.8l-2.2-3.8c-3.5-6-10.3-9-17.1-7.7-8.8 1.8-18 2.7-27.4 2.5-69.5-1-126.9-60.1-126-129.6 0.9-70.3 58.4-126.9 129-126.3 69.3 0.6 126 57 127 126.2 0.4 31.6-10.6 60.7-29.3 83.2-4.3 5.2-5 12.5-1.6 18.3l6.6 11.4c3.6 6.2 10.8 9.3 17.7 7.5 17.5-4.4 35.8-6.7 54.6-6.7 52.3 0 100.4 17.9 138.6 48 6.4 5 15.5 4.5 21.2-1.2l24.2-24.2c4.7-4.7 6-11.8 3.3-17.8-7.3-16.1-11.3-34-11.3-52.8 0-70.7 57.3-128 128-128 70.6 0 128 57.4 128 128 0 70.7-57.3 128-128 128-20.7 0-40.2-4.9-57.5-13.6-6.2-3.1-13.7-2-18.7 2.9l-28.4 28.5z" p-id="14012" fill="#ffd400"></path></svg>`,
|
||||
ocrTex: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><defs><style>.cls-1{fill-opacity: 0;}.cls-2{fill:#ffd400;}</style></defs><rect class="cls-1" width="24" height="24"/><path class="cls-2" d="M9,7.1H2.33L2.14,9.56H2.4c.15-1.77.32-2.14,2-2.14a3.39,3.39,0,0,1,.59,0c.23,0,.23.16.23.41v5.77c0,.37,0,.53-1.15.53H3.61v.34c.45,0,1.56,0,2.06,0s1.64,0,2.09,0v-.34H7.32c-1.15,0-1.15-.16-1.15-.53V7.86c0-.22,0-.37.19-.41a3.9,3.9,0,0,1,.63,0c1.65,0,1.81.37,2,2.14h.27L9,7.1Z"/><path class="cls-2" d="M14.91,14.15h-.27c-.28,1.68-.53,2.48-2.41,2.48H10.78c-.52,0-.54-.08-.54-.44V13.27h1c1.06,0,1.19.35,1.19,1.28h.27v-2.9h-.27c0,.94-.13,1.28-1.19,1.28h-1V10.3c0-.36,0-.44.54-.44h1.41c1.68,0,2,.61,2.14,2.13h.27l-.3-2.46H8.14v.33H8.4c.84,0,.86.12.86.52v5.73c0,.4,0,.52-.86.52H8.14V17h6.31Z"/><path class="cls-2" d="M18.22,10.27l1.5-2.2a1.67,1.67,0,0,1,1.58-.71V7H18.69v.33c.44,0,.68.25.68.5a.37.37,0,0,1-.1.26L18,10,16.61,7.85a.46.46,0,0,1-.07-.16c0-.13.24-.32.7-.33V7c-.37,0-1.18,0-1.59,0s-1,0-1.43,0v.33h.21c.6,0,.81.08,1,.38l2,3-1.79,2.64a1.67,1.67,0,0,1-1.58.73v.34H16.7v-.34c-.5,0-.69-.31-.69-.51s0-.14.11-.26l1.55-2.3,1.73,2.62s.06.09.06.12-.24.32-.72.33v.34c.39,0,1.19,0,1.6,0s1,0,1.42,0v-.34h-.2c-.58,0-.81-.06-1-.4l-2.3-3.49Z"/></svg>`,
|
||||
};
|
||||
}
|
||||
|
||||
async addReaderAnnotationButton(reader: _ZoteroReaderInstance) {
|
||||
if (!reader) {
|
||||
return false;
|
||||
}
|
||||
await reader._initPromise;
|
||||
let updateCount = 0;
|
||||
const _document = reader._iframeWindow.document;
|
||||
for (const moreButton of _document.getElementsByClassName("more")) {
|
||||
if (moreButton.getAttribute("knowledgeinit") === "true") {
|
||||
updateCount += 1;
|
||||
continue;
|
||||
}
|
||||
moreButton.setAttribute("knowledgeinit", "true");
|
||||
const createNoteButton = _document.createElement("div");
|
||||
createNoteButton.setAttribute("style", "margin: 5px;");
|
||||
createNoteButton.title = "Quick Note";
|
||||
createNoteButton.innerHTML = this.icons["createNote"];
|
||||
|
||||
let annotationWrapper = moreButton;
|
||||
while (!annotationWrapper.getAttribute("data-sidebar-annotation-id")) {
|
||||
annotationWrapper = annotationWrapper.parentElement;
|
||||
}
|
||||
const itemKey = annotationWrapper.getAttribute(
|
||||
"data-sidebar-annotation-id"
|
||||
);
|
||||
const libraryID = (Zotero.Items.get(reader.itemID) as Zotero.Item)
|
||||
.libraryID;
|
||||
const annotationItem = await Zotero.Items.getByLibraryAndKeyAsync(
|
||||
libraryID,
|
||||
itemKey
|
||||
);
|
||||
|
||||
createNoteButton.addEventListener("click", async (e) => {
|
||||
await this.createNoteFromAnnotation(annotationItem);
|
||||
e.preventDefault();
|
||||
});
|
||||
createNoteButton.addEventListener("mouseover", (e: XUL.XULEvent) => {
|
||||
createNoteButton.setAttribute(
|
||||
"style",
|
||||
"background: #F0F0F0; margin: 5px;"
|
||||
);
|
||||
});
|
||||
createNoteButton.addEventListener("mouseout", (e: XUL.XULEvent) => {
|
||||
createNoteButton.setAttribute("style", "margin: 5px;");
|
||||
});
|
||||
moreButton.before(createNoteButton);
|
||||
if (annotationItem.annotationType === "image") {
|
||||
// Image OCR
|
||||
const ocrButton = _document.createElement("div");
|
||||
ocrButton.setAttribute("style", "margin: 5px;");
|
||||
ocrButton.innerHTML = this.icons["ocrTex"];
|
||||
ocrButton.title = "OCR LaTex";
|
||||
ocrButton.addEventListener("click", async (e) => {
|
||||
await this.OCRImageAnnotation(
|
||||
(
|
||||
ocrButton.parentElement.parentElement
|
||||
.nextSibling as HTMLImageElement
|
||||
).src,
|
||||
annotationItem
|
||||
);
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
ocrButton.addEventListener("mouseover", (e: XUL.XULEvent) => {
|
||||
ocrButton.setAttribute("style", "background: #F0F0F0; margin: 5px;");
|
||||
});
|
||||
ocrButton.addEventListener("mouseout", (e: XUL.XULEvent) => {
|
||||
ocrButton.setAttribute("style", "margin: 5px;");
|
||||
});
|
||||
moreButton.before(ocrButton);
|
||||
}
|
||||
updateCount += 1;
|
||||
}
|
||||
return reader.annotationItemIDs.length === updateCount;
|
||||
}
|
||||
|
||||
public async buildReaderAnnotationButtons() {
|
||||
Zotero.debug("Knowledge4Zotero: buildReaderAnnotationButton");
|
||||
for (const reader of Zotero.Reader._readers) {
|
||||
Zotero.debug("reader found");
|
||||
let t = 0;
|
||||
while (t < 100 && !(await this.addReaderAnnotationButton(reader))) {
|
||||
await Zotero.Promise.delay(50);
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async createNoteFromAnnotation(annotationItem: Zotero.Item) {
|
||||
if (annotationItem.annotationComment) {
|
||||
const text = annotationItem.annotationComment;
|
||||
let link = this._Addon.NoteParse.parseLinkInText(text);
|
||||
|
||||
if (link) {
|
||||
const note = (await this._Addon.NoteUtils.getNoteFromLink(link)).item;
|
||||
if (note && note.id) {
|
||||
await this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("onNoteLink", {
|
||||
params: {
|
||||
item: note,
|
||||
infoText: "OK",
|
||||
},
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const note: Zotero.Item = new Zotero.Item("note");
|
||||
note.libraryID = annotationItem.libraryID;
|
||||
note.parentID = annotationItem.parentItem.parentID;
|
||||
await note.saveTx();
|
||||
|
||||
ZoteroPane.openNoteWindow(note.id);
|
||||
let editorInstance: Zotero.EditorInstance =
|
||||
this._Addon.WorkspaceWindow.getEditorInstance(note);
|
||||
let t = 0;
|
||||
// Wait for editor instance
|
||||
while (t < 10 && !editorInstance) {
|
||||
await Zotero.Promise.delay(500);
|
||||
t += 1;
|
||||
editorInstance = this._Addon.WorkspaceWindow.getEditorInstance(note);
|
||||
}
|
||||
|
||||
const renderredTemplate =
|
||||
await this._Addon.TemplateController.renderTemplateAsync(
|
||||
"[QuickNoteV3]",
|
||||
"annotationItem, topItem, noteItem",
|
||||
[annotationItem, annotationItem.parentItem.parentItem, note]
|
||||
);
|
||||
await this._Addon.NoteUtils.addLineToNote(
|
||||
note,
|
||||
renderredTemplate,
|
||||
0,
|
||||
false,
|
||||
"before"
|
||||
);
|
||||
|
||||
const tags = annotationItem.getTags();
|
||||
for (const tag of tags) {
|
||||
note.addTag(tag.tag, tag.type);
|
||||
}
|
||||
await note.saveTx();
|
||||
|
||||
annotationItem.annotationComment = `${
|
||||
annotationItem.annotationComment ? annotationItem.annotationComment : ""
|
||||
}\nnote link: "${this._Addon.NoteUtils.getNoteLink(note)}"`;
|
||||
await annotationItem.saveTx();
|
||||
}
|
||||
|
||||
private async OCRImageAnnotation(src: string, annotationItem: Zotero.Item) {
|
||||
/*
|
||||
message.content = {
|
||||
params: { src: string, annotationItem: Zotero.Item }
|
||||
}
|
||||
*/
|
||||
let result: string;
|
||||
let success: boolean;
|
||||
const engine = Zotero.Prefs.get("Knowledge4Zotero.OCREngine");
|
||||
if (engine === "mathpix") {
|
||||
const xhr = await Zotero.HTTP.request(
|
||||
"POST",
|
||||
"https://api.mathpix.com/v3/text",
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
app_id: Zotero.Prefs.get("Knowledge4Zotero.OCRMathpix.Appid"),
|
||||
app_key: Zotero.Prefs.get("Knowledge4Zotero.OCRMathpix.Appkey"),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
src: src,
|
||||
math_inline_delimiters: ["$", "$"],
|
||||
math_display_delimiters: ["$$", "$$"],
|
||||
rm_spaces: true,
|
||||
}),
|
||||
responseType: "json",
|
||||
}
|
||||
);
|
||||
console.log(xhr);
|
||||
if (xhr && xhr.status && xhr.status === 200 && xhr.response.text) {
|
||||
result = xhr.response.text;
|
||||
success = true;
|
||||
} else {
|
||||
result =
|
||||
xhr.status === 200 ? xhr.response.error : `${xhr.status} Error`;
|
||||
success = false;
|
||||
}
|
||||
} else if (engine === "xunfei") {
|
||||
/**
|
||||
* 1.Doc:https://www.xfyun.cn/doc/words/formula-discern/API.html
|
||||
* 2.Error code:https://www.xfyun.cn/document/error-code
|
||||
* @author iflytek
|
||||
*/
|
||||
|
||||
const config = {
|
||||
hostUrl: "https://rest-api.xfyun.cn/v2/itr",
|
||||
host: "rest-api.xfyun.cn",
|
||||
appid: Zotero.Prefs.get("Knowledge4Zotero.OCRXunfei.APPID"),
|
||||
apiSecret: Zotero.Prefs.get("Knowledge4Zotero.OCRXunfei.APISecret"),
|
||||
apiKey: Zotero.Prefs.get("Knowledge4Zotero.OCRXunfei.APIKey"),
|
||||
uri: "/v2/itr",
|
||||
};
|
||||
|
||||
let date = new Date().toUTCString();
|
||||
let postBody = getPostBody();
|
||||
let digest = getDigest(postBody);
|
||||
|
||||
const xhr = await Zotero.HTTP.request("POST", config.hostUrl, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json,version=1.0",
|
||||
Host: config.host,
|
||||
Date: date,
|
||||
Digest: digest,
|
||||
Authorization: getAuthStr(date, digest),
|
||||
},
|
||||
body: JSON.stringify(postBody),
|
||||
responseType: "json",
|
||||
});
|
||||
|
||||
if (xhr?.response?.code === 0) {
|
||||
result = xhr.response.data.region
|
||||
.filter((r) => r.type === "text")
|
||||
.map((r) => r.recog.content)
|
||||
.join(" ")
|
||||
.replace(/ifly-latex-(begin)?(end)?/g, "$");
|
||||
console.log(xhr);
|
||||
success = true;
|
||||
} else {
|
||||
result =
|
||||
xhr.status === 200
|
||||
? `${xhr.response.code} ${xhr.response.message}`
|
||||
: `${xhr.status} Error`;
|
||||
success = false;
|
||||
}
|
||||
|
||||
function getPostBody() {
|
||||
let digestObj = {
|
||||
common: {
|
||||
app_id: config.appid,
|
||||
},
|
||||
business: {
|
||||
ent: "teach-photo-print",
|
||||
aue: "raw",
|
||||
},
|
||||
data: {
|
||||
image: src.split(",").pop(),
|
||||
},
|
||||
};
|
||||
return digestObj;
|
||||
}
|
||||
|
||||
function getDigest(body) {
|
||||
return (
|
||||
"SHA-256=" +
|
||||
CryptoJS.enc.Base64.stringify(CryptoJS.SHA256(JSON.stringify(body)))
|
||||
);
|
||||
}
|
||||
|
||||
function getAuthStr(date, digest) {
|
||||
let signatureOrigin = `host: ${config.host}\ndate: ${date}\nPOST ${config.uri} HTTP/1.1\ndigest: ${digest}`;
|
||||
let signatureSha = CryptoJS.HmacSHA256(
|
||||
signatureOrigin,
|
||||
config.apiSecret
|
||||
);
|
||||
let signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||
let authorizationOrigin = `api_key="${config.apiKey}", algorithm="hmac-sha256", headers="host date request-line digest", signature="${signature}"`;
|
||||
return authorizationOrigin;
|
||||
}
|
||||
} else if (engine === "bing") {
|
||||
const xhr = await Zotero.HTTP.request(
|
||||
"POST",
|
||||
"https://www.bing.com/cameraexp/api/v1/getlatex",
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: src.split(",").pop(),
|
||||
inputForm: "Image",
|
||||
clientInfo: { platform: "edge" },
|
||||
}),
|
||||
responseType: "json",
|
||||
}
|
||||
);
|
||||
if (xhr && xhr.status && xhr.status === 200 && !xhr.response.isError) {
|
||||
result = xhr.response.latex
|
||||
? `$${xhr.response.latex}$`
|
||||
: xhr.response.ocrText;
|
||||
success = true;
|
||||
} else {
|
||||
result =
|
||||
xhr.status === 200
|
||||
? xhr.response.errorMessage
|
||||
: `${xhr.status} Error`;
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
result = "OCR Engine Not Found";
|
||||
success = false;
|
||||
}
|
||||
if (success) {
|
||||
annotationItem.annotationComment = `${
|
||||
annotationItem.annotationComment
|
||||
? `${annotationItem.annotationComment}\n`
|
||||
: ""
|
||||
}${result}`;
|
||||
await annotationItem.saveTx();
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes OCR",
|
||||
`OCR Result: ${result}`
|
||||
);
|
||||
} else {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes OCR",
|
||||
result,
|
||||
"fail"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ReaderViews;
|
||||
|
|
@ -1,114 +1,20 @@
|
|||
import Knowledge4Zotero from "./addon";
|
||||
import AddonBase from "./module";
|
||||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class AddonSync extends AddonBase {
|
||||
class SyncController extends AddonBase {
|
||||
triggerTime: number;
|
||||
private io: {
|
||||
dataIn: any;
|
||||
dataOut: any;
|
||||
deferred?: typeof Promise;
|
||||
};
|
||||
private _window: Window;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
doLoad(_window: Window) {
|
||||
if (this._window && !this._window.closed) {
|
||||
this._window.close();
|
||||
}
|
||||
this._window = _window;
|
||||
this.io = (this._window as unknown as XUL.XULWindow).arguments[0];
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
doUpdate() {
|
||||
const syncInfo = this.getNoteSyncStatus(this.io.dataIn);
|
||||
const syncPathLable = this._window.document.getElementById(
|
||||
"Knowledge4Zotero-sync-path"
|
||||
);
|
||||
const path = `${decodeURIComponent(syncInfo.path)}/${decodeURIComponent(
|
||||
syncInfo.filename
|
||||
)}`;
|
||||
|
||||
syncPathLable.setAttribute(
|
||||
"value",
|
||||
path.length > 50
|
||||
? `${path.slice(0, 25)}...${path.slice(path.length - 25)}`
|
||||
: path
|
||||
);
|
||||
syncPathLable.setAttribute("tooltiptext", path);
|
||||
|
||||
const copyCbk = (event) => {
|
||||
Zotero.Utilities.Internal.copyTextToClipboard(event.target.tooltipText);
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Path Copied",
|
||||
event.target.tooltipText
|
||||
);
|
||||
};
|
||||
syncPathLable.removeEventListener("click", copyCbk);
|
||||
syncPathLable.addEventListener("click", copyCbk);
|
||||
|
||||
let lastSync: string;
|
||||
const lastSyncTime = Number(syncInfo.lastsync);
|
||||
const currentTime = new Date().getTime();
|
||||
if (currentTime - lastSyncTime <= 60000) {
|
||||
lastSync = `${Math.round(
|
||||
(currentTime - lastSyncTime) / 1000
|
||||
)} seconds ago.`;
|
||||
} else if (currentTime - lastSyncTime <= 3600000) {
|
||||
lastSync = `${Math.round(
|
||||
(currentTime - lastSyncTime) / 60000
|
||||
)} minutes ago.`;
|
||||
} else {
|
||||
lastSync = new Date(lastSyncTime).toLocaleString();
|
||||
}
|
||||
this._window.document
|
||||
.getElementById("Knowledge4Zotero-sync-lastsync")
|
||||
.setAttribute("value", lastSync);
|
||||
setTimeout(() => {
|
||||
if (!this._window.closed) {
|
||||
this.doUpdate();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
doUnload() {
|
||||
this.io.deferred && this.io.deferred.resolve();
|
||||
}
|
||||
|
||||
async doAccept() {
|
||||
// Update Settings
|
||||
let enable = (
|
||||
this._window.document.getElementById(
|
||||
"Knowledge4Zotero-sync-enable"
|
||||
) as XUL.Checkbox
|
||||
).checked;
|
||||
if (!enable) {
|
||||
const note = this.io.dataIn;
|
||||
const allNoteIds = await this.getRelatedNoteIds(note);
|
||||
const notes = Zotero.Items.get(allNoteIds) as Zotero.Item[];
|
||||
for (const item of notes) {
|
||||
await this.removeSyncNote(item);
|
||||
}
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Cancel sync of ${notes.length} notes.`
|
||||
);
|
||||
}
|
||||
}
|
||||
doExport() {
|
||||
this.io.dataOut.export = true;
|
||||
(this._window.document.querySelector("dialog") as any).acceptDialog();
|
||||
}
|
||||
|
||||
getSyncNoteIds(): number[] {
|
||||
const ids = Zotero.Prefs.get("Knowledge4Zotero.syncNoteIds") as string;
|
||||
return ids.split(",").map((id: string) => Number(id));
|
||||
}
|
||||
|
||||
isSyncNote(note: Zotero.Item): boolean {
|
||||
const syncNoteIds = this._Addon.sync.getSyncNoteIds();
|
||||
const syncNoteIds = this.getSyncNoteIds();
|
||||
return syncNoteIds.includes(note.id);
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +27,7 @@ class AddonSync extends AddonBase {
|
|||
const subNoteIds = (
|
||||
await Promise.all(
|
||||
linkMatches.map(async (link) =>
|
||||
this._Addon.knowledge.getNoteFromLink(link)
|
||||
this._Addon.NoteUtils.getNoteFromLink(link)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -132,8 +38,8 @@ class AddonSync extends AddonBase {
|
|||
return allNoteIds;
|
||||
}
|
||||
|
||||
async getRelatedNoteIdsFromNotes(notes: Zotero.Item[]): Promise<Number[]> {
|
||||
let allNoteIds: Number[] = [];
|
||||
async getRelatedNoteIdsFromNotes(notes: Zotero.Item[]): Promise<number[]> {
|
||||
let allNoteIds: number[] = [];
|
||||
for (const note of notes) {
|
||||
allNoteIds = allNoteIds.concat(await this.getRelatedNoteIds(note));
|
||||
}
|
||||
|
|
@ -222,7 +128,9 @@ class AddonSync extends AddonBase {
|
|||
items = items || (Zotero.Items.get(this.getSyncNoteIds()) as Zotero.Item[]);
|
||||
const toExport = {};
|
||||
const forceNoteIds = force
|
||||
? await this.getRelatedNoteIdsFromNotes(useIO ? [this.io.dataIn] : items)
|
||||
? await this.getRelatedNoteIdsFromNotes(
|
||||
useIO ? [this._Addon.SyncInfoWindow.io.dataIn] : items
|
||||
)
|
||||
: [];
|
||||
for (const item of items) {
|
||||
const syncInfo = this.getNoteSyncStatus(item);
|
||||
|
|
@ -242,12 +150,15 @@ class AddonSync extends AddonBase {
|
|||
}
|
||||
console.log(toExport);
|
||||
for (const filepath of Object.keys(toExport)) {
|
||||
await this._Addon.knowledge.syncNotesToFile(toExport[filepath], filepath);
|
||||
await this._Addon.NoteExport.syncNotesToFile(
|
||||
toExport[filepath],
|
||||
filepath
|
||||
);
|
||||
}
|
||||
if (this._window && !this._window.closed) {
|
||||
this.doUpdate();
|
||||
if (this._Addon.SyncInfoWindow._window && !this._Addon.SyncInfoWindow._window.closed) {
|
||||
this._Addon.SyncInfoWindow.doUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AddonSync;
|
||||
export default SyncController;
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class SyncInfoWindow extends AddonBase {
|
||||
triggerTime: number;
|
||||
public io: {
|
||||
dataIn: any;
|
||||
dataOut: any;
|
||||
deferred?: typeof Promise;
|
||||
};
|
||||
public _window: Window;
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
doLoad(_window: Window) {
|
||||
if (this._window && !this._window.closed) {
|
||||
this._window.close();
|
||||
}
|
||||
this._window = _window;
|
||||
this.io = (this._window as unknown as XUL.XULWindow).arguments[0];
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
doUpdate() {
|
||||
const syncInfo = this._Addon.SyncController.getNoteSyncStatus(
|
||||
this.io.dataIn
|
||||
);
|
||||
const syncPathLable = this._window.document.getElementById(
|
||||
"Knowledge4Zotero-sync-path"
|
||||
);
|
||||
const path = `${decodeURIComponent(syncInfo.path)}/${decodeURIComponent(
|
||||
syncInfo.filename
|
||||
)}`;
|
||||
|
||||
syncPathLable.setAttribute(
|
||||
"value",
|
||||
path.length > 50
|
||||
? `${path.slice(0, 25)}...${path.slice(path.length - 25)}`
|
||||
: path
|
||||
);
|
||||
syncPathLable.setAttribute("tooltiptext", path);
|
||||
|
||||
const copyCbk = (event) => {
|
||||
Zotero.Utilities.Internal.copyTextToClipboard(event.target.tooltipText);
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Path Copied",
|
||||
event.target.tooltipText
|
||||
);
|
||||
};
|
||||
syncPathLable.removeEventListener("click", copyCbk);
|
||||
syncPathLable.addEventListener("click", copyCbk);
|
||||
|
||||
let lastSync: string;
|
||||
const lastSyncTime = Number(syncInfo.lastsync);
|
||||
const currentTime = new Date().getTime();
|
||||
if (currentTime - lastSyncTime <= 60000) {
|
||||
lastSync = `${Math.round(
|
||||
(currentTime - lastSyncTime) / 1000
|
||||
)} seconds ago.`;
|
||||
} else if (currentTime - lastSyncTime <= 3600000) {
|
||||
lastSync = `${Math.round(
|
||||
(currentTime - lastSyncTime) / 60000
|
||||
)} minutes ago.`;
|
||||
} else {
|
||||
lastSync = new Date(lastSyncTime).toLocaleString();
|
||||
}
|
||||
this._window.document
|
||||
.getElementById("Knowledge4Zotero-sync-lastsync")
|
||||
.setAttribute("value", lastSync);
|
||||
setTimeout(() => {
|
||||
if (!this._window.closed) {
|
||||
this.doUpdate();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
doUnload() {
|
||||
this.io.deferred && this.io.deferred.resolve();
|
||||
}
|
||||
|
||||
async doAccept() {
|
||||
// Update Settings
|
||||
let enable = (
|
||||
this._window.document.getElementById(
|
||||
"Knowledge4Zotero-sync-enable"
|
||||
) as XUL.Checkbox
|
||||
).checked;
|
||||
if (!enable) {
|
||||
const note = this.io.dataIn;
|
||||
const allNoteIds = await this._Addon.SyncController.getRelatedNoteIds(
|
||||
note
|
||||
);
|
||||
const notes = Zotero.Items.get(allNoteIds) as Zotero.Item[];
|
||||
for (const item of notes) {
|
||||
await this._Addon.SyncController.removeSyncNote(item);
|
||||
}
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Cancel sync of ${notes.length} notes.`
|
||||
);
|
||||
}
|
||||
}
|
||||
doExport() {
|
||||
this.io.dataOut.export = true;
|
||||
(this._window.document.querySelector("dialog") as any).acceptDialog();
|
||||
}
|
||||
}
|
||||
|
||||
export default SyncInfoWindow;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import Knowledge4Zotero from "./addon";
|
||||
import AddonBase from "./module";
|
||||
import Knowledge4Zotero from "../addon";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class AddonSyncList extends AddonBase {
|
||||
class SyncListWindow extends AddonBase {
|
||||
private _window: Window;
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
|
|
@ -30,7 +30,7 @@ class AddonSyncList extends AddonBase {
|
|||
return;
|
||||
}
|
||||
const notes = Zotero.Items.get(
|
||||
this._Addon.sync.getSyncNoteIds()
|
||||
this._Addon.SyncController.getSyncNoteIds()
|
||||
) as Zotero.Item[];
|
||||
const listbox = this._window.document.getElementById("sync-list");
|
||||
let e,
|
||||
|
|
@ -40,7 +40,7 @@ class AddonSyncList extends AddonBase {
|
|||
e.parentElement.removeChild(e);
|
||||
}
|
||||
for (const note of notes) {
|
||||
const syncInfo = this._Addon.sync.getNoteSyncStatus(note);
|
||||
const syncInfo = this._Addon.SyncController.getNoteSyncStatus(note);
|
||||
const listitem: XUL.ListItem =
|
||||
this._window.document.createElement("listitem");
|
||||
listitem.setAttribute("id", note.id);
|
||||
|
|
@ -119,7 +119,7 @@ class AddonSyncList extends AddonBase {
|
|||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
await this._Addon.sync.doSync(selectedItems, true, false);
|
||||
await this._Addon.SyncController.doSync(selectedItems, true, false);
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ class AddonSyncList extends AddonBase {
|
|||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
await this._Addon.knowledge.exportNotesToFile(selectedItems, false, true);
|
||||
await this._Addon.NoteExport.exportNotesToFile(selectedItems, false, true);
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
|
|
@ -154,16 +154,16 @@ class AddonSyncList extends AddonBase {
|
|||
return;
|
||||
}
|
||||
if (this.useRelated()) {
|
||||
let noteIds: number[] = await this._Addon.sync.getRelatedNoteIdsFromNotes(
|
||||
let noteIds: number[] = await this._Addon.SyncController.getRelatedNoteIdsFromNotes(
|
||||
selectedItems
|
||||
);
|
||||
selectedItems = Zotero.Items.get(noteIds) as Zotero.Item[];
|
||||
}
|
||||
for (const note of selectedItems) {
|
||||
await this._Addon.sync.removeSyncNote(note);
|
||||
await this._Addon.SyncController.removeSyncNote(note);
|
||||
}
|
||||
this.doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
export default AddonSyncList;
|
||||
export default SyncListWindow;
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
import Knowledge4Zotero from "./addon";
|
||||
import { NoteTemplate } from "./base";
|
||||
import AddonBase from "./module";
|
||||
import Knowledge4Zotero from "../addon";
|
||||
import { NoteTemplate } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class AddonTemplate extends AddonBase {
|
||||
private _window: Window;
|
||||
class TemplateController extends AddonBase {
|
||||
_systemTemplateNames: string[];
|
||||
_defaultTemplates: NoteTemplate[];
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
|
|
@ -12,7 +11,7 @@ class AddonTemplate extends AddonBase {
|
|||
"[QuickInsert]",
|
||||
"[QuickBackLink]",
|
||||
"[QuickImport]",
|
||||
"[QuickNoteV2]",
|
||||
"[QuickNoteV3]",
|
||||
"[ExportMDFileName]",
|
||||
];
|
||||
this._defaultTemplates = [
|
||||
|
|
@ -32,8 +31,8 @@ class AddonTemplate extends AddonBase {
|
|||
disabled: false,
|
||||
},
|
||||
{
|
||||
name: "[QuickNoteV2]",
|
||||
text: '${await new Promise(async (r) => {\nlet res = ""\nif(annotationItem.annotationComment){\nres += Zotero.Knowledge4Zotero.parse.parseMDToHTML(annotationItem.annotationComment);\n}\nres += await Zotero.Knowledge4Zotero.parse.parseAnnotationHTML(noteItem, [annotationItem], true);\nr(res);})}',
|
||||
name: "[QuickNoteV3]",
|
||||
text: '${await new Promise(async (r) => {\nlet res = ""\nif(annotationItem.annotationComment){\nres += Zotero.Knowledge4Zotero.NoteParse.parseMDToHTML(annotationItem.annotationComment);\n}\nres += await Zotero.Knowledge4Zotero.NoteParse.parseAnnotationHTML(noteItem, [annotationItem], true);\nr(res);})}',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
|
|
@ -69,248 +68,6 @@ class AddonTemplate extends AddonBase {
|
|||
];
|
||||
}
|
||||
|
||||
openEditor() {
|
||||
if (this._window && !this._window.closed) {
|
||||
this._window.focus();
|
||||
} else {
|
||||
window.open(
|
||||
"chrome://Knowledge4Zotero/content/template.xul",
|
||||
"_blank",
|
||||
"chrome,extrachrome,centerscreen,width=800,height=400,resizable=yes"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
initTemplates(_window: Window) {
|
||||
this._window = _window;
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
resetTemplates() {
|
||||
let oldTemplatesRaw: string = Zotero.Prefs.get(
|
||||
"Knowledge4Zotero.noteTemplate"
|
||||
) as string;
|
||||
// Convert old version
|
||||
if (oldTemplatesRaw) {
|
||||
const templates: NoteTemplate[] = JSON.parse(oldTemplatesRaw);
|
||||
for (const template of templates) {
|
||||
this.setTemplate(template);
|
||||
}
|
||||
Zotero.Prefs.clear("Knowledge4Zotero.noteTemplate");
|
||||
}
|
||||
// Convert buggy template
|
||||
if (!this.getTemplateText("[QuickBackLink]").includes("ignore=1")) {
|
||||
this.setTemplate(
|
||||
this._defaultTemplates.find((t) => t.name === "[QuickBackLink]")
|
||||
);
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
"The [QuickBackLink] is reset because of missing ignore=1 in link."
|
||||
);
|
||||
}
|
||||
let templateKeys = this.getTemplateKeys();
|
||||
const currentNames = templateKeys.map((t) => t.name);
|
||||
for (const defaultTemplate of this._defaultTemplates) {
|
||||
if (!currentNames.includes(defaultTemplate.name)) {
|
||||
this.setTemplate(defaultTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCitationStyle(): Object {
|
||||
let format = Zotero.Prefs.get("Knowledge4Zotero.citeFormat") as string;
|
||||
try {
|
||||
if (format) {
|
||||
format = JSON.parse(format);
|
||||
} else {
|
||||
throw Error("format not initialized");
|
||||
}
|
||||
} catch (e) {
|
||||
format = Zotero.QuickCopy.getFormatFromURL(
|
||||
Zotero.QuickCopy.lastActiveURL
|
||||
);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
Zotero.Prefs.set("Knowledge4Zotero.citeFormat", JSON.stringify(format));
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
getSelectedTemplateName(): string {
|
||||
const listbox: XUL.ListItem =
|
||||
this._window.document.getElementById("template-list");
|
||||
const selectedItem = listbox.selectedItem;
|
||||
if (selectedItem) {
|
||||
const name = selectedItem.getAttribute("id");
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
updateTemplateView() {
|
||||
const templates = this.getTemplateKeys();
|
||||
const listbox = this._window.document.getElementById("template-list");
|
||||
let e,
|
||||
es = this._window.document.getElementsByTagName("listitem");
|
||||
while (es.length > 0) {
|
||||
e = es[0];
|
||||
e.parentElement.removeChild(e);
|
||||
}
|
||||
for (const template of templates) {
|
||||
const listitem = this._window.document.createElement("listitem");
|
||||
listitem.setAttribute("id", template.name);
|
||||
const name = this._window.document.createElement("listcell");
|
||||
name.setAttribute("label", template.name);
|
||||
if (this._systemTemplateNames.includes(template.name)) {
|
||||
listitem.style.color = "#f2ac46";
|
||||
}
|
||||
listitem.append(name);
|
||||
listbox.append(listitem);
|
||||
}
|
||||
this.updateEditorView();
|
||||
}
|
||||
|
||||
updateEditorView() {
|
||||
Zotero.debug("update editor");
|
||||
console.log("update editor");
|
||||
const name = this.getSelectedTemplateName();
|
||||
const templateText = this.getTemplateText(name);
|
||||
|
||||
const header: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-name");
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
const saveTemplate = this._window.document.getElementById("save-template");
|
||||
const deleteTemplate =
|
||||
this._window.document.getElementById("delete-template");
|
||||
const resetTemplate =
|
||||
this._window.document.getElementById("reset-template");
|
||||
if (!name) {
|
||||
header.value = "";
|
||||
header.setAttribute("disabled", "true");
|
||||
text.value = "";
|
||||
text.setAttribute("disabled", "true");
|
||||
saveTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.hidden = false;
|
||||
resetTemplate.hidden = true;
|
||||
} else {
|
||||
header.value = name;
|
||||
if (!this._systemTemplateNames.includes(name)) {
|
||||
header.removeAttribute("disabled");
|
||||
deleteTemplate.hidden = false;
|
||||
resetTemplate.hidden = true;
|
||||
} else {
|
||||
header.setAttribute("disabled", "true");
|
||||
deleteTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.hidden = true;
|
||||
resetTemplate.hidden = false;
|
||||
}
|
||||
text.value = templateText;
|
||||
text.removeAttribute("disabled");
|
||||
saveTemplate.removeAttribute("disabled");
|
||||
deleteTemplate.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
createTemplate() {
|
||||
const template: NoteTemplate = {
|
||||
name: `New Template: ${new Date().getTime()}`,
|
||||
text: "",
|
||||
disabled: false,
|
||||
};
|
||||
this.setTemplate(template);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
async importNoteTemplate() {
|
||||
const io = {
|
||||
// Not working
|
||||
singleSelection: true,
|
||||
dataIn: null,
|
||||
dataOut: null,
|
||||
deferred: Zotero.Promise.defer(),
|
||||
};
|
||||
|
||||
(window as unknown as XUL.XULWindow).openDialog(
|
||||
"chrome://zotero/content/selectItemsDialog.xul",
|
||||
"",
|
||||
"chrome,dialog=no,centerscreen,resizable=yes",
|
||||
io
|
||||
);
|
||||
await io.deferred.promise;
|
||||
|
||||
const ids = io.dataOut;
|
||||
const note: Zotero.Item = (Zotero.Items.get(ids) as Zotero.Item[]).filter(
|
||||
(item: Zotero.Item) => item.isNote()
|
||||
)[0];
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
const template: NoteTemplate = {
|
||||
name: `Template from ${note.getNoteTitle()}: ${new Date().getTime()}`,
|
||||
text: note.getNote(),
|
||||
disabled: false,
|
||||
};
|
||||
this.setTemplate(template);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
saveSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
const header: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-name");
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
|
||||
if (this._systemTemplateNames.includes(name) && header.value !== name) {
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is a system template. Modifying template name is not allowed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const template = this.getTemplateKey(name);
|
||||
template.name = header.value;
|
||||
template.text = text.value;
|
||||
this.setTemplate(template);
|
||||
if (name !== template.name) {
|
||||
this.removeTemplate(name);
|
||||
}
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${template.name} saved.`
|
||||
);
|
||||
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
deleteSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
if (this._systemTemplateNames.includes(name)) {
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is a system template. Removing system template is note allowed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.removeTemplate(name);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
resetSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
if (this._systemTemplateNames.includes(name)) {
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
text.value = this._defaultTemplates.find((t) => t.name === name).text;
|
||||
this._Addon.views.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is reset. Please save before leaving.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderTemplate(
|
||||
key: string,
|
||||
argString: string = "",
|
||||
|
|
@ -468,6 +225,97 @@ class AddonTemplate extends AddonBase {
|
|||
this.removeTemplateKey(keyName);
|
||||
Zotero.Prefs.clear(`Knowledge4Zotero.template.${keyName}`);
|
||||
}
|
||||
|
||||
resetTemplates() {
|
||||
let oldTemplatesRaw: string = Zotero.Prefs.get(
|
||||
"Knowledge4Zotero.noteTemplate"
|
||||
) as string;
|
||||
// Convert old version
|
||||
if (oldTemplatesRaw) {
|
||||
const templates: NoteTemplate[] = JSON.parse(oldTemplatesRaw);
|
||||
for (const template of templates) {
|
||||
this._Addon.TemplateController.setTemplate(template);
|
||||
}
|
||||
Zotero.Prefs.clear("Knowledge4Zotero.noteTemplate");
|
||||
}
|
||||
// Convert buggy template
|
||||
if (
|
||||
!this._Addon.TemplateController.getTemplateText(
|
||||
"[QuickBackLink]"
|
||||
).includes("ignore=1")
|
||||
) {
|
||||
this._Addon.TemplateController.setTemplate(
|
||||
this._Addon.TemplateController._defaultTemplates.find(
|
||||
(t) => t.name === "[QuickBackLink]"
|
||||
)
|
||||
);
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
"The [QuickBackLink] is reset because of missing ignore=1 in link."
|
||||
);
|
||||
}
|
||||
let templateKeys = this._Addon.TemplateController.getTemplateKeys();
|
||||
const currentNames = templateKeys.map((t) => t.name);
|
||||
for (const defaultTemplate of this._Addon.TemplateController
|
||||
._defaultTemplates) {
|
||||
if (!currentNames.includes(defaultTemplate.name)) {
|
||||
this._Addon.TemplateController.setTemplate(defaultTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCitationStyle(): {
|
||||
mode: string;
|
||||
contentType: string;
|
||||
id: string;
|
||||
locale: string;
|
||||
} {
|
||||
let format = Zotero.Prefs.get("Knowledge4Zotero.citeFormat") as string;
|
||||
try {
|
||||
if (format) {
|
||||
format = JSON.parse(format);
|
||||
} else {
|
||||
throw Error("format not initialized");
|
||||
}
|
||||
} catch (e) {
|
||||
format = Zotero.QuickCopy.getFormatFromURL(
|
||||
Zotero.QuickCopy.lastActiveURL
|
||||
);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
Zotero.Prefs.set("Knowledge4Zotero.citeFormat", JSON.stringify(format));
|
||||
}
|
||||
return format as any;
|
||||
}
|
||||
}
|
||||
|
||||
export default AddonTemplate;
|
||||
/*
|
||||
* This part is for the template usage only
|
||||
* to keep API consistency
|
||||
*/
|
||||
class TemplateAPI extends AddonBase {
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public getNoteLink(
|
||||
note: Zotero.Item,
|
||||
options: {
|
||||
ignore?: boolean;
|
||||
withLine?: boolean;
|
||||
} = { ignore: false, withLine: false }
|
||||
) {
|
||||
return this._Addon.NoteUtils.getNoteLink(note, options);
|
||||
}
|
||||
|
||||
public async getWorkspaceEditorInstance(
|
||||
type: "main" | "preview" = "main",
|
||||
wait: boolean = true
|
||||
) {
|
||||
return await this._Addon.WorkspaceWindow.getWorkspaceEditorInstance(
|
||||
type,
|
||||
wait
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { TemplateController, TemplateAPI };
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { NoteTemplate } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class TemplateWindow extends AddonBase {
|
||||
private _window: Window;
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
openEditor() {
|
||||
if (this._window && !this._window.closed) {
|
||||
this._window.focus();
|
||||
} else {
|
||||
window.open(
|
||||
"chrome://Knowledge4Zotero/content/template.xul",
|
||||
"_blank",
|
||||
"chrome,extrachrome,centerscreen,width=800,height=400,resizable=yes"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
initTemplates(_window: Window) {
|
||||
this._window = _window;
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
getSelectedTemplateName(): string {
|
||||
const listbox: XUL.ListItem =
|
||||
this._window.document.getElementById("template-list");
|
||||
const selectedItem = listbox.selectedItem;
|
||||
if (selectedItem) {
|
||||
const name = selectedItem.getAttribute("id");
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
updateTemplateView() {
|
||||
const templates = this._Addon.TemplateController.getTemplateKeys();
|
||||
const listbox = this._window.document.getElementById("template-list");
|
||||
let e,
|
||||
es = this._window.document.getElementsByTagName("listitem");
|
||||
while (es.length > 0) {
|
||||
e = es[0];
|
||||
e.parentElement.removeChild(e);
|
||||
}
|
||||
for (const template of templates) {
|
||||
const listitem = this._window.document.createElement("listitem");
|
||||
listitem.setAttribute("id", template.name);
|
||||
const name = this._window.document.createElement("listcell");
|
||||
name.setAttribute("label", template.name);
|
||||
if (
|
||||
this._Addon.TemplateController._systemTemplateNames.includes(
|
||||
template.name
|
||||
)
|
||||
) {
|
||||
listitem.style.color = "#f2ac46";
|
||||
}
|
||||
listitem.append(name);
|
||||
listbox.append(listitem);
|
||||
}
|
||||
this.updateEditorView();
|
||||
}
|
||||
|
||||
updateEditorView() {
|
||||
Zotero.debug("update editor");
|
||||
console.log("update editor");
|
||||
const name = this.getSelectedTemplateName();
|
||||
const templateText = this._Addon.TemplateController.getTemplateText(name);
|
||||
|
||||
const header: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-name");
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
const saveTemplate = this._window.document.getElementById("save-template");
|
||||
const deleteTemplate =
|
||||
this._window.document.getElementById("delete-template");
|
||||
const resetTemplate =
|
||||
this._window.document.getElementById("reset-template");
|
||||
if (!name) {
|
||||
header.value = "";
|
||||
header.setAttribute("disabled", "true");
|
||||
text.value = "";
|
||||
text.setAttribute("disabled", "true");
|
||||
saveTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.hidden = false;
|
||||
resetTemplate.hidden = true;
|
||||
} else {
|
||||
header.value = name;
|
||||
if (!this._Addon.TemplateController._systemTemplateNames.includes(name)) {
|
||||
header.removeAttribute("disabled");
|
||||
deleteTemplate.hidden = false;
|
||||
resetTemplate.hidden = true;
|
||||
} else {
|
||||
header.setAttribute("disabled", "true");
|
||||
deleteTemplate.setAttribute("disabled", "true");
|
||||
deleteTemplate.hidden = true;
|
||||
resetTemplate.hidden = false;
|
||||
}
|
||||
text.value = templateText;
|
||||
text.removeAttribute("disabled");
|
||||
saveTemplate.removeAttribute("disabled");
|
||||
deleteTemplate.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
createTemplate() {
|
||||
const template: NoteTemplate = {
|
||||
name: `New Template: ${new Date().getTime()}`,
|
||||
text: "",
|
||||
disabled: false,
|
||||
};
|
||||
this._Addon.TemplateController.setTemplate(template);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
async importNoteTemplate() {
|
||||
const io = {
|
||||
// Not working
|
||||
singleSelection: true,
|
||||
dataIn: null,
|
||||
dataOut: null,
|
||||
deferred: Zotero.Promise.defer(),
|
||||
};
|
||||
|
||||
(window as unknown as XUL.XULWindow).openDialog(
|
||||
"chrome://zotero/content/selectItemsDialog.xul",
|
||||
"",
|
||||
"chrome,dialog=no,centerscreen,resizable=yes",
|
||||
io
|
||||
);
|
||||
await io.deferred.promise;
|
||||
|
||||
const ids = io.dataOut;
|
||||
const note: Zotero.Item = (Zotero.Items.get(ids) as Zotero.Item[]).filter(
|
||||
(item: Zotero.Item) => item.isNote()
|
||||
)[0];
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
const template: NoteTemplate = {
|
||||
name: `Template from ${note.getNoteTitle()}: ${new Date().getTime()}`,
|
||||
text: note.getNote(),
|
||||
disabled: false,
|
||||
};
|
||||
this._Addon.TemplateController.setTemplate(template);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
saveSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
const header: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-name");
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
|
||||
if (
|
||||
this._Addon.TemplateController._systemTemplateNames.includes(name) &&
|
||||
header.value !== name
|
||||
) {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is a system template. Modifying template name is not allowed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const template = this._Addon.TemplateController.getTemplateKey(name);
|
||||
template.name = header.value;
|
||||
template.text = text.value;
|
||||
this._Addon.TemplateController.setTemplate(template);
|
||||
if (name !== template.name) {
|
||||
this._Addon.TemplateController.removeTemplate(name);
|
||||
}
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${template.name} saved.`
|
||||
);
|
||||
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
deleteSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
if (this._Addon.TemplateController._systemTemplateNames.includes(name)) {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is a system template. Removing system template is note allowed.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
this._Addon.TemplateController.removeTemplate(name);
|
||||
this.updateTemplateView();
|
||||
}
|
||||
|
||||
resetSelectedTemplate() {
|
||||
const name = this.getSelectedTemplateName();
|
||||
if (this._Addon.TemplateController._systemTemplateNames.includes(name)) {
|
||||
const text: XUL.Textbox =
|
||||
this._window.document.getElementById("editor-textbox");
|
||||
text.value = this._Addon.TemplateController._defaultTemplates.find(
|
||||
(t) => t.name === name
|
||||
).text;
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Template ${name} is reset. Please save before leaving.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default TemplateWindow;
|
||||
291
src/treemodel.js
291
src/treemodel.js
|
|
@ -1,291 +0,0 @@
|
|||
var mergeSort, findInsertIndex;
|
||||
mergeSort = require('mergesort');
|
||||
findInsertIndex = require('find-insert-index');
|
||||
|
||||
module.exports = (function () {
|
||||
'use strict';
|
||||
|
||||
var walkStrategies;
|
||||
|
||||
walkStrategies = {};
|
||||
|
||||
function k(result) {
|
||||
return function () {
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function TreeModel(config) {
|
||||
config = config || {};
|
||||
this.config = config;
|
||||
this.config.childrenPropertyName = config.childrenPropertyName || 'children';
|
||||
this.config.modelComparatorFn = config.modelComparatorFn;
|
||||
}
|
||||
|
||||
function addChildToNode(node, child) {
|
||||
child.parent = node;
|
||||
node.children.push(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
function Node(config, model) {
|
||||
this.config = config;
|
||||
this.model = model;
|
||||
this.children = [];
|
||||
}
|
||||
|
||||
TreeModel.prototype.parse = function (model) {
|
||||
var i, childCount, node;
|
||||
|
||||
// if (!(model instanceof Object)) {
|
||||
// throw new TypeError('Model must be of type object.');
|
||||
// }
|
||||
|
||||
node = new Node(this.config, model);
|
||||
if (model[this.config.childrenPropertyName] instanceof Array) {
|
||||
if (this.config.modelComparatorFn) {
|
||||
model[this.config.childrenPropertyName] = mergeSort(
|
||||
this.config.modelComparatorFn,
|
||||
model[this.config.childrenPropertyName]);
|
||||
}
|
||||
for (i = 0, childCount = model[this.config.childrenPropertyName].length; i < childCount; i++) {
|
||||
addChildToNode(node, this.parse(model[this.config.childrenPropertyName][i]));
|
||||
}
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
function hasComparatorFunction(node) {
|
||||
return typeof node.config.modelComparatorFn === 'function';
|
||||
}
|
||||
|
||||
Node.prototype.isRoot = function () {
|
||||
return this.parent === undefined;
|
||||
};
|
||||
|
||||
Node.prototype.hasChildren = function () {
|
||||
return this.children.length > 0;
|
||||
};
|
||||
|
||||
function addChild(self, child, insertIndex) {
|
||||
var index;
|
||||
|
||||
if (!(child instanceof Node)) {
|
||||
throw new TypeError('Child must be of type Node.');
|
||||
}
|
||||
|
||||
child.parent = self;
|
||||
if (!(self.model[self.config.childrenPropertyName] instanceof Array)) {
|
||||
self.model[self.config.childrenPropertyName] = [];
|
||||
}
|
||||
|
||||
if (hasComparatorFunction(self)) {
|
||||
// Find the index to insert the child
|
||||
index = findInsertIndex(
|
||||
self.config.modelComparatorFn,
|
||||
self.model[self.config.childrenPropertyName],
|
||||
child.model);
|
||||
|
||||
// Add to the model children
|
||||
self.model[self.config.childrenPropertyName].splice(index, 0, child.model);
|
||||
|
||||
// Add to the node children
|
||||
self.children.splice(index, 0, child);
|
||||
} else {
|
||||
if (insertIndex === undefined) {
|
||||
self.model[self.config.childrenPropertyName].push(child.model);
|
||||
self.children.push(child);
|
||||
} else {
|
||||
if (insertIndex < 0 || insertIndex > self.children.length) {
|
||||
throw new Error('Invalid index.');
|
||||
}
|
||||
self.model[self.config.childrenPropertyName].splice(insertIndex, 0, child.model);
|
||||
self.children.splice(insertIndex, 0, child);
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
Node.prototype.addChild = function (child) {
|
||||
return addChild(this, child);
|
||||
};
|
||||
|
||||
Node.prototype.addChildAtIndex = function (child, index) {
|
||||
if (hasComparatorFunction(this)) {
|
||||
throw new Error('Cannot add child at index when using a comparator function.');
|
||||
}
|
||||
|
||||
return addChild(this, child, index);
|
||||
};
|
||||
|
||||
Node.prototype.setIndex = function (index) {
|
||||
if (hasComparatorFunction(this)) {
|
||||
throw new Error('Cannot set node index when using a comparator function.');
|
||||
}
|
||||
|
||||
if (this.isRoot()) {
|
||||
if (index === 0) {
|
||||
return this;
|
||||
}
|
||||
throw new Error('Invalid index.');
|
||||
}
|
||||
|
||||
if (index < 0 || index >= this.parent.children.length) {
|
||||
throw new Error('Invalid index.');
|
||||
}
|
||||
|
||||
var oldIndex = this.parent.children.indexOf(this);
|
||||
|
||||
this.parent.children.splice(index, 0, this.parent.children.splice(oldIndex, 1)[0]);
|
||||
|
||||
this.parent.model[this.parent.config.childrenPropertyName]
|
||||
.splice(index, 0, this.parent.model[this.parent.config.childrenPropertyName].splice(oldIndex, 1)[0]);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Node.prototype.getPath = function () {
|
||||
var path = [];
|
||||
(function addToPath(node) {
|
||||
path.unshift(node);
|
||||
if (!node.isRoot()) {
|
||||
addToPath(node.parent);
|
||||
}
|
||||
})(this);
|
||||
return path;
|
||||
};
|
||||
|
||||
Node.prototype.getIndex = function () {
|
||||
if (this.isRoot()) {
|
||||
return 0;
|
||||
}
|
||||
return this.parent.children.indexOf(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse the arguments of traversal functions. These functions can take one optional
|
||||
* first argument which is an options object. If present, this object will be stored
|
||||
* in args.options. The only mandatory argument is the callback function which can
|
||||
* appear in the first or second position (if an options object is given). This
|
||||
* function will be saved to args.fn. The last optional argument is the context on
|
||||
* which the callback function will be called. It will be available in args.ctx.
|
||||
*
|
||||
* @returns Parsed arguments.
|
||||
*/
|
||||
function parseArgs() {
|
||||
var args = {};
|
||||
if (arguments.length === 1) {
|
||||
if (typeof arguments[0] === 'function') {
|
||||
args.fn = arguments[0];
|
||||
} else {
|
||||
args.options = arguments[0];
|
||||
}
|
||||
} else if (arguments.length === 2) {
|
||||
if (typeof arguments[0] === 'function') {
|
||||
args.fn = arguments[0];
|
||||
args.ctx = arguments[1];
|
||||
} else {
|
||||
args.options = arguments[0];
|
||||
args.fn = arguments[1];
|
||||
}
|
||||
} else {
|
||||
args.options = arguments[0];
|
||||
args.fn = arguments[1];
|
||||
args.ctx = arguments[2];
|
||||
}
|
||||
args.options = args.options || {};
|
||||
if (!args.options.strategy) {
|
||||
args.options.strategy = 'pre';
|
||||
}
|
||||
if (!walkStrategies[args.options.strategy]) {
|
||||
throw new Error('Unknown tree walk strategy. Valid strategies are \'pre\' [default], \'post\' and \'breadth\'.');
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
Node.prototype.walk = function () {
|
||||
var args;
|
||||
args = parseArgs.apply(this, arguments);
|
||||
walkStrategies[args.options.strategy].call(this, args.fn, args.ctx);
|
||||
};
|
||||
|
||||
walkStrategies.pre = function depthFirstPreOrder(callback, context) {
|
||||
var i, childCount, keepGoing;
|
||||
keepGoing = callback.call(context, this);
|
||||
for (i = 0, childCount = this.children.length; i < childCount; i++) {
|
||||
if (keepGoing === false) {
|
||||
return false;
|
||||
}
|
||||
keepGoing = depthFirstPreOrder.call(this.children[i], callback, context);
|
||||
}
|
||||
return keepGoing;
|
||||
};
|
||||
|
||||
walkStrategies.post = function depthFirstPostOrder(callback, context) {
|
||||
var i, childCount, keepGoing;
|
||||
for (i = 0, childCount = this.children.length; i < childCount; i++) {
|
||||
keepGoing = depthFirstPostOrder.call(this.children[i], callback, context);
|
||||
if (keepGoing === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
keepGoing = callback.call(context, this);
|
||||
return keepGoing;
|
||||
};
|
||||
|
||||
walkStrategies.breadth = function breadthFirst(callback, context) {
|
||||
var queue = [this];
|
||||
(function processQueue() {
|
||||
var i, childCount, node;
|
||||
if (queue.length === 0) {
|
||||
return;
|
||||
}
|
||||
node = queue.shift();
|
||||
for (i = 0, childCount = node.children.length; i < childCount; i++) {
|
||||
queue.push(node.children[i]);
|
||||
}
|
||||
if (callback.call(context, node) !== false) {
|
||||
processQueue();
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
Node.prototype.all = function () {
|
||||
var args, all = [];
|
||||
args = parseArgs.apply(this, arguments);
|
||||
args.fn = args.fn || k(true);
|
||||
walkStrategies[args.options.strategy].call(this, function (node) {
|
||||
if (args.fn.call(args.ctx, node)) {
|
||||
all.push(node);
|
||||
}
|
||||
}, args.ctx);
|
||||
return all;
|
||||
};
|
||||
|
||||
Node.prototype.first = function () {
|
||||
var args, first;
|
||||
args = parseArgs.apply(this, arguments);
|
||||
args.fn = args.fn || k(true);
|
||||
walkStrategies[args.options.strategy].call(this, function (node) {
|
||||
if (args.fn.call(args.ctx, node)) {
|
||||
first = node;
|
||||
return false;
|
||||
}
|
||||
}, args.ctx);
|
||||
return first;
|
||||
};
|
||||
|
||||
Node.prototype.drop = function () {
|
||||
var indexOfChild;
|
||||
if (!this.isRoot()) {
|
||||
indexOfChild = this.parent.children.indexOf(this);
|
||||
this.parent.children.splice(indexOfChild, 1);
|
||||
this.parent.model[this.config.childrenPropertyName].splice(indexOfChild, 1);
|
||||
this.parent = undefined;
|
||||
delete this.parent;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return TreeModel;
|
||||
})();
|
||||
|
|
@ -76,4 +76,45 @@ class CopyHelper {
|
|||
);
|
||||
}
|
||||
}
|
||||
export { EditorMessage, OutlineType, NoteTemplate, CopyHelper };
|
||||
|
||||
async function pick(
|
||||
title: string,
|
||||
mode: "open" | "save" | "folder",
|
||||
filters?: [string, string][],
|
||||
suggestion?: string
|
||||
): Promise<string> {
|
||||
const fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(
|
||||
Components.interfaces.nsIFilePicker
|
||||
);
|
||||
|
||||
if (suggestion) fp.defaultString = suggestion;
|
||||
|
||||
mode = {
|
||||
open: Components.interfaces.nsIFilePicker.modeOpen,
|
||||
save: Components.interfaces.nsIFilePicker.modeSave,
|
||||
folder: Components.interfaces.nsIFilePicker.modeGetFolder,
|
||||
}[mode];
|
||||
|
||||
fp.init(window, title, mode);
|
||||
|
||||
for (const [label, ext] of filters || []) {
|
||||
fp.appendFilter(label, ext);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return new Zotero.Promise((resolve) => {
|
||||
fp.open((userChoice) => {
|
||||
switch (userChoice) {
|
||||
case Components.interfaces.nsIFilePicker.returnOK:
|
||||
case Components.interfaces.nsIFilePicker.returnReplace:
|
||||
resolve(fp.file.path);
|
||||
break;
|
||||
|
||||
default: // aka returnCancel
|
||||
resolve("");
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
export { EditorMessage, OutlineType, NoteTemplate, CopyHelper, pick };
|
||||
1019
src/views.ts
1019
src/views.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,9 @@
|
|||
/*
|
||||
* This file contains the first-run wizard window code
|
||||
*/
|
||||
|
||||
import Knowledge4Zotero from "./addon";
|
||||
import { EditorMessage } from "./base";
|
||||
import { EditorMessage } from "./utils";
|
||||
import AddonBase from "./module";
|
||||
|
||||
class AddonWizard extends AddonBase {
|
||||
|
|
@ -272,7 +276,7 @@ class AddonWizard extends AddonBase {
|
|||
Zotero.locale === "zh-CN" ? this.templateCN : this.template
|
||||
);
|
||||
await this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("setMainKnowledge", {
|
||||
new EditorMessage("setMainNote", {
|
||||
params: { itemID: noteID, enableConfirm: false, enableOpen: true },
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { OutlineType } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class WorkspaceMenu extends AddonBase {
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public getWorkspaceMenuWindow(): Window {
|
||||
return this._Addon.WorkspaceWindow.workspaceTabId
|
||||
? this._Addon.WorkspaceWindow.workspaceTabId !== "WINDOW"
|
||||
? window
|
||||
: this._Addon.WorkspaceWindow.getWorkspaceWindow()
|
||||
: window;
|
||||
}
|
||||
|
||||
public updateViewMenu() {
|
||||
Zotero.debug(
|
||||
`updateViewMenu, ${this._Addon.WorkspaceOutline.currentOutline}`
|
||||
);
|
||||
const _mainWindow = this.getWorkspaceMenuWindow();
|
||||
const treeview = _mainWindow.document.getElementById("menu_treeview");
|
||||
this._Addon.WorkspaceOutline.currentOutline === OutlineType.treeView
|
||||
? treeview.setAttribute("checked", true as any)
|
||||
: treeview.removeAttribute("checked");
|
||||
const mindmap = _mainWindow.document.getElementById("menu_mindmap");
|
||||
this._Addon.WorkspaceOutline.currentOutline === OutlineType.mindMap
|
||||
? mindmap.setAttribute("checked", true as any)
|
||||
: mindmap.removeAttribute("checked");
|
||||
const bubblemap = _mainWindow.document.getElementById("menu_bubblemap");
|
||||
this._Addon.WorkspaceOutline.currentOutline === OutlineType.bubbleMap
|
||||
? bubblemap.setAttribute("checked", true as any)
|
||||
: bubblemap.removeAttribute("checked");
|
||||
|
||||
const noteFontSize = Zotero.Prefs.get("note.fontSize");
|
||||
for (let menuitem of this._Addon.WorkspaceWindow.workspaceWindow.document.querySelectorAll(
|
||||
`#note-font-size-menu menuitem`
|
||||
)) {
|
||||
if (parseInt(menuitem.getAttribute("label")) == noteFontSize) {
|
||||
menuitem.setAttribute("checked", true as any);
|
||||
} else {
|
||||
menuitem.removeAttribute("checked");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WorkspaceMenu;
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { OutlineType } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class WorkspaceOutline extends AddonBase {
|
||||
public currentOutline: OutlineType;
|
||||
public currentNodeID: number;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this.currentOutline = OutlineType.treeView;
|
||||
this.currentNodeID = -1;
|
||||
}
|
||||
|
||||
public switchView(newType: OutlineType = undefined) {
|
||||
if (!newType) {
|
||||
newType = this.currentOutline + 1;
|
||||
}
|
||||
if (newType > OutlineType.bubbleMap) {
|
||||
newType = OutlineType.treeView;
|
||||
}
|
||||
const mindmap =
|
||||
this._Addon.WorkspaceWindow.workspaceWindow.document.getElementById(
|
||||
"mindmap-container"
|
||||
);
|
||||
|
||||
const oldIframe =
|
||||
this._Addon.WorkspaceWindow.workspaceWindow.document.getElementById(
|
||||
"mindmapIframe"
|
||||
);
|
||||
if (oldIframe) {
|
||||
oldIframe.remove();
|
||||
}
|
||||
this.currentOutline = newType;
|
||||
const srcList = [
|
||||
"",
|
||||
"chrome://Knowledge4Zotero/content/treeView.html",
|
||||
"chrome://Knowledge4Zotero/content/mindMap.html",
|
||||
"chrome://Knowledge4Zotero/content/bubbleMap.html",
|
||||
];
|
||||
const iframe =
|
||||
this._Addon.WorkspaceWindow.workspaceWindow.document.createElement(
|
||||
"iframe"
|
||||
);
|
||||
iframe.setAttribute("id", "mindmapIframe");
|
||||
iframe.setAttribute("src", srcList[this.currentOutline]);
|
||||
mindmap.append(iframe);
|
||||
this.resizeOutline();
|
||||
this.updateOutline();
|
||||
// Clear stored node id
|
||||
this.currentNodeID = -1;
|
||||
this._Addon.WorkspaceMenu.updateViewMenu();
|
||||
}
|
||||
|
||||
public async updateOutline() {
|
||||
Zotero.debug("Knowledge4Zotero: updateMindMap");
|
||||
// await this._initIframe.promise;
|
||||
const _window = this._Addon.WorkspaceWindow.getWorkspaceWindow();
|
||||
if (!_window) {
|
||||
return;
|
||||
}
|
||||
const iframe = _window.document.getElementById(
|
||||
"mindmapIframe"
|
||||
) as HTMLIFrameElement;
|
||||
iframe.contentWindow.postMessage(
|
||||
{
|
||||
type: "setMindMapData",
|
||||
nodes: this._Addon.NoteUtils.getNoteTreeAsList(
|
||||
this._Addon.WorkspaceWindow.getWorkspaceNote(),
|
||||
true,
|
||||
false
|
||||
),
|
||||
},
|
||||
"*"
|
||||
);
|
||||
}
|
||||
|
||||
public resizeOutline() {
|
||||
const iframe =
|
||||
this._Addon.WorkspaceWindow.workspaceWindow.document.getElementById(
|
||||
"mindmapIframe"
|
||||
);
|
||||
const container =
|
||||
this._Addon.WorkspaceWindow.workspaceWindow.document.getElementById(
|
||||
"zotero-knowledge-outline"
|
||||
);
|
||||
if (iframe) {
|
||||
iframe.style.height = `${container.clientHeight - 60}px`;
|
||||
iframe.style.width = `${container.clientWidth - 10}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WorkspaceOutline;
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { EditorMessage, OutlineType } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class WorkspaceWindow extends AddonBase {
|
||||
private _initIframe: ZoteroPromise;
|
||||
public workspaceWindow: Window;
|
||||
public workspaceTabId: string;
|
||||
public workspaceNoteEditor: Zotero.EditorInstance | undefined;
|
||||
public previewItemID: number;
|
||||
private _firstInit: boolean;
|
||||
public _workspacePromise: ZoteroPromise;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this._initIframe = Zotero.Promise.defer();
|
||||
this.workspaceTabId = "";
|
||||
this._firstInit = true;
|
||||
}
|
||||
|
||||
public getWorkspaceWindow(): Window | undefined {
|
||||
if (this.workspaceWindow && !this.workspaceWindow.closed) {
|
||||
return this.workspaceWindow;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async openWorkspaceWindow(
|
||||
type: "window" | "tab" = "tab",
|
||||
reopen: boolean = false,
|
||||
select: boolean = true
|
||||
) {
|
||||
if (this.getWorkspaceWindow()) {
|
||||
if (!reopen) {
|
||||
Zotero.debug("openWorkspaceWindow: focus");
|
||||
if (this.workspaceTabId !== "WINDOW") {
|
||||
Zotero_Tabs.select(this.workspaceTabId);
|
||||
} else {
|
||||
(this.getWorkspaceWindow() as Window).focus();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
Zotero.debug("openWorkspaceWindow: reopen");
|
||||
this.closeWorkspaceWindow();
|
||||
}
|
||||
}
|
||||
this._workspacePromise = Zotero.Promise.defer();
|
||||
this._firstInit = true;
|
||||
if (type === "window") {
|
||||
Zotero.debug("openWorkspaceWindow: as window");
|
||||
this._initIframe = Zotero.Promise.defer();
|
||||
let win = window.open(
|
||||
"chrome://Knowledge4Zotero/content/workspace.xul",
|
||||
"_blank",
|
||||
"chrome,extrachrome,menubar,resizable,scrollbars,status,width=1000,height=600"
|
||||
);
|
||||
this.workspaceWindow = win as Window;
|
||||
this.workspaceTabId = "WINDOW";
|
||||
await this.waitWorkspaceReady();
|
||||
this.setWorkspaceNote("main");
|
||||
this._Addon.NoteUtils.currentLine[this.getWorkspaceNote().id] = -1;
|
||||
this.initKnowledgeWindow();
|
||||
this._Addon.WorkspaceOutline.switchView(OutlineType.treeView);
|
||||
this._Addon.WorkspaceOutline.updateOutline();
|
||||
this._Addon.ZoteroViews.updateAutoInsertAnnotationsMenu();
|
||||
} else {
|
||||
Zotero.debug("openWorkspaceWindow: as tab");
|
||||
this._initIframe = Zotero.Promise.defer();
|
||||
// Avoid sidebar show up
|
||||
Zotero_Tabs.jump(0);
|
||||
let { id, container } = Zotero_Tabs.add({
|
||||
type: "betternotes",
|
||||
title: Zotero.locale.includes("zh") ? "工作区" : "Workspace",
|
||||
index: 1,
|
||||
data: {},
|
||||
select: select,
|
||||
onClose: () => (this.workspaceTabId = ""),
|
||||
});
|
||||
this.workspaceTabId = id;
|
||||
const _iframe = window.document.createElement("browser");
|
||||
_iframe.setAttribute("class", "reader");
|
||||
_iframe.setAttribute("flex", "1");
|
||||
_iframe.setAttribute("type", "content");
|
||||
_iframe.setAttribute(
|
||||
"src",
|
||||
"chrome://Knowledge4Zotero/content/workspace.xul"
|
||||
);
|
||||
container.appendChild(_iframe);
|
||||
|
||||
// @ts-ignore
|
||||
this.workspaceWindow = _iframe.contentWindow;
|
||||
await this.waitWorkspaceReady();
|
||||
|
||||
this._Addon.ZoteroViews.hideMenuBar(this.workspaceWindow.document);
|
||||
|
||||
this._Addon.NoteUtils.currentLine[this.getWorkspaceNote().id] = -1;
|
||||
this.initKnowledgeWindow();
|
||||
this._Addon.WorkspaceOutline.switchView(OutlineType.treeView);
|
||||
this._Addon.WorkspaceOutline.updateOutline();
|
||||
}
|
||||
}
|
||||
|
||||
public closeWorkspaceWindow() {
|
||||
if (this.getWorkspaceWindow()) {
|
||||
if (this.workspaceTabId !== "WINDOW") {
|
||||
Zotero_Tabs.close(this.workspaceTabId);
|
||||
} else {
|
||||
(this.getWorkspaceWindow() as Window).close();
|
||||
}
|
||||
}
|
||||
this.workspaceTabId = "";
|
||||
}
|
||||
|
||||
public async waitWorkspaceReady() {
|
||||
let _window = this.getWorkspaceWindow() as Window;
|
||||
if (!_window) {
|
||||
return false;
|
||||
}
|
||||
let t = 0;
|
||||
await this._workspacePromise.promise;
|
||||
return true;
|
||||
}
|
||||
|
||||
public initKnowledgeWindow() {
|
||||
this.workspaceWindow.addEventListener(
|
||||
"message",
|
||||
(e) => this.messageHandler(e),
|
||||
false
|
||||
);
|
||||
this._Addon.WorkspaceOutline.currentOutline = OutlineType.treeView;
|
||||
this.workspaceWindow.document
|
||||
.getElementById("outline-switchview")
|
||||
.addEventListener("click", async (e) => {
|
||||
this._Addon.WorkspaceOutline.switchView();
|
||||
});
|
||||
this.workspaceWindow.addEventListener("resize", (e) =>
|
||||
this._Addon.WorkspaceOutline.resizeOutline()
|
||||
);
|
||||
this.workspaceWindow.document
|
||||
.getElementById("outline-splitter")
|
||||
.addEventListener("mouseup", async (e) => {
|
||||
this._Addon.WorkspaceOutline.resizeOutline();
|
||||
});
|
||||
this.workspaceWindow.addEventListener("close", (e) => {
|
||||
this.workspaceWindow = undefined;
|
||||
this.workspaceTabId = "";
|
||||
this._Addon.ZoteroViews.updateAutoInsertAnnotationsMenu();
|
||||
});
|
||||
}
|
||||
|
||||
private async messageHandler(e) {
|
||||
Zotero.debug(`Knowledge4Zotero: view message ${e.data.type}`);
|
||||
console.log(`Knowledge4Zotero: view message ${e.data.type}`);
|
||||
if (e.data.type === "ready") {
|
||||
this._initIframe.resolve();
|
||||
} else if (e.data.type === "getMindMapData") {
|
||||
this._Addon.WorkspaceOutline.updateOutline();
|
||||
} else if (e.data.type === "jumpNode") {
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("jumpNode", {
|
||||
params: e.data,
|
||||
})
|
||||
);
|
||||
} else if (e.data.type === "jumpNote") {
|
||||
Zotero.debug(e.data);
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("onNoteLink", {
|
||||
params: await this._Addon.NoteUtils.getNoteFromLink(e.data.link),
|
||||
})
|
||||
);
|
||||
} else if (e.data.type === "moveNode") {
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("moveNode", {
|
||||
params: e.data,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async getWorkspaceEditor(type: "main" | "preview" = "main") {
|
||||
let _window = this._Addon.WorkspaceWindow.getWorkspaceWindow() as Window;
|
||||
if (!_window) {
|
||||
return;
|
||||
}
|
||||
await this._Addon.WorkspaceWindow.waitWorkspaceReady();
|
||||
return _window.document.getElementById(`zotero-note-editor-${type}`);
|
||||
}
|
||||
|
||||
getWorkspaceNote(): Zotero.Item {
|
||||
return Zotero.Items.get(
|
||||
Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID") as number
|
||||
) as Zotero.Item;
|
||||
}
|
||||
|
||||
async getWorkspaceEditorInstance(
|
||||
type: "main" | "preview" = "main",
|
||||
wait: boolean = true
|
||||
): Promise<Zotero.EditorInstance | undefined> {
|
||||
let noteEditor = (await this.getWorkspaceEditor(type)) as any;
|
||||
if (!noteEditor) {
|
||||
return;
|
||||
}
|
||||
let t = 0;
|
||||
while (wait && !noteEditor.getCurrentInstance() && t < 500) {
|
||||
t += 1;
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
this.workspaceNoteEditor =
|
||||
noteEditor.getCurrentInstance() as Zotero.EditorInstance;
|
||||
return this.workspaceNoteEditor;
|
||||
}
|
||||
|
||||
getEditorInstance(note: Zotero.Item) {
|
||||
// If there are multiple editors of main note available, we use the workspace editor.
|
||||
if (
|
||||
note.id === this.getWorkspaceNote().id &&
|
||||
this.getWorkspaceWindow() &&
|
||||
this.workspaceNoteEditor &&
|
||||
!Components.utils.isDeadWrapper(this.workspaceNoteEditor._iframeWindow)
|
||||
) {
|
||||
return this.workspaceNoteEditor;
|
||||
}
|
||||
const editor = (
|
||||
Zotero.Notes._editorInstances as Zotero.EditorInstance[]
|
||||
).find(
|
||||
(e) =>
|
||||
e._item.id === note.id &&
|
||||
!Components.utils.isDeadWrapper(e._iframeWindow)
|
||||
);
|
||||
if (note.id === this.getWorkspaceNote().id) {
|
||||
this.workspaceNoteEditor = editor;
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
|
||||
async setWorkspaceNote(
|
||||
type: "main" | "preview" = "main",
|
||||
note: Zotero.Item | undefined = undefined,
|
||||
showPopup: boolean = true
|
||||
) {
|
||||
let _window = this.getWorkspaceWindow() as Window;
|
||||
note = note || this.getWorkspaceNote();
|
||||
if (!_window) {
|
||||
return;
|
||||
}
|
||||
if (type === "preview") {
|
||||
const splitter = _window.document.getElementById("preview-splitter");
|
||||
splitter && splitter.setAttribute("state", "open");
|
||||
this.previewItemID = note.id;
|
||||
} else {
|
||||
// Set line to default
|
||||
this._Addon.NoteUtils.currentLine[note.id] = -1;
|
||||
if (Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID") !== note.id) {
|
||||
Zotero.Prefs.set("Knowledge4Zotero.mainKnowledgeID", note.id);
|
||||
}
|
||||
}
|
||||
await this.waitWorkspaceReady();
|
||||
let noteEditor: any = await this.getWorkspaceEditor(type);
|
||||
if (!noteEditor._initialized) {
|
||||
noteEditor._iframe.contentWindow.addEventListener(
|
||||
"drop",
|
||||
(event) => {
|
||||
noteEditor._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"),
|
||||
},
|
||||
noteEditor._iframe.contentWindow
|
||||
);
|
||||
},
|
||||
true
|
||||
);
|
||||
noteEditor._initialized = true;
|
||||
}
|
||||
noteEditor.mode = "edit";
|
||||
noteEditor.viewMode = "library";
|
||||
noteEditor.parent = null;
|
||||
noteEditor.item = note;
|
||||
if (!noteEditor || !noteEditor.getCurrentInstance()) {
|
||||
await noteEditor.initEditor();
|
||||
}
|
||||
|
||||
await noteEditor._editorInstance._initPromise;
|
||||
const position = (
|
||||
this._Addon.EditorViews.getEditorElement(
|
||||
noteEditor._editorInstance._iframeWindow.document
|
||||
).parentNode as HTMLElement
|
||||
).scrollTop;
|
||||
// Due to unknown reasons, only after the second init the editor will be correctly loaded.
|
||||
// Thus we must init it twice
|
||||
if (this._firstInit) {
|
||||
this._firstInit = false;
|
||||
await noteEditor.initEditor();
|
||||
}
|
||||
this._Addon.EditorViews.scrollToPosition(
|
||||
noteEditor._editorInstance,
|
||||
position
|
||||
);
|
||||
if (type === "main") {
|
||||
this._Addon.WorkspaceOutline.updateOutline();
|
||||
this._Addon.ZoteroViews.updateWordCount();
|
||||
const recentMainNotes = Zotero.Items.get(
|
||||
new Array(
|
||||
...new Set(
|
||||
(
|
||||
Zotero.Prefs.get("Knowledge4Zotero.recentMainNoteIds") as string
|
||||
).split(",")
|
||||
)
|
||||
)
|
||||
) as Zotero.Item[];
|
||||
recentMainNotes.splice(0, 0, note);
|
||||
Zotero.Prefs.set(
|
||||
"Knowledge4Zotero.recentMainNoteIds",
|
||||
new Array(...new Set(recentMainNotes.map((item) => String(item.id))))
|
||||
.slice(0, 10)
|
||||
.filter((id) => id)
|
||||
.join(",")
|
||||
);
|
||||
if (showPopup) {
|
||||
this._Addon.ZoteroViews.showProgressWindow(
|
||||
"Better Notes",
|
||||
`Set main Note to: ${note.getNoteTitle()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WorkspaceWindow;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,333 @@
|
|||
import Knowledge4Zotero from "../addon";
|
||||
import { EditorMessage } from "../utils";
|
||||
import AddonBase from "../module";
|
||||
|
||||
class ZoteroViews extends AddonBase {
|
||||
progressWindowIcon: object;
|
||||
icons: object;
|
||||
|
||||
constructor(parent: Knowledge4Zotero) {
|
||||
super(parent);
|
||||
this.progressWindowIcon = {
|
||||
success: "chrome://zotero/skin/tick.png",
|
||||
fail: "chrome://zotero/skin/cross.png",
|
||||
default: "chrome://Knowledge4Zotero/skin/favicon.png",
|
||||
};
|
||||
this.icons = {
|
||||
tabIcon: `<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="icon icon-bg"><path d="M791.30324 369.7c-5 5-6.2 12.7-2.8 18.9 17.5 31.9 27.4 68.5 27.4 107.4 0 56.2-20.7 107.6-54.9 147-4.5 5.1-5.1 12.6-1.8 18.4l39.2 67.9c3.3 5.7 9.6 8.7 16.1 7.8 6-0.8 12.1-1.2 18.3-1.2 70.1 0.5 128 59.7 127.1 129.7-0.9 69.7-57.4 125.9-127.1 126.4-70.9 0.5-128.9-57.1-128.9-128 0-38.1 16.7-72.3 43.1-95.8l-37-64c-4.2-7.3-13.3-10-20.9-6.4-29.3 14.2-62.3 22.2-97.2 22.2-26.7 0-52.3-4.7-76-13.2-7.3-2.6-15.4 0.3-19.3 7l-24.9 43.1c-3.1 5.4-2.8 12.1 0.8 17.2 15 21.2 23.7 47.1 23.5 75.1-0.7 69.5-57.5 126.2-127 126.8-71.6 0.6-129.8-57.7-129.1-129.4 0.8-69.7 58-126.5 127.8-126.6 12 0 23.7 1.6 34.8 4.7 7 2 14.5-1.1 18.2-7.4l21.7-37.6c3.7-6.4 2.5-14.6-2.9-19.6-33.6-31.2-57.5-72.6-67-119.2-1.5-7.5-8-12.9-15.7-12.9h-92c-6.9 0-13.1 4.5-15.2 11.1C232.80324 590.2 184.70324 627 128.00324 627 57.00324 627-0.49676 569.2 0.00324 498.1 0.40324 427.5 58.60324 370.3 129.20324 371c54.2 0.5 100.4 34.8 118.5 82.8C250.00324 460 256.00324 464 262.60324 464h94.1c7.6 0 14.2-5.3 15.7-12.7 11-54.2 41.5-101.3 84-133.6 6.4-4.9 8.2-13.8 4.2-20.8l-2.2-3.8c-3.5-6-10.3-9-17.1-7.7-8.8 1.8-18 2.7-27.4 2.5-69.5-1-126.9-60.1-126-129.6 0.9-70.3 58.4-126.9 129-126.3 69.3 0.6 126 57 127 126.2 0.4 31.6-10.6 60.7-29.3 83.2-4.3 5.2-5 12.5-1.6 18.3l6.6 11.4c3.6 6.2 10.8 9.3 17.7 7.5 17.5-4.4 35.8-6.7 54.6-6.7 52.3 0 100.4 17.9 138.6 48 6.4 5 15.5 4.5 21.2-1.2l24.2-24.2c4.7-4.7 6-11.8 3.3-17.8-7.3-16.1-11.3-34-11.3-52.8 0-70.7 57.3-128 128-128 70.6 0 128 57.4 128 128 0 70.7-57.3 128-128 128-20.7 0-40.2-4.9-57.5-13.6-6.2-3.1-13.7-2-18.7 2.9l-28.4 28.5z" fill="#f2ac46"/></svg>`,
|
||||
openWorkspaceCollectionView: `<svg t="1651317033804" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2432" width="100%" height="100%"><path d="M874.9 459.4c-18.8 0-34 15.2-34 34v355.7c0 18.6-15.5 33.7-34.5 33.7H181.5c-19 0-34.5-15.1-34.5-33.7V232.3c0-18.6 15.5-33.7 34.5-33.7H541c18.8 0 34-15.2 34-34s-15.2-34-34-34H181.5C125 130.6 79 176.2 79 232.3v616.8c0 56 46 101.7 102.5 101.7h624.9c56.5 0 102.5-45.6 102.5-101.7V493.4c0-18.8-15.2-34-34-34z" fill="currentColor" p-id="2433"></path><path d="M885.5 82.7H657.1c-18.8 0-34 15.2-34 34s15.2 34 34 34h169.7L358.5 619.1c-13.3 13.3-13.3 34.8 0 48.1 6.6 6.6 15.3 10 24 10s17.4-3.3 24-10l470-470v169.7c0 18.8 15.2 34 34 34s34-15.2 34-34V141.5c0.1-32.4-26.4-58.8-59-58.8z" fill="currentColor" p-id="2434"></path></svg>`,
|
||||
};
|
||||
}
|
||||
|
||||
public hideMenuBar(_document: Document) {
|
||||
_document.getElementById("better-notes-menu").hidden = true;
|
||||
}
|
||||
|
||||
public keppDefaultMenuOrder() {
|
||||
const fileMenu = document.querySelector("#menu_FilePopup");
|
||||
const editMenu = document.querySelector("#menu_EditPopup");
|
||||
const exit = fileMenu.querySelector("#menu_FileQuitItem");
|
||||
// exit.remove();
|
||||
const prefs = editMenu.querySelector("#menu_preferences");
|
||||
// prefs.remove();
|
||||
if (exit) {
|
||||
for (const ele of fileMenu.querySelectorAll(".menu-betternotes")) {
|
||||
exit.before(ele);
|
||||
}
|
||||
}
|
||||
if (prefs) {
|
||||
for (const ele of editMenu.querySelectorAll(".menu-betternotes")) {
|
||||
prefs.before(ele);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public switchRealMenuBar(hidden: boolean) {
|
||||
// We only handle hide. The show will be handled by the ZoteroStandalone.switchMenuType
|
||||
document
|
||||
.querySelectorAll(".menu-type-betternotes")
|
||||
.forEach((el) => ((el as HTMLElement).hidden = hidden));
|
||||
|
||||
// Disable Zotero pdf export
|
||||
(document.getElementById("menu_export_files") as XUL.Element).disabled =
|
||||
!hidden;
|
||||
}
|
||||
|
||||
public switchKey(disabled: boolean) {
|
||||
document
|
||||
.querySelectorAll(".key-type-betternotes")
|
||||
.forEach((el) => (el as XUL.Element).setAttribute("disabled", disabled));
|
||||
}
|
||||
|
||||
public addNewMainNoteButton() {
|
||||
// Top toolbar button
|
||||
let addNoteItem = document
|
||||
.getElementById("zotero-tb-note-add")
|
||||
.getElementsByTagName("menuitem")[1];
|
||||
let button = document.createElement("menuitem");
|
||||
button.setAttribute("id", "zotero-tb-knowledge-openwindow");
|
||||
button.setAttribute("label", "New Main Note");
|
||||
button.addEventListener("click", (e) => {
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("createWorkspace", {})
|
||||
);
|
||||
});
|
||||
button.setAttribute("class", "menuitem-iconic");
|
||||
button.setAttribute(
|
||||
"style",
|
||||
"list-style-image: url('chrome://Knowledge4Zotero/skin/favicon.png');"
|
||||
);
|
||||
addNoteItem.after(button);
|
||||
}
|
||||
|
||||
public addOpenWorkspaceButton() {
|
||||
// Left collection tree view button
|
||||
const treeRow = document.createElement("html:div");
|
||||
treeRow.setAttribute("class", "row");
|
||||
treeRow.setAttribute(
|
||||
"style",
|
||||
"height: 22px; margin: 0 0 0 0; padding: 0 6px 0 6px;"
|
||||
);
|
||||
const span1 = document.createElement("span");
|
||||
span1.setAttribute("class", "cell label primary");
|
||||
const span2 = document.createElement("span");
|
||||
span2.setAttribute("class", "icon icon-twisty twisty open");
|
||||
span2.innerHTML = this.icons["openWorkspaceCollectionView"];
|
||||
const span3 = document.createElement("span");
|
||||
span3.setAttribute("class", "icon icon-bg cell-icon");
|
||||
span3.setAttribute(
|
||||
"style",
|
||||
"background-image:url(chrome://Knowledge4Zotero/skin/favicon.png)"
|
||||
);
|
||||
const span4 = document.createElement("span");
|
||||
span4.setAttribute("class", "cell-text");
|
||||
span4.setAttribute("style", "margin-left: 6px;");
|
||||
span4.innerHTML = Zotero.locale.includes("zh")
|
||||
? "打开工作区"
|
||||
: "Open Workspace";
|
||||
span1.append(span2, span3, span4);
|
||||
treeRow.append(span1);
|
||||
treeRow.addEventListener("click", (e) => {
|
||||
this._Addon.events.onEditorEvent(
|
||||
new EditorMessage("openWorkspace", { event: e })
|
||||
);
|
||||
});
|
||||
treeRow.addEventListener("mouseover", (e: XUL.XULEvent) => {
|
||||
treeRow.setAttribute(
|
||||
"style",
|
||||
"height: 22px; margin: 0 0 0 0; padding: 0 6px 0 6px; background-color: grey;"
|
||||
);
|
||||
});
|
||||
treeRow.addEventListener("mouseleave", (e: XUL.XULEvent) => {
|
||||
treeRow.setAttribute(
|
||||
"style",
|
||||
"height: 22px; margin: 0 0 0 0; padding: 0 6px 0 6px;"
|
||||
);
|
||||
});
|
||||
treeRow.addEventListener("mousedown", (e: XUL.XULEvent) => {
|
||||
treeRow.setAttribute(
|
||||
"style",
|
||||
"height: 22px; margin: 0 0 0 0; padding: 0 6px 0 6px; color: #FFFFFF;"
|
||||
);
|
||||
});
|
||||
treeRow.addEventListener("mouseup", (e: XUL.XULEvent) => {
|
||||
treeRow.setAttribute(
|
||||
"style",
|
||||
"height: 22px; margin: 0 0 0 0; padding: 0 6px 0 6px;"
|
||||
);
|
||||
});
|
||||
document
|
||||
.getElementById("zotero-collections-tree-container")
|
||||
.children[0].before(treeRow);
|
||||
}
|
||||
|
||||
public updateTemplateMenu(type: "Note" | "Item" | "Text") {
|
||||
const _window = this._Addon.WorkspaceMenu.getWorkspaceMenuWindow();
|
||||
|
||||
// If tab is open but not selected, we use copy mode
|
||||
const copyMode =
|
||||
Boolean(
|
||||
this._Addon.WorkspaceWindow.workspaceTabId &&
|
||||
this._Addon.WorkspaceWindow.workspaceTabId !== "WINDOW" &&
|
||||
Zotero_Tabs.selectedID !== this._Addon.WorkspaceWindow.workspaceTabId
|
||||
) || !this._Addon.WorkspaceWindow.workspaceTabId;
|
||||
Zotero.debug(`updateTemplateMenu`);
|
||||
let templates = this._Addon.TemplateController.getTemplateKeys()
|
||||
.filter((e) => e.name.indexOf(type) !== -1)
|
||||
.filter(
|
||||
(e) =>
|
||||
!this._Addon.TemplateController._systemTemplateNames.includes(e.name)
|
||||
);
|
||||
const popup = _window.document.getElementById(
|
||||
`menu_insert${type}TemplatePopup`
|
||||
);
|
||||
popup.innerHTML = "";
|
||||
if (templates.length === 0) {
|
||||
templates = [
|
||||
{
|
||||
name: "No Template",
|
||||
text: "",
|
||||
disabled: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
for (const template of templates) {
|
||||
const menuitem = _window.document.createElement("menuitem");
|
||||
menuitem.setAttribute("id", template.name);
|
||||
menuitem.setAttribute("label", template.name);
|
||||
menuitem.setAttribute(
|
||||
"oncommand",
|
||||
`
|
||||
Zotero.Knowledge4Zotero.events.onEditorEvent({
|
||||
type: "insert${type}UsingTemplate",
|
||||
content: {
|
||||
params: { templateName: "${template.name}", copy: ${copyMode} },
|
||||
},
|
||||
});`
|
||||
);
|
||||
|
||||
if (template.disabled) {
|
||||
menuitem.setAttribute("disabled", true as any);
|
||||
}
|
||||
popup.append(menuitem);
|
||||
}
|
||||
}
|
||||
|
||||
public updateCitationStyleMenu() {
|
||||
const _window = this._Addon.WorkspaceMenu.getWorkspaceMenuWindow();
|
||||
Zotero.debug(`updateCitationStyleMenu`);
|
||||
|
||||
const popup = _window.document.getElementById("menu_citeSettingPopup");
|
||||
popup.innerHTML = "";
|
||||
|
||||
let format = this._Addon.TemplateController.getCitationStyle();
|
||||
|
||||
// add styles to list
|
||||
const styles = Zotero.Styles.getVisible();
|
||||
styles.forEach(function (style) {
|
||||
const val = JSON.stringify({
|
||||
mode: "bibliography",
|
||||
contentType: "html",
|
||||
id: style.styleID,
|
||||
locale: "",
|
||||
});
|
||||
const itemNode: XUL.Element = document.createElement("menuitem");
|
||||
itemNode.setAttribute("value", val);
|
||||
itemNode.setAttribute("label", style.title);
|
||||
itemNode.setAttribute("type", "checkbox");
|
||||
itemNode.setAttribute(
|
||||
"oncommand",
|
||||
"Zotero.Prefs.set('Knowledge4Zotero.citeFormat', event.target.value)"
|
||||
);
|
||||
popup.appendChild(itemNode);
|
||||
|
||||
if (format.id == style.styleID) {
|
||||
itemNode.setAttribute("checked", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public updateOCRStyleMenu() {
|
||||
Zotero.debug(`updateOCRStyleMenu`);
|
||||
const popup = document.getElementById("menu_ocrsettingpopup");
|
||||
Array.prototype.forEach.call(popup.children, (e) =>
|
||||
e.setAttribute("checked", false)
|
||||
);
|
||||
let engine = Zotero.Prefs.get("Knowledge4Zotero.OCREngine");
|
||||
if (!engine) {
|
||||
engine = "bing";
|
||||
Zotero.Prefs.set("Knowledge4Zotero.OCREngine", engine);
|
||||
}
|
||||
(
|
||||
document.getElementById(`menu_ocr_${engine}_betternotes`) as XUL.Menuitem
|
||||
).setAttribute("checked", true);
|
||||
}
|
||||
|
||||
public updateWordCount() {
|
||||
const _window = this._Addon.WorkspaceMenu.getWorkspaceMenuWindow();
|
||||
if (!_window) {
|
||||
return;
|
||||
}
|
||||
Zotero.debug("updateWordCount");
|
||||
|
||||
const menuitem = _window.document.getElementById(
|
||||
"menu_wordcount_betternotes"
|
||||
);
|
||||
function fnGetCpmisWords(str) {
|
||||
let sLen = 0;
|
||||
try {
|
||||
// replace break lines
|
||||
str = str.replace(/(\r\n+|\s+| +)/g, "龘");
|
||||
// letter, numbers to 'm' letter
|
||||
str = str.replace(/[\x00-\xff]/g, "m");
|
||||
// make neighbor 'm' to be one letter
|
||||
str = str.replace(/m+/g, "*");
|
||||
// remove white space
|
||||
str = str.replace(/龘+/g, "");
|
||||
sLen = str.length;
|
||||
} catch (e) {}
|
||||
return sLen;
|
||||
}
|
||||
menuitem.setAttribute(
|
||||
"label",
|
||||
`Word Count: ${fnGetCpmisWords(
|
||||
this._Addon.NoteParse.parseNoteHTML(
|
||||
this._Addon.WorkspaceWindow.getWorkspaceNote()
|
||||
).innerText
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
public updateAutoInsertAnnotationsMenu() {
|
||||
const _window = this._Addon.WorkspaceMenu.getWorkspaceMenuWindow();
|
||||
|
||||
Zotero.debug("updateAutoInsertAnnotationsMenu");
|
||||
|
||||
let autoAnnotation = Zotero.Prefs.get("Knowledge4Zotero.autoAnnotation");
|
||||
if (typeof autoAnnotation === "undefined") {
|
||||
autoAnnotation = false;
|
||||
Zotero.Prefs.set("Knowledge4Zotero.autoAnnotation", autoAnnotation);
|
||||
}
|
||||
|
||||
const menuitem: XUL.Element = _window.document.getElementById(
|
||||
"menu_autoannotation_betternotes"
|
||||
);
|
||||
if (autoAnnotation) {
|
||||
menuitem.setAttribute("checked", true);
|
||||
} else {
|
||||
menuitem.removeAttribute("checked");
|
||||
}
|
||||
|
||||
// Hide main window menu if the standalone window is already opened
|
||||
window.document.getElementById("menu_autoannotation_betternotes").hidden =
|
||||
_window !== window;
|
||||
}
|
||||
|
||||
public showProgressWindow(
|
||||
header: string,
|
||||
context: string,
|
||||
type: "default" | "success" | "fail" = "default",
|
||||
t: number = 5000
|
||||
) {
|
||||
let progressWindow = new Zotero.ProgressWindow({ closeOnClick: true });
|
||||
progressWindow.changeHeadline(header);
|
||||
progressWindow.progress = new progressWindow.ItemProgress(
|
||||
this.progressWindowIcon[type],
|
||||
context
|
||||
);
|
||||
progressWindow.show();
|
||||
if (t > 0) {
|
||||
progressWindow.startCloseTimer(t);
|
||||
}
|
||||
return progressWindow;
|
||||
}
|
||||
|
||||
public changeProgressWindowDescription(progressWindow: any, context: string) {
|
||||
if (!progressWindow || progressWindow.closed) {
|
||||
return;
|
||||
}
|
||||
progressWindow.progress._itemText.innerHTML = context;
|
||||
}
|
||||
}
|
||||
|
||||
export default ZoteroViews;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
declare interface ZoteroPromise {
|
||||
promise: Promise<void>;
|
||||
resolve: () => void;
|
||||
}
|
||||
Loading…
Reference in New Issue