converted export dialog to new pattern

This commit is contained in:
zadam 2022-06-16 15:04:57 +02:00
parent 595e16cc6f
commit 36c210d0dd
8 changed files with 264 additions and 240 deletions

View file

@ -1,137 +0,0 @@
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";
const $dialog = $("#export-dialog");
const $form = $("#export-form");
const $noteTitle = $dialog.find(".export-note-title");
const $subtreeFormats = $("#export-subtree-formats");
const $singleFormats = $("#export-single-formats");
const $subtreeType = $("#export-type-subtree");
const $singleType = $("#export-type-single");
const $exportButton = $("#export-button");
const $opmlVersions = $("#opml-versions");
let taskId = '';
let branchId = null;
export async function showDialog(notePath, defaultType) {
// each opening of the dialog resets the taskId so we don't associate it with previous exports anymore
taskId = '';
$exportButton.removeAttr("disabled");
if (defaultType === 'subtree') {
$subtreeType.prop("checked", true).trigger('change');
// to show/hide OPML versions
$("input[name=export-subtree-format]:checked").trigger('change');
}
else if (defaultType === 'single') {
$singleType.prop("checked", true).trigger('change');
}
else {
throw new Error("Unrecognized type " + defaultType);
}
$("#opml-v2").prop("checked", true); // setting default
utils.openDialog($dialog);
const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath);
branchId = await froca.getBranchId(parentNoteId, noteId);
const noteTitle = await treeService.getNoteTitle(noteId);
$noteTitle.html(noteTitle);
}
$form.on('submit', () => {
$dialog.modal('hide');
const exportType = $dialog.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'
? $("input[name=export-subtree-format]:checked").val()
: $("input[name=export-single-format]:checked").val();
const exportVersion = exportFormat === 'opml' ? $dialog.find("input[name='opml-version']:checked").val() : "1.0";
exportBranch(branchId, exportType, exportFormat, exportVersion);
return false;
});
function exportBranch(branchId, type, format, version) {
taskId = utils.randomString(10);
const url = openService.getUrlForDownload(`api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`);
openService.download(url);
}
$('input[name=export-type]').on('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();
}
});
$('input[name=export-subtree-format]').on('change', function () {
if (this.value === 'opml') {
$opmlVersions.slideDown();
}
else {
$opmlVersions.slideUp();
}
});
function makeToast(id, message) {
return {
id: id,
title: "Export status",
message: message,
icon: "arrow-square-up-right"
};
}
ws.subscribeToMessages(async message => {
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);
}
});

View file

@ -66,6 +66,7 @@ import AddLinkDialog from "../widgets/dialogs/add_link.js";
import CloneToDialog from "../widgets/dialogs/clone_to.js";
import MoveToDialog from "../widgets/dialogs/move_to.js";
import ImportDialog from "../widgets/dialogs/import.js";
import ExportDialog from "../widgets/dialogs/export.js";
export default class DesktopLayout {
constructor(customWidgets) {
@ -206,6 +207,7 @@ export default class DesktopLayout {
.child(new AddLinkDialog())
.child(new CloneToDialog())
.child(new MoveToDialog())
.child(new ImportDialog());
.child(new ImportDialog())
.child(new ExportDialog());
}
}

View file

@ -53,7 +53,10 @@ export default class NoteActionsWidget extends NoteContextAwareWidget {
return;
}
import('../../dialogs/export.js').then(d => d.showDialog(this.noteContext.notePath, 'single'));
this.triggerCommand("showExportDialog", {
notePath: this.noteContext.notePath,
defaultType: "single"
});
});
this.$importNoteButton = this.$widget.find('.import-files-button');

View file

@ -0,0 +1,256 @@
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">&times;</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);
}
});

View file

@ -1451,10 +1451,9 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
}
async exportNoteCommand({node}) {
const exportDialog = await import('../dialogs/export.js');
const notePath = treeService.getNotePath(node);
exportDialog.showDialog(notePath,"subtree");
this.triggerCommand("showExportDialog", {notePath, defaultType: "subtree"});
}
async importIntoNoteCommand({node}) {

View file

@ -540,25 +540,6 @@ div[data-notify="container"] {
font-size: 150%;
}
#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;
}
.ck-editor__is-empty.ck-content.ck-editor__editable::before {
content: 'You can start writing note here ...';
position: absolute;

View file

@ -17,7 +17,6 @@
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div>
<%- include('dialogs/export.ejs') %>
<%- include('dialogs/markdown_import.ejs') %>
<%- include('dialogs/note_revisions.ejs') %>
<%- include('dialogs/options.ejs') %>

View file

@ -1,79 +0,0 @@
<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 "<span class="export-note-title"></span>"</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</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 ZIP archive - 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">
<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 id="opml-versions">
<div class="form-check">
<input class="form-check-input" type="radio" name="opml-version" id="opml-v1" value="1.0">
<label class="form-check-label" for="opml-v1">OPML v1.0 - plain text only</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="opml-version" id="opml-v2" value="2.0">
<label class="form-check-label" for="opml-v2">OMPL v2.0 - allows also HTML</label>
</div>
</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">
<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" id="export-button">Export</button>
</div>
</form>
</div>
</div>
</div>