From e1b67e20ec66b0d295fe567d21baeb68ad23c72a Mon Sep 17 00:00:00 2001 From: dymani Date: Tue, 30 May 2023 02:24:56 +0800 Subject: [PATCH 1/4] Add buttons to move split panes --- src/public/app/layouts/desktop_layout.js | 3 + .../app/widgets/buttons/move_pane_button.js | 55 +++++++++++++++++++ .../containers/split_note_container.js | 38 +++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/public/app/widgets/buttons/move_pane_button.js diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index 17dcc99a7..62e6b3ed1 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -75,6 +75,7 @@ import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js"; import ApiLogWidget from "../widgets/api_log.js"; import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; import ScriptExecutorWidget from "../widgets/ribbon_widgets/script_executor.js"; +import MovePaneButton from "../widgets/buttons/move_pane_button.js"; export default class DesktopLayout { constructor(customWidgets) { @@ -123,6 +124,8 @@ export default class DesktopLayout { .child(new NoteIconWidget()) .child(new NoteTitleWidget()) .child(new SpacerWidget(0, 1)) + .child(new MovePaneButton(true)) + .child(new MovePaneButton(false)) .child(new ClosePaneButton()) .child(new CreatePaneButton()) ) diff --git a/src/public/app/widgets/buttons/move_pane_button.js b/src/public/app/widgets/buttons/move_pane_button.js new file mode 100644 index 000000000..9ea4dbe61 --- /dev/null +++ b/src/public/app/widgets/buttons/move_pane_button.js @@ -0,0 +1,55 @@ +import OnClickButtonWidget from "./onclick_button.js"; +import appContext from "../../components/app_context.js"; + +export default class MovePaneButton extends OnClickButtonWidget { + isEnabled() { + if (!super.isEnabled()) + return false; + + if (this.isMovingLeft) { + // movable if the current context is not a main context, i.e. non-null mainNtxId + return !!this.noteContext?.mainNtxId; + } else { + const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); + const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; + // movable if the next context is not null and not a main context, i.e. non-null mainNtxId + return !!nextContext?.mainNtxId; + } + } + + initialRenderCompleteEvent() { + this.refresh(); + super.initialRenderCompleteEvent(); + } + + async noteContextRemovedEvent({ntxIds}) { + this.refresh(); + } + + async newNoteContextCreatedEvent({noteContext}) { + this.refresh(); + } + + async noteContextSwitchEvent() { + this.refresh(); + } + + async noteContextReorderEvent({ntxIdsInOrder}) { + this.refresh(); + } + + constructor(isMovingLeft) { + super(); + + this.isMovingLeft = isMovingLeft; + + this.icon(isMovingLeft ? "bx-chevron-left" : "bx-chevron-right") + .title(isMovingLeft ? "Move left" : "Move right") + .titlePlacement("bottom") + .onClick(async (widget, e) => { + e.stopPropagation(); + widget.triggerCommand("moveThisNoteSplit", {ntxId: widget.getClosestNtxId(), isMovingLeft: this.isMovingLeft}); + }) + .class("icon-action"); + } +} diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 66356164d..854ccfd23 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -1,5 +1,6 @@ import FlexContainer from "./flex_container.js"; import appContext from "../../components/app_context.js"; +import NoteContext from "../../components/note_context.js"; export default class SplitNoteContainer extends FlexContainer { constructor(widgetFactory) { @@ -74,6 +75,43 @@ export default class SplitNoteContainer extends FlexContainer { appContext.tabManager.removeNoteContext(ntxId); } + async moveThisNoteSplitCommand({ntxId, isMovingLeft}) { + if (!ntxId) { + logError("empty ntxId!"); + return; + } + + const contexts = appContext.tabManager.noteContexts; + + const currentIndex = contexts.findIndex(c => c.ntxId === ntxId); + const otherIndex = currentIndex + (isMovingLeft ? -1 : 1); + + if (currentIndex === -1 || otherIndex < 0 || otherIndex >= contexts.length) { + logError("invalid context!"); + return; + } + + if (contexts[currentIndex].isEmpty() && contexts[otherIndex].isEmpty()) + // no op + return; + + const currentId = contexts[currentIndex].ntxId; + const currentPath = contexts[currentIndex].notePath; + + const otherId = contexts[otherIndex].ntxId; + const otherPath = contexts[otherIndex].notePath; + + if (!!currentPath) + await appContext.tabManager.switchToNoteContext(otherId, currentPath); + if (!!otherPath) + await appContext.tabManager.switchToNoteContext(currentId, otherPath); + + // activate context that now contains the original note + await appContext.tabManager.activateNoteContext(otherId); + + this.triggerEvent('noteContextSwitch'); + } + activeContextChangedEvent() { this.refresh(); } From 2a399069936bb3e0c094ca52ebbad493ed529122 Mon Sep 17 00:00:00 2001 From: dymani Date: Tue, 30 May 2023 04:22:51 +0800 Subject: [PATCH 2/4] Cleanup --- src/public/app/widgets/containers/split_note_container.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 854ccfd23..3a17b7d20 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -1,6 +1,5 @@ import FlexContainer from "./flex_container.js"; import appContext from "../../components/app_context.js"; -import NoteContext from "../../components/note_context.js"; export default class SplitNoteContainer extends FlexContainer { constructor(widgetFactory) { From 735852b3c1dc9d642bfc01f603b1f84aec9e9e1b Mon Sep 17 00:00:00 2001 From: dymani Date: Wed, 31 May 2023 01:53:55 +0800 Subject: [PATCH 3/4] Use noteContextReorder event instead --- src/public/app/components/tab_manager.js | 13 ++++--- .../app/widgets/buttons/close_pane_button.js | 4 +++ .../containers/split_note_container.js | 36 ++++++++++--------- src/public/app/widgets/tab_row.js | 16 +++++++++ 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index e5ca32c45..ace30105f 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -451,16 +451,15 @@ export default class TabManager extends Component { this.tabsUpdate.scheduleUpdate(); } - noteContextReorderEvent({ntxIdsInOrder}) { - const order = {}; - let i = 0; - - for (const ntxId of ntxIdsInOrder) { - order[ntxId] = i++; - } + noteContextReorderEvent({ntxIdsInOrder, mainNtxIdsInOrder}) { + const order = Object.fromEntries(ntxIdsInOrder.map((v, i) => [v, i])); this.children.sort((a, b) => order[a.ntxId] < order[b.ntxId] ? -1 : 1); + if (!!mainNtxIdsInOrder && mainNtxIdsInOrder.length === this.children.length) { + this.children.forEach((c, i) => c.mainNtxId = mainNtxIdsInOrder[i]); + } + this.tabsUpdate.scheduleUpdate(); } diff --git a/src/public/app/widgets/buttons/close_pane_button.js b/src/public/app/widgets/buttons/close_pane_button.js index 690dcac6f..220fd2cca 100644 --- a/src/public/app/widgets/buttons/close_pane_button.js +++ b/src/public/app/widgets/buttons/close_pane_button.js @@ -7,6 +7,10 @@ export default class ClosePaneButton extends OnClickButtonWidget { && this.noteContext && !!this.noteContext.mainNtxId; } + async noteContextReorderEvent({ntxIdsInOrder}) { + this.refresh(); + } + constructor() { super(); diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 3a17b7d20..988c537b1 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -83,32 +83,36 @@ export default class SplitNoteContainer extends FlexContainer { const contexts = appContext.tabManager.noteContexts; const currentIndex = contexts.findIndex(c => c.ntxId === ntxId); - const otherIndex = currentIndex + (isMovingLeft ? -1 : 1); + const leftIndex = isMovingLeft ? currentIndex - 1 : currentIndex; - if (currentIndex === -1 || otherIndex < 0 || otherIndex >= contexts.length) { + if (currentIndex === -1 || leftIndex < 0 || leftIndex + 1 >= contexts.length) { logError("invalid context!"); return; } - if (contexts[currentIndex].isEmpty() && contexts[otherIndex].isEmpty()) + if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) // no op return; - const currentId = contexts[currentIndex].ntxId; - const currentPath = contexts[currentIndex].notePath; - - const otherId = contexts[otherIndex].ntxId; - const otherPath = contexts[otherIndex].notePath; - - if (!!currentPath) - await appContext.tabManager.switchToNoteContext(otherId, currentPath); - if (!!otherPath) - await appContext.tabManager.switchToNoteContext(currentId, otherPath); + const ntxIds = contexts.map(c => c.ntxId); + const mainNtxIds = contexts.map(c => c.mainNtxId); + + this.triggerCommand("noteContextReorder", { + ntxIdsInOrder: [ + ...ntxIds.slice(0, leftIndex), + ntxIds[leftIndex + 1], + ntxIds[leftIndex], + ...ntxIds.slice(leftIndex + 2), + ], + oldNtxIdsInOrder: ntxIds, + mainNtxIdsInOrder: mainNtxIds.map(id => id === ntxIds[leftIndex] ? ntxIds[leftIndex + 1] : id) + }); + + this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex]}"]`) + .insertAfter(this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex + 1]}"]`)); // activate context that now contains the original note - await appContext.tabManager.activateNoteContext(otherId); - - this.triggerEvent('noteContextSwitch'); + await appContext.tabManager.activateNoteContext(isMovingLeft ? ntxIds[leftIndex + 1] : ntxIds[leftIndex]); } activeContextChangedEvent() { diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index 55a5da24c..6e15f3458 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -609,6 +609,22 @@ export default class TabRowWidget extends BasicWidget { this.updateTabById(noteContext.mainNtxId || noteContext.ntxId); } + noteContextReorderEvent({ntxIdsInOrder, oldNtxIdsInOrder, mainNtxIdsInOrder}) { + if (!oldNtxIdsInOrder || !mainNtxIdsInOrder + || ntxIdsInOrder.length !== oldNtxIdsInOrder.length + || ntxIdsInOrder.length !== mainNtxIdsInOrder.length + ) + return; + + ntxIdsInOrder.forEach((id, i) => { + // update main context that is not a tab + if (!mainNtxIdsInOrder[i] && this.getTabById(id).length === 0) { + this.getTabById(oldNtxIdsInOrder[i]).attr("data-ntx-id", id); + this.updateTabById(id); + } + }); + } + updateTabById(ntxId) { const $tab = this.getTabById(ntxId); From 58253567cd55a72a86252cd6237d8b1a46ebc996 Mon Sep 17 00:00:00 2001 From: dymani Date: Thu, 1 Jun 2023 00:48:37 +0800 Subject: [PATCH 4/4] Simplify noteContextReorder event call --- src/public/app/components/tab_manager.js | 14 +++- .../app/widgets/buttons/move_pane_button.js | 64 ++++++++----------- .../containers/split_note_container.js | 25 ++++---- src/public/app/widgets/tab_row.js | 19 ++---- 4 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index ace30105f..53c3ccbbd 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -451,13 +451,21 @@ export default class TabManager extends Component { this.tabsUpdate.scheduleUpdate(); } - noteContextReorderEvent({ntxIdsInOrder, mainNtxIdsInOrder}) { + noteContextReorderEvent({ntxIdsInOrder, oldMainNtxId, newMainNtxId}) { const order = Object.fromEntries(ntxIdsInOrder.map((v, i) => [v, i])); this.children.sort((a, b) => order[a.ntxId] < order[b.ntxId] ? -1 : 1); - if (!!mainNtxIdsInOrder && mainNtxIdsInOrder.length === this.children.length) { - this.children.forEach((c, i) => c.mainNtxId = mainNtxIdsInOrder[i]); + if (oldMainNtxId && newMainNtxId) { + this.children.forEach(c => { + if (c.ntxId === newMainNtxId) { + // new main context has null mainNtxId + c.mainNtxId = null; + } else if (c.ntxId === oldMainNtxId || c.mainNtxId === oldMainNtxId) { + // old main context or subcontexts all have the new mainNtxId + c.mainNtxId = newMainNtxId; + } + }); } this.tabsUpdate.scheduleUpdate(); diff --git a/src/public/app/widgets/buttons/move_pane_button.js b/src/public/app/widgets/buttons/move_pane_button.js index 9ea4dbe61..632651ca5 100644 --- a/src/public/app/widgets/buttons/move_pane_button.js +++ b/src/public/app/widgets/buttons/move_pane_button.js @@ -2,42 +2,6 @@ import OnClickButtonWidget from "./onclick_button.js"; import appContext from "../../components/app_context.js"; export default class MovePaneButton extends OnClickButtonWidget { - isEnabled() { - if (!super.isEnabled()) - return false; - - if (this.isMovingLeft) { - // movable if the current context is not a main context, i.e. non-null mainNtxId - return !!this.noteContext?.mainNtxId; - } else { - const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); - const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; - // movable if the next context is not null and not a main context, i.e. non-null mainNtxId - return !!nextContext?.mainNtxId; - } - } - - initialRenderCompleteEvent() { - this.refresh(); - super.initialRenderCompleteEvent(); - } - - async noteContextRemovedEvent({ntxIds}) { - this.refresh(); - } - - async newNoteContextCreatedEvent({noteContext}) { - this.refresh(); - } - - async noteContextSwitchEvent() { - this.refresh(); - } - - async noteContextReorderEvent({ntxIdsInOrder}) { - this.refresh(); - } - constructor(isMovingLeft) { super(); @@ -52,4 +16,32 @@ export default class MovePaneButton extends OnClickButtonWidget { }) .class("icon-action"); } + + isEnabled() { + if (!super.isEnabled()) { + return false; + } + + if (this.isMovingLeft) { + // movable if the current context is not a main context, i.e. non-null mainNtxId + return !!this.noteContext?.mainNtxId; + } else { + const currentIndex = appContext.tabManager.noteContexts.findIndex(c => c.ntxId === this.ntxId); + const nextContext = appContext.tabManager.noteContexts[currentIndex + 1]; + // movable if the next context is not null and not a main context, i.e. non-null mainNtxId + return !!nextContext?.mainNtxId; + } + } + + async noteContextRemovedEvent() { + this.refresh(); + } + + async newNoteContextCreatedEvent() { + this.refresh(); + } + + async noteContextReorderEvent() { + this.refresh(); + } } diff --git a/src/public/app/widgets/containers/split_note_container.js b/src/public/app/widgets/containers/split_note_container.js index 988c537b1..0188add6d 100644 --- a/src/public/app/widgets/containers/split_note_container.js +++ b/src/public/app/widgets/containers/split_note_container.js @@ -86,28 +86,31 @@ export default class SplitNoteContainer extends FlexContainer { const leftIndex = isMovingLeft ? currentIndex - 1 : currentIndex; if (currentIndex === -1 || leftIndex < 0 || leftIndex + 1 >= contexts.length) { - logError("invalid context!"); + logError(`invalid context! currentIndex: ${currentIndex}, leftIndex: ${leftIndex}, contexts.length: ${contexts.length}`); return; } - if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) + if (contexts[leftIndex].isEmpty() && contexts[leftIndex + 1].isEmpty()) { // no op return; + } const ntxIds = contexts.map(c => c.ntxId); - const mainNtxIds = contexts.map(c => c.mainNtxId); + const newNtxIds = [ + ...ntxIds.slice(0, leftIndex), + ntxIds[leftIndex + 1], + ntxIds[leftIndex], + ...ntxIds.slice(leftIndex + 2), + ]; + const isChangingMainContext = !contexts[leftIndex].mainNtxId; this.triggerCommand("noteContextReorder", { - ntxIdsInOrder: [ - ...ntxIds.slice(0, leftIndex), - ntxIds[leftIndex + 1], - ntxIds[leftIndex], - ...ntxIds.slice(leftIndex + 2), - ], - oldNtxIdsInOrder: ntxIds, - mainNtxIdsInOrder: mainNtxIds.map(id => id === ntxIds[leftIndex] ? ntxIds[leftIndex + 1] : id) + ntxIdsInOrder: newNtxIds, + oldMainNtxId: isChangingMainContext ? ntxIds[leftIndex] : null, + newMainNtxId: isChangingMainContext ? ntxIds[leftIndex + 1]: null, }); + // reorder the note context widgets this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex]}"]`) .insertAfter(this.$widget.find(`[data-ntx-id="${ntxIds[leftIndex + 1]}"]`)); diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index 6e15f3458..9081ed9e1 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -609,20 +609,15 @@ export default class TabRowWidget extends BasicWidget { this.updateTabById(noteContext.mainNtxId || noteContext.ntxId); } - noteContextReorderEvent({ntxIdsInOrder, oldNtxIdsInOrder, mainNtxIdsInOrder}) { - if (!oldNtxIdsInOrder || !mainNtxIdsInOrder - || ntxIdsInOrder.length !== oldNtxIdsInOrder.length - || ntxIdsInOrder.length !== mainNtxIdsInOrder.length - ) + noteContextReorderEvent({oldMainNtxId, newMainNtxId}) { + if (!oldMainNtxId || !newMainNtxId) { + // no need to update tab row return; + } - ntxIdsInOrder.forEach((id, i) => { - // update main context that is not a tab - if (!mainNtxIdsInOrder[i] && this.getTabById(id).length === 0) { - this.getTabById(oldNtxIdsInOrder[i]).attr("data-ntx-id", id); - this.updateTabById(id); - } - }); + // update tab id for the new main context + this.getTabById(oldMainNtxId).attr("data-ntx-id", newMainNtxId); + this.updateTabById(newMainNtxId); } updateTabById(ntxId) {