mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	
		
			
	
	
		
			257 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			257 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import treeService from "../../services/tree.js"; | ||
|  | import utils from "../../services/utils.js"; | ||
|  | import ws from "../../services/ws.js"; | ||
|  | import toastService from "../../services/toast.js"; | ||
|  | import froca from "../../services/froca.js"; | ||
|  | import openService from "../../services/open.js"; | ||
|  | import BasicWidget from "../basic_widget.js"; | ||
|  | 
 | ||
|  | const TPL = `
 | ||
|  | <div class="export-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | ||
|  |     <style> | ||
|  |     .export-form .form-check { | ||
|  |         padding-top: 10px; | ||
|  |         padding-bottom: 10px; | ||
|  |     } | ||
|  |      | ||
|  |     .export-form .format-choice { | ||
|  |         padding-left: 40px; | ||
|  |         display: none; | ||
|  |     } | ||
|  |      | ||
|  |     .export-form .opml-versions { | ||
|  |         padding-left: 60px; | ||
|  |         display: none; | ||
|  |     } | ||
|  |      | ||
|  |     .export-form .form-check-label { | ||
|  |         padding: 2px; | ||
|  |     } | ||
|  |     </style> | ||
|  | 
 | ||
|  |     <div class="modal-dialog modal-lg" role="document"> | ||
|  |         <div class="modal-content"> | ||
|  |             <div class="modal-header"> | ||
|  |                 <h5 class="modal-title">Export note "<span class="export-note-title"></span>"</h5> | ||
|  |                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||
|  |                     <span aria-hidden="true">×</span> | ||
|  |                 </button> | ||
|  |             </div> | ||
|  |             <form class="export-form"> | ||
|  |                 <div class="modal-body"> | ||
|  |                     <div class="form-check"> | ||
|  |                         <label class="form-check-label"> | ||
|  |                             <input class="export-type-subtree form-check-input" type="radio" name="export-type" value="subtree"> | ||
|  |                             this note and all of its descendants | ||
|  |                         </label> | ||
|  |                     </div> | ||
|  | 
 | ||
|  |                     <div class="export-subtree-formats format-choice"> | ||
|  |                         <div class="form-check"> | ||
|  |                             <label class="form-check-label"> | ||
|  |                                 <input class="form-check-input" type="radio" name="export-subtree-format" value="html"> | ||
|  |                                 HTML in ZIP archive - this is recommended since this preserves all the formatting. | ||
|  |                             </label> | ||
|  |                         </div> | ||
|  | 
 | ||
|  |                         <div class="form-check"> | ||
|  |                             <label class="form-check-label"> | ||
|  |                                 <input class="form-check-input" type="radio" name="export-subtree-format" value="markdown"> | ||
|  |                                 Markdown - this preserves most of the formatting. | ||
|  |                             </label> | ||
|  |                         </div> | ||
|  | 
 | ||
|  |                         <div class="form-check"> | ||
|  |                             <label class="form-check-label"> | ||
|  |                                 <input class="form-check-input" type="radio" name="export-subtree-format" value="opml"> | ||
|  |                                 OPML - outliner interchange format for text only. Formatting, images and files are not included. | ||
|  |                             </label> | ||
|  |                         </div> | ||
|  | 
 | ||
|  |                         <div class="opml-versions"> | ||
|  |                             <div class="form-check"> | ||
|  |                                 <label class="form-check-label"> | ||
|  |                                     <input class="form-check-input" type="radio" name="opml-version" value="1.0"> | ||
|  |                                     OPML v1.0 - plain text only | ||
|  |                                 </label> | ||
|  |                             </div> | ||
|  | 
 | ||
|  |                             <div class="form-check"> | ||
|  |                                 <label class="form-check-label"> | ||
|  |                                     <input class="form-check-input" type="radio" name="opml-version" value="2.0"> | ||
|  |                                     OMPL v2.0 - allows also HTML | ||
|  |                                 </label> | ||
|  |                             </div> | ||
|  |                         </div> | ||
|  |                     </div> | ||
|  | 
 | ||
|  |                     <div class="form-check"> | ||
|  |                         <label class="form-check-label"> | ||
|  |                             <input class="form-check-input" type="radio" name="export-type" value="single"> | ||
|  |                             only this note without its descendants | ||
|  |                         </label> | ||
|  |                     </div> | ||
|  | 
 | ||
|  |                     <div class="export-single-formats format-choice"> | ||
|  |                         <div class="form-check"> | ||
|  |                             <label class="form-check-label"> | ||
|  |                                 <input class="form-check-input" type="radio" name="export-single-format" value="html"> | ||
|  |                                 HTML - this is recommended since this preserves all the formatting. | ||
|  |                             </label> | ||
|  |                         </div> | ||
|  | 
 | ||
|  |                         <div class="form-check"> | ||
|  |                             <label class="form-check-label"> | ||
|  |                                 <input class="form-check-input" type="radio" name="export-single-format" value="markdown">                             | ||
|  |                                 Markdown - this preserves most of the formatting. | ||
|  |                             </label> | ||
|  |                         </div> | ||
|  |                     </div> | ||
|  |                 </div> | ||
|  |                 <div class="modal-footer"> | ||
|  |                     <button class="export-button btn btn-primary">Export</button> | ||
|  |                 </div> | ||
|  |             </form> | ||
|  |         </div> | ||
|  |     </div> | ||
|  | </div>`; | ||
|  | 
 | ||
|  | export default class ExportDialog extends BasicWidget { | ||
|  |     constructor() { | ||
|  |         super(); | ||
|  | 
 | ||
|  |         this.taskId = ''; | ||
|  |         this.branchId = null; | ||
|  |     } | ||
|  | 
 | ||
|  |     doRender() { | ||
|  |         this.$widget = $(TPL); | ||
|  |         this.$form = this.$widget.find(".export-form"); | ||
|  |         this.$noteTitle = this.$widget.find(".export-note-title"); | ||
|  |         this.$subtreeFormats = this.$widget.find(".export-subtree-formats"); | ||
|  |         this.$singleFormats = this.$widget.find(".export-single-formats"); | ||
|  |         this.$subtreeType = this.$widget.find(".export-type-subtree"); | ||
|  |         this.$singleType = this.$widget.find(".export-type-single"); | ||
|  |         this.$exportButton = this.$widget.find(".export-button"); | ||
|  |         this.$opmlVersions = this.$widget.find(".opml-versions"); | ||
|  | 
 | ||
|  |         this.$form.on('submit', () => { | ||
|  |             this.$widget.modal('hide'); | ||
|  | 
 | ||
|  |             const exportType = this.$widget.find("input[name='export-type']:checked").val(); | ||
|  | 
 | ||
|  |             if (!exportType) { | ||
|  |                 // this shouldn't happen as we always choose default export type
 | ||
|  |                 alert("Choose export type first please"); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             const exportFormat = exportType === 'subtree' | ||
|  |                 ? this.$widget.find("input[name=export-subtree-format]:checked").val() | ||
|  |                 : this.$widget.find("input[name=export-single-format]:checked").val(); | ||
|  | 
 | ||
|  |             const exportVersion = exportFormat === 'opml' | ||
|  |                 ? this.$widget.find("input[name='opml-version']:checked").val() | ||
|  |                 : "1.0"; | ||
|  | 
 | ||
|  |             this.exportBranch(this.branchId, exportType, exportFormat, exportVersion); | ||
|  | 
 | ||
|  |             return false; | ||
|  |         }); | ||
|  | 
 | ||
|  |         this.$widget.find('input[name=export-type]').on('change', e => { | ||
|  |             if (e.currentTarget.value === 'subtree') { | ||
|  |                 if (this.$widget.find("input[name=export-subtree-format]:checked").length === 0) { | ||
|  |                     this.$widget.find("input[name=export-subtree-format]:first").prop("checked", true); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 this.$subtreeFormats.slideDown(); | ||
|  |                 this.$singleFormats.slideUp(); | ||
|  |             } | ||
|  |             else { | ||
|  |                 if (this.$widget.find("input[name=export-single-format]:checked").length === 0) { | ||
|  |                     this.$widget.find("input[name=export-single-format]:first").prop("checked", true); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 this.$subtreeFormats.slideUp(); | ||
|  |                 this.$singleFormats.slideDown(); | ||
|  |             } | ||
|  |         }); | ||
|  | 
 | ||
|  |         this.$widget.find('input[name=export-subtree-format]').on('change', e => { | ||
|  |             if (e.currentTarget.value === 'opml') { | ||
|  |                 this.$opmlVersions.slideDown(); | ||
|  |             } | ||
|  |             else { | ||
|  |                 this.$opmlVersions.slideUp(); | ||
|  |             } | ||
|  |         }); | ||
|  |     } | ||
|  | 
 | ||
|  |     async showExportDialogEvent({notePath, defaultType}) { | ||
|  |         // each opening of the dialog resets the taskId, so we don't associate it with previous exports anymore
 | ||
|  |         this.taskId = ''; | ||
|  |         this.$exportButton.removeAttr("disabled"); | ||
|  | 
 | ||
|  |         if (defaultType === 'subtree') { | ||
|  |             this.$subtreeType.prop("checked", true).trigger('change'); | ||
|  | 
 | ||
|  |             // to show/hide OPML versions
 | ||
|  |             this.$widget.find("input[name=export-subtree-format]:checked").trigger('change'); | ||
|  |         } | ||
|  |         else if (defaultType === 'single') { | ||
|  |             this.$singleType.prop("checked", true).trigger('change'); | ||
|  |         } | ||
|  |         else { | ||
|  |             throw new Error("Unrecognized type " + defaultType); | ||
|  |         } | ||
|  | 
 | ||
|  |         this.$widget.find(".opml-v2").prop("checked", true); // setting default
 | ||
|  | 
 | ||
|  |         utils.openDialog(this.$widget); | ||
|  | 
 | ||
|  |         const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath); | ||
|  | 
 | ||
|  |         this.branchId = await froca.getBranchId(parentNoteId, noteId); | ||
|  | 
 | ||
|  |         const noteTitle = await treeService.getNoteTitle(noteId); | ||
|  | 
 | ||
|  |         this.$noteTitle.html(noteTitle); | ||
|  |     } | ||
|  | 
 | ||
|  |     exportBranch(branchId, type, format, version) { | ||
|  |         this.taskId = utils.randomString(10); | ||
|  | 
 | ||
|  |         const url = openService.getUrlForDownload(`api/notes/${branchId}/export/${type}/${format}/${version}/${this.taskId}`); | ||
|  | 
 | ||
|  |         openService.download(url); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | ws.subscribeToMessages(async message => { | ||
|  |     const makeToast = (id, message) => ({ | ||
|  |         id: id, | ||
|  |         title: "Export status", | ||
|  |         message: message, | ||
|  |         icon: "arrow-square-up-right" | ||
|  |     }); | ||
|  | 
 | ||
|  |     if (message.taskType !== 'export') { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (message.type === 'taskError') { | ||
|  |         toastService.closePersistent(message.taskId); | ||
|  |         toastService.showError(message.message); | ||
|  |     } | ||
|  |     else if (message.type === 'taskProgressCount') { | ||
|  |         toastService.showPersistent(makeToast(message.taskId, "Export in progress: " + message.progressCount)); | ||
|  |     } | ||
|  |     else if (message.type === 'taskSucceeded') { | ||
|  |         const toast = makeToast(message.taskId, "Export finished successfully."); | ||
|  |         toast.closeAfter = 5000; | ||
|  | 
 | ||
|  |         toastService.showPersistent(toast); | ||
|  |     } | ||
|  | }); |