mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	unified export dialog, WIP
This commit is contained in:
		
							
								
								
									
										67
									
								
								src/public/javascripts/dialogs/export.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/public/javascripts/dialogs/export.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | import treeService from '../services/tree.js'; | ||||||
|  | import treeUtils from "../services/tree_utils.js"; | ||||||
|  | import exportService from "../services/export.js"; | ||||||
|  |  | ||||||
|  | const $dialog = $("#export-dialog"); | ||||||
|  | const $form = $("#export-form"); | ||||||
|  | const $noteTitle = $dialog.find(".note-title"); | ||||||
|  | const $subtreeFormats = $("#export-subtree-formats"); | ||||||
|  | const $singleFormats = $("#export-single-formats"); | ||||||
|  | const $subtreeType = $("#export-type-subtree"); | ||||||
|  | const $singleType = $("#export-type-single"); | ||||||
|  |  | ||||||
|  | async function showDialog(defaultType) { | ||||||
|  |     if (defaultType === 'subtree') { | ||||||
|  |         $subtreeType.prop("checked", true).change(); | ||||||
|  |     } | ||||||
|  |     else if (defaultType === 'single') { | ||||||
|  |         $singleType.prop("checked", true).change(); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         throw new Error("Unrecognized type " + defaultType); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     glob.activeDialog = $dialog; | ||||||
|  |  | ||||||
|  |     $dialog.modal(); | ||||||
|  |  | ||||||
|  |     const currentNode = treeService.getCurrentNode(); | ||||||
|  |     const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId); | ||||||
|  |  | ||||||
|  |     $noteTitle.html(noteTitle); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | $form.submit(() => { | ||||||
|  |     const exportType = $dialog.find("input[name='export-type']:checked").val(); | ||||||
|  |  | ||||||
|  |     const currentNode = treeService.getCurrentNode(); | ||||||
|  |  | ||||||
|  |     exportService.exportNote(currentNode.data.branchId, exportType); | ||||||
|  |  | ||||||
|  |     $dialog.modal('hide'); | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | $('input[name=export-type]').change(function () { | ||||||
|  |     if (this.value === 'subtree') { | ||||||
|  |         if ($("input[name=export-subtree-format]:checked").length === 0) { | ||||||
|  |             $("input[name=export-subtree-format]:first").prop("checked", true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $subtreeFormats.slideDown(); | ||||||
|  |         $singleFormats.slideUp(); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         if ($("input[name=export-single-format]:checked").length === 0) { | ||||||
|  |             $("input[name=export-single-format]:first").prop("checked", true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $subtreeFormats.slideUp(); | ||||||
|  |         $singleFormats.slideDown(); | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |     showDialog | ||||||
|  | }; | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| import treeService from '../services/tree.js'; |  | ||||||
| import server from '../services/server.js'; |  | ||||||
| import treeUtils from "../services/tree_utils.js"; |  | ||||||
| import exportService from "../services/export.js"; |  | ||||||
|  |  | ||||||
| const $dialog = $("#export-subtree-dialog"); |  | ||||||
| const $form = $("#export-subtree-form"); |  | ||||||
| const $noteTitle = $dialog.find(".note-title"); |  | ||||||
|  |  | ||||||
| async function showDialog() { |  | ||||||
|     glob.activeDialog = $dialog; |  | ||||||
|  |  | ||||||
|     $dialog.modal(); |  | ||||||
|  |  | ||||||
|     const currentNode = treeService.getCurrentNode(); |  | ||||||
|     const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId); |  | ||||||
|  |  | ||||||
|     $noteTitle.html(noteTitle); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| $form.submit(() => { |  | ||||||
|     const exportFormat = $dialog.find("input[name='export-format']:checked").val(); |  | ||||||
|  |  | ||||||
|     const currentNode = treeService.getCurrentNode(); |  | ||||||
|  |  | ||||||
|     exportService.exportSubtree(currentNode.data.branchId, exportFormat); |  | ||||||
|  |  | ||||||
|     $dialog.modal('hide'); |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|     showDialog |  | ||||||
| }; |  | ||||||
							
								
								
									
										5
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							| @@ -7,6 +7,7 @@ import recentChangesDialog from '../dialogs/recent_changes.js'; | |||||||
| import optionsDialog from '../dialogs/options.js'; | import optionsDialog from '../dialogs/options.js'; | ||||||
| import sqlConsoleDialog from '../dialogs/sql_console.js'; | import sqlConsoleDialog from '../dialogs/sql_console.js'; | ||||||
| import markdownImportDialog from '../dialogs/markdown_import.js'; | import markdownImportDialog from '../dialogs/markdown_import.js'; | ||||||
|  | import exportDialog from '../dialogs/export.js'; | ||||||
|  |  | ||||||
| import cloning from './cloning.js'; | import cloning from './cloning.js'; | ||||||
| import contextMenu from './tree_context_menu.js'; | import contextMenu from './tree_context_menu.js'; | ||||||
| @@ -103,12 +104,12 @@ if (utils.isElectron()) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| $("#export-note-to-markdown-button").click(function () { | $("#export-note-button").click(function () { | ||||||
|     if ($(this).hasClass("disabled")) { |     if ($(this).hasClass("disabled")) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     exportService.exportSubtree(noteDetailService.getCurrentNoteId(), 'markdown-single') |     exportDialog.showDialog('single'); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| treeService.showTree(); | treeService.showTree(); | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import protectedSessionHolder from './protected_session_holder.js'; | |||||||
| import utils from './utils.js'; | import utils from './utils.js'; | ||||||
| import server from './server.js'; | import server from './server.js'; | ||||||
|  |  | ||||||
| function exportSubtree(noteId, format) { | function exportNote(noteId, format) { | ||||||
|     const url = utils.getHost() + "/api/notes/" + noteId + "/export/" + format + |     const url = utils.getHost() + "/api/notes/" + noteId + "/export/" + format + | ||||||
|         "?protectedSessionId=" + encodeURIComponent(protectedSessionHolder.getProtectedSessionId()); |         "?protectedSessionId=" + encodeURIComponent(protectedSessionHolder.getProtectedSessionId()); | ||||||
|  |  | ||||||
| @@ -47,6 +47,6 @@ $("#import-upload").change(async function() { | |||||||
| }); | }); | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     exportSubtree, |     exportNote, | ||||||
|     importIntoNote |     importIntoNote | ||||||
| }; | }; | ||||||
| @@ -564,8 +564,6 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection | |||||||
|  |  | ||||||
|     clearSelectedNodes(); // to unmark previously active node |     clearSelectedNodes(); // to unmark previously active node | ||||||
|  |  | ||||||
|     infoService.showMessage("Created!"); |  | ||||||
|  |  | ||||||
|     return {note, branch}; |     return {note, branch}; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import protectedSessionService from './protected_session.js'; | |||||||
| import treeChangesService from './branches.js'; | import treeChangesService from './branches.js'; | ||||||
| import treeUtils from './tree_utils.js'; | import treeUtils from './tree_utils.js'; | ||||||
| import branchPrefixDialog from '../dialogs/branch_prefix.js'; | import branchPrefixDialog from '../dialogs/branch_prefix.js'; | ||||||
| import exportSubtreeDialog from '../dialogs/export_subtree.js'; | import exportDialog from '../dialogs/export.js'; | ||||||
| import infoService from "./info.js"; | import infoService from "./info.js"; | ||||||
| import treeCache from "./tree_cache.js"; | import treeCache from "./tree_cache.js"; | ||||||
| import syncService from "./sync.js"; | import syncService from "./sync.js"; | ||||||
| @@ -93,7 +93,7 @@ const contextMenuItems = [ | |||||||
|     {title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "clipboard"}, |     {title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "clipboard"}, | ||||||
|     {title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard"}, |     {title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard"}, | ||||||
|     {title: "----"}, |     {title: "----"}, | ||||||
|     {title: "Export subtree", cmd: "exportSubtree", uiIcon: "arrow-up-right"}, |     {title: "Export", cmd: "export", uiIcon: "arrow-up-right"}, | ||||||
|     {title: "Import into note (tar, opml, md, enex)", cmd: "importIntoNote", uiIcon: "arrow-down-left"}, |     {title: "Import into note (tar, opml, md, enex)", cmd: "importIntoNote", uiIcon: "arrow-down-left"}, | ||||||
|     {title: "----"}, |     {title: "----"}, | ||||||
|     {title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify"}, |     {title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify"}, | ||||||
| @@ -127,7 +127,7 @@ async function getContextMenuItems(event) { | |||||||
|     enableItem("pasteAfter", clipboardIds.length > 0 && isNotRoot && parentNote.type !== 'search'); |     enableItem("pasteAfter", clipboardIds.length > 0 && isNotRoot && parentNote.type !== 'search'); | ||||||
|     enableItem("pasteInto", clipboardIds.length > 0 && note.type !== 'search'); |     enableItem("pasteInto", clipboardIds.length > 0 && note.type !== 'search'); | ||||||
|     enableItem("importIntoNote", note.type !== 'search'); |     enableItem("importIntoNote", note.type !== 'search'); | ||||||
|     enableItem("exportSubtree", note.type !== 'search'); |     enableItem("export", note.type !== 'search'); | ||||||
|     enableItem("editBranchPrefix", isNotRoot && parentNote.type !== 'search'); |     enableItem("editBranchPrefix", isNotRoot && parentNote.type !== 'search'); | ||||||
|  |  | ||||||
|     // Activate node on right-click |     // Activate node on right-click | ||||||
| @@ -179,8 +179,8 @@ function selectContextMenuItem(event, cmd) { | |||||||
|     else if (cmd === "delete") { |     else if (cmd === "delete") { | ||||||
|         treeChangesService.deleteNodes(treeService.getSelectedNodes(true)); |         treeChangesService.deleteNodes(treeService.getSelectedNodes(true)); | ||||||
|     } |     } | ||||||
|     else if (cmd === "exportSubtree") { |     else if (cmd === "export") { | ||||||
|         exportSubtreeDialog.showDialog(); |         exportDialog.showDialog("subtree"); | ||||||
|     } |     } | ||||||
|     else if (cmd === "importIntoNote") { |     else if (cmd === "importIntoNote") { | ||||||
|         exportService.importIntoNote(node.data.noteId); |         exportService.importIntoNote(node.data.noteId); | ||||||
|   | |||||||
| @@ -685,3 +685,13 @@ div[data-notify="container"] { | |||||||
|     color: #777; |     color: #777; | ||||||
|     z-index: 100; |     z-index: 100; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #export-form .form-check { | ||||||
|  |     padding-top: 10px; | ||||||
|  |     padding-bottom: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #export-form .format-choice { | ||||||
|  |     padding-left: 40px; | ||||||
|  |     display: none; | ||||||
|  | } | ||||||
| @@ -9,14 +9,15 @@ const repository = require("../../services/repository"); | |||||||
| async function exportNote(req, res) { | async function exportNote(req, res) { | ||||||
|     // entityId maybe either noteId or branchId depending on format |     // entityId maybe either noteId or branchId depending on format | ||||||
|     const entityId = req.params.entityId; |     const entityId = req.params.entityId; | ||||||
|  |     const type = req.params.type; | ||||||
|     const format = req.params.format; |     const format = req.params.format; | ||||||
|  |  | ||||||
|     if (format === 'native-tar') { |     if (type === 'tar') { | ||||||
|         await nativeTarExportService.exportToTar(await repository.getBranch(entityId), res); |         await nativeTarExportService.exportToTar(await repository.getBranch(entityId), format, res); | ||||||
|     } |  | ||||||
|     else if (format === 'markdown-tar') { |  | ||||||
|         await markdownTarExportService.exportToMarkdown(await repository.getBranch(entityId), res); |  | ||||||
|     } |     } | ||||||
|  |     // else if (format === 'tar') { | ||||||
|  |     //     await markdownTarExportService.exportToMarkdown(await repository.getBranch(entityId), res); | ||||||
|  |     // } | ||||||
|     // export single note without subtree |     // export single note without subtree | ||||||
|     else if (format === 'markdown-single') { |     else if (format === 'markdown-single') { | ||||||
|         await markdownSingleExportService.exportSingleMarkdown(await repository.getNote(entityId), res); |         await markdownSingleExportService.exportSingleMarkdown(await repository.getNote(entityId), res); | ||||||
|   | |||||||
| @@ -3,8 +3,15 @@ | |||||||
| const html = require('html'); | const html = require('html'); | ||||||
| const native_tar = require('tar-stream'); | const native_tar = require('tar-stream'); | ||||||
| const sanitize = require("sanitize-filename"); | const sanitize = require("sanitize-filename"); | ||||||
|  | const mimeTypes = require('mime-types'); | ||||||
|  | const TurndownService = require('turndown'); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param format - 'html' or 'markdown' | ||||||
|  |  */ | ||||||
|  | async function exportToTar(branch, format, res) { | ||||||
|  |     const turndownService = new TurndownService(); | ||||||
|  |  | ||||||
| async function exportToTar(branch, res) { |  | ||||||
|     const pack = native_tar.pack(); |     const pack = native_tar.pack(); | ||||||
|  |  | ||||||
|     const exportedNoteIds = []; |     const exportedNoteIds = []; | ||||||
| @@ -52,6 +59,10 @@ async function exportToTar(branch, res) { | |||||||
|             }) |             }) | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|  |         if (note.type === 'text') { | ||||||
|  |             metadata.format = format; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (await note.hasLabel('excludeFromExport')) { |         if (await note.hasLabel('excludeFromExport')) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @@ -75,9 +86,35 @@ async function exportToTar(branch, res) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     function saveDataFile(childFileName, note) { |     function saveDataFile(childFileName, note) { | ||||||
|         const content = note.type === 'text' ? html.prettyPrint(note.content, {indent_size: 2}) : note.content; |         let content = note.content; | ||||||
|  |  | ||||||
|         pack.entry({name: childFileName + ".dat", size: content.length}, content); |         if (note.type === 'text') { | ||||||
|  |             if (format === 'html') { | ||||||
|  |                 content = html.prettyPrint(note.content, {indent_size: 2}); | ||||||
|  |             } | ||||||
|  |             else if (format === 'markdown') { | ||||||
|  |                 content = turndownService.turndown(note.content); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 throw new Error("Unknown format: " + format); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const extension = mimeTypes.extension(note.mime) | ||||||
|  |             || getExceptionalExtension(note.mime) | ||||||
|  |             || "dat"; | ||||||
|  |  | ||||||
|  |         if (!childFileName.toLowerCase().endsWith(extension)) { | ||||||
|  |             childFileName += "." + extension; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         pack.entry({name: childFileName, size: content.length}, content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function getExceptionalExtension(mime) { | ||||||
|  |         if (mime === 'application/x-javascript') { | ||||||
|  |             return 'js'; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function saveMetadataFile(childFileName, metadata) { |     function saveMetadataFile(childFileName, metadata) { | ||||||
|   | |||||||
							
								
								
									
										67
									
								
								src/views/dialogs/export.ejs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/views/dialogs/export.ejs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | <div id="export-dialog" class="modal fade mx-auto" tabindex="-1" role="dialog"> | ||||||
|  |     <div class="modal-dialog modal-lg" role="document"> | ||||||
|  |         <div class="modal-content"> | ||||||
|  |             <div class="modal-header"> | ||||||
|  |                 <h5 class="modal-title">Export note</h5> | ||||||
|  |                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||||
|  |                     <span aria-hidden="true">×</span> | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|  |             <form id="export-form"> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <div class="form-check"> | ||||||
|  |                         <input class="form-check-input" type="radio" name="export-type" id="export-type-subtree" value="subtree"> | ||||||
|  |                         <label class="form-check-label" for="export-type-subtree">this note and all of its descendants</label> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <div id="export-subtree-formats" class="format-choice"> | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-html" | ||||||
|  |                                    value="html"> | ||||||
|  |                             <label class="form-check-label" for="export-subtree-format-html">HTML in TAR archiv - this is recommended since this preserves all the formatting.</label> | ||||||
|  |                         </div> | ||||||
|  |  | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-markdown" | ||||||
|  |                                    value="markdown-tar"> | ||||||
|  |                             <label class="form-check-label" for="export-subtree-format-markdown"> | ||||||
|  |                                 Markdown - this preserves most of the formatting. | ||||||
|  |                             </label> | ||||||
|  |                         </div> | ||||||
|  |  | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-opml" | ||||||
|  |                                    value="opml"> | ||||||
|  |                             <label class="form-check-label" for="export-subtree-format-opml"> | ||||||
|  |                                 OPML - outliner interchange format for text only. Formatting, images and files are not included. | ||||||
|  |                             </label> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <div class="form-check"> | ||||||
|  |                         <input class="form-check-input" type="radio" name="export-type" id="export-type-single" value="single"> | ||||||
|  |                         <label class="form-check-label" for="export-type-single">only this note without its descendants</label> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <div id="export-single-formats" class="format-choice"> | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <input class="form-check-input" type="radio" name="export-single-format" id="export-single-format-html" value="html"> | ||||||
|  |                             <label class="form-check-label" for="export-single-format-html">HTML - this is recommended since this preserves all the formatting.</label> | ||||||
|  |                         </div> | ||||||
|  |  | ||||||
|  |                         <div class="form-check"> | ||||||
|  |                             <input class="form-check-input" type="radio" name="export-single-format" id="export-single-format-markdown" | ||||||
|  |                                    value="markdown-tar"> | ||||||
|  |                             <label class="form-check-label" for="export-single-format-markdown"> | ||||||
|  |                                 Markdown - this preserves most of the formatting. | ||||||
|  |                             </label> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                     <button class="btn btn-primary btn-sm">Export</button> | ||||||
|  |                 </div> | ||||||
|  |             </form> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| <div id="export-subtree-dialog" class="modal fade mx-auto" tabindex="-1" role="dialog"> |  | ||||||
|     <div class="modal-dialog modal-lg" role="document"> |  | ||||||
|         <div class="modal-content"> |  | ||||||
|             <div class="modal-header"> |  | ||||||
|                 <h5 class="modal-title">Export subtree</h5> |  | ||||||
|                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"> |  | ||||||
|                     <span aria-hidden="true">×</span> |  | ||||||
|                 </button> |  | ||||||
|             </div> |  | ||||||
|             <form id="export-subtree-form"> |  | ||||||
|                 <div class="modal-body"> |  | ||||||
|                     <div>Export note "<span class="note-title"></span>" and its subtree in the following format:</div> |  | ||||||
|  |  | ||||||
|                     <br/> |  | ||||||
|  |  | ||||||
|                     <div class="form-check"> |  | ||||||
|                         <input class="form-check-input" type="radio" name="export-format" id="export-format-tar" value="native-tar" checked> |  | ||||||
|                         <label class="form-check-label" for="export-format-tar">Native TAR - this is Trilium's native format which preserves all notes' data & metadata.</label> |  | ||||||
|                     </div> |  | ||||||
|  |  | ||||||
|                     <br/> |  | ||||||
|  |  | ||||||
|                     <div class="form-check"> |  | ||||||
|                         <input class="form-check-input" type="radio" name="export-format" id="export-format-opml" value="opml"> |  | ||||||
|                         <label class="form-check-label" for="export-format-opml"> |  | ||||||
|                             OPML - standard outliner interchange format for text only. Formatting, images, files are not included. |  | ||||||
|                         </label> |  | ||||||
|                     </div> |  | ||||||
|  |  | ||||||
|                     <br/> |  | ||||||
|  |  | ||||||
|                     <div class="form-check disabled"> |  | ||||||
|                         <input class="form-check-input" type="radio" name="export-format" id="export-format-markdown" |  | ||||||
|                                value="markdown-tar"> |  | ||||||
|                         <label class="form-check-label" for="export-format-markdown"> |  | ||||||
|                             Markdown - TAR archive of Markdown formatted notes |  | ||||||
|                         </label> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="modal-footer"> |  | ||||||
|                     <button class="btn btn-primary btn-sm">Export</button> |  | ||||||
|                 </div> |  | ||||||
|             </form> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| @@ -157,9 +157,9 @@ | |||||||
|                 <div class="dropdown-menu dropdown-menu-right"> |                 <div class="dropdown-menu dropdown-menu-right"> | ||||||
|                   <a class="dropdown-item" id="show-note-revisions-button" data-bind="css: { disabled: type() == 'file' || type() == 'image' }">Revisions</a> |                   <a class="dropdown-item" id="show-note-revisions-button" data-bind="css: { disabled: type() == 'file' || type() == 'image' }">Revisions</a> | ||||||
|                   <a class="dropdown-item show-attributes-button"><kbd>Alt+A</kbd> Attributes</a> |                   <a class="dropdown-item show-attributes-button"><kbd>Alt+A</kbd> Attributes</a> | ||||||
|                   <a class="dropdown-item" id="show-source-button" data-bind="css: { disabled: type() != 'text' }">HTML source</a> |                   <a class="dropdown-item" id="show-source-button" data-bind="css: { disabled: type() != 'text' && type() != 'code' && type() != 'relation-map' && type() != 'search' }">Note source</a> | ||||||
|                   <a class="dropdown-item" id="upload-file-button">Upload file</a> |                   <a class="dropdown-item" id="upload-file-button">Upload file</a> | ||||||
|                   <a class="dropdown-item" id="export-note-to-markdown-button" data-bind="css: { disabled: type() != 'text' && type() != 'code' }">Export as markdown</a> |                   <a class="dropdown-item" id="export-note-button" data-bind="css: { disabled: type() != 'text' }">Export note</a> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
| @@ -173,7 +173,7 @@ | |||||||
|       <% include dialogs/attributes.ejs %> |       <% include dialogs/attributes.ejs %> | ||||||
|       <% include dialogs/branch_prefix.ejs %> |       <% include dialogs/branch_prefix.ejs %> | ||||||
|       <% include dialogs/event_log.ejs %> |       <% include dialogs/event_log.ejs %> | ||||||
|       <% include dialogs/export_subtree.ejs %> |       <% include dialogs/export.ejs %> | ||||||
|       <% include dialogs/jump_to_note.ejs %> |       <% include dialogs/jump_to_note.ejs %> | ||||||
|       <% include dialogs/markdown_import.ejs %> |       <% include dialogs/markdown_import.ejs %> | ||||||
|       <% include dialogs/note_revisions.ejs %> |       <% include dialogs/note_revisions.ejs %> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user