mirror of
https://github.com/heyman/heynote.git
synced 2025-06-28 13:31:38 +02:00
Add feature for moving the current block to another buffer
- The Ctrl/Cmd-S keyboard shortcut now pops up a buffer search dialog that can be used to select a buffer that the block should be moved to. - Update `BufferSelector` UI and logic to support moving blocks
This commit is contained in:
parent
158ac08418
commit
c9c092fc43
@ -5,6 +5,7 @@ Here are the most notable changes in each release. For a more detailed list of c
|
|||||||
|
|
||||||
## 2.1.0 (not yet released)
|
## 2.1.0 (not yet released)
|
||||||
|
|
||||||
|
- Added support for moving the current block to another (or new) buffer. Pressing `Ctrl/Cmd+S` will now pop up a dialog where you can search for and select another buffer to which the block will be moved. It's also possible to select to create a brand new buffer to which the block will be moved.
|
||||||
- Added support for the following languages:
|
- Added support for the following languages:
|
||||||
* Elixir
|
* Elixir
|
||||||
* Scala
|
* Scala
|
||||||
|
@ -39,7 +39,7 @@ Available for Mac, Windows, and Linux.
|
|||||||
⌘ + ⌥ + Enter Split the current block at cursor position
|
⌘ + ⌥ + Enter Split the current block at cursor position
|
||||||
⌘ + L Change block language
|
⌘ + L Change block language
|
||||||
⌘ + N Create a new note buffer
|
⌘ + N Create a new note buffer
|
||||||
⌘ + S Create a new note buffer from the current block
|
⌘ + S Move the current block to another (or new) buffer
|
||||||
⌘ + P Open note selector
|
⌘ + P Open note selector
|
||||||
⌘ + Down Goto next block
|
⌘ + Down Goto next block
|
||||||
⌘ + Up Goto previous block
|
⌘ + Up Goto previous block
|
||||||
@ -58,7 +58,7 @@ Alt + Shift + Enter Add new block at the start of the buffer
|
|||||||
Ctrl + Alt + Enter Split the current block at cursor position
|
Ctrl + Alt + Enter Split the current block at cursor position
|
||||||
Ctrl + L Change block language
|
Ctrl + L Change block language
|
||||||
Ctrl + N Create a new note buffer
|
Ctrl + N Create a new note buffer
|
||||||
Ctrl + S Create a new note buffer from the current block
|
Ctrl + S Move the current block to another (or new) buffer
|
||||||
Ctrl + P Open note selector
|
Ctrl + P Open note selector
|
||||||
Ctrl + Down Goto next block
|
Ctrl + Down Goto next block
|
||||||
Ctrl + Up Goto previous block
|
Ctrl + Up Goto previous block
|
||||||
|
@ -10,7 +10,7 @@ export const keyHelpStr = (platform: string) => {
|
|||||||
[`${modChar} + ${altChar} + Enter`, "Split the current block at cursor position"],
|
[`${modChar} + ${altChar} + Enter`, "Split the current block at cursor position"],
|
||||||
[`${modChar} + L`, "Change block language"],
|
[`${modChar} + L`, "Change block language"],
|
||||||
[`${modChar} + N`, "Create a new note buffer"],
|
[`${modChar} + N`, "Create a new note buffer"],
|
||||||
[`${modChar} + S`, "Create a new note buffer from the current block"],
|
[`${modChar} + S`, "Move the current block to another (or new) buffer"],
|
||||||
[`${modChar} + P`, "Open note selector"],
|
[`${modChar} + P`, "Open note selector"],
|
||||||
[`${modChar} + Down`, "Goto next block"],
|
[`${modChar} + Down`, "Goto next block"],
|
||||||
[`${modChar} + Up`, "Goto previous block"],
|
[`${modChar} + Up`, "Goto previous block"],
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import { useHeynoteStore } from "../stores/heynote-store"
|
import { useHeynoteStore } from "../stores/heynote-store"
|
||||||
import { useErrorStore } from "../stores/error-store"
|
import { useErrorStore } from "../stores/error-store"
|
||||||
import { useSettingsStore } from "../stores/settings-store"
|
import { useSettingsStore } from "../stores/settings-store"
|
||||||
|
import { useEditorCacheStore } from '../stores/editor-cache'
|
||||||
|
|
||||||
import { OPEN_SETTINGS_EVENT, SETTINGS_CHANGE_EVENT } from '@/src/common/constants'
|
import { OPEN_SETTINGS_EVENT, SETTINGS_CHANGE_EVENT } from '@/src/common/constants'
|
||||||
|
|
||||||
@ -55,6 +56,7 @@
|
|||||||
showBufferSelector(value) { this.dialogWatcher(value) },
|
showBufferSelector(value) { this.dialogWatcher(value) },
|
||||||
showCreateBuffer(value) { this.dialogWatcher(value) },
|
showCreateBuffer(value) { this.dialogWatcher(value) },
|
||||||
showEditBuffer(value) { this.dialogWatcher(value) },
|
showEditBuffer(value) { this.dialogWatcher(value) },
|
||||||
|
showMoveToBufferSelector(value) { this.dialogWatcher(value) },
|
||||||
|
|
||||||
currentBufferPath() {
|
currentBufferPath() {
|
||||||
this.focusEditor()
|
this.focusEditor()
|
||||||
@ -66,7 +68,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useSettingsStore),
|
...mapStores(useSettingsStore, useEditorCacheStore),
|
||||||
...mapState(useHeynoteStore, [
|
...mapState(useHeynoteStore, [
|
||||||
"currentBufferPath",
|
"currentBufferPath",
|
||||||
"currentBufferName",
|
"currentBufferName",
|
||||||
@ -74,6 +76,7 @@
|
|||||||
"showBufferSelector",
|
"showBufferSelector",
|
||||||
"showCreateBuffer",
|
"showCreateBuffer",
|
||||||
"showEditBuffer",
|
"showEditBuffer",
|
||||||
|
"showMoveToBufferSelector",
|
||||||
]),
|
]),
|
||||||
|
|
||||||
editorInert() {
|
editorInert() {
|
||||||
@ -89,6 +92,7 @@
|
|||||||
"closeDialog",
|
"closeDialog",
|
||||||
"closeBufferSelector",
|
"closeBufferSelector",
|
||||||
"openBuffer",
|
"openBuffer",
|
||||||
|
"closeMoveToBufferSelector",
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Used as a watcher for the booleans that control the visibility of editor dialogs.
|
// Used as a watcher for the booleans that control the visibility of editor dialogs.
|
||||||
@ -123,6 +127,11 @@
|
|||||||
formatCurrentBlock() {
|
formatCurrentBlock() {
|
||||||
this.$refs.editor.formatCurrentBlock()
|
this.$refs.editor.formatCurrentBlock()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onMoveCurrentBlockToOtherEditor(path) {
|
||||||
|
this.editorCacheStore.moveCurrentBlockToOtherEditor(path)
|
||||||
|
this.closeMoveToBufferSelector()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,8 +166,16 @@
|
|||||||
<BufferSelector
|
<BufferSelector
|
||||||
v-if="showBufferSelector"
|
v-if="showBufferSelector"
|
||||||
@openBuffer="openBuffer"
|
@openBuffer="openBuffer"
|
||||||
|
@openCreateBuffer="(nameSuggestion) => openCreateBuffer('new', nameSuggestion)"
|
||||||
@close="closeBufferSelector"
|
@close="closeBufferSelector"
|
||||||
/>
|
/>
|
||||||
|
<BufferSelector
|
||||||
|
v-if="showMoveToBufferSelector"
|
||||||
|
headline="Move block to..."
|
||||||
|
@openBuffer="onMoveCurrentBlockToOtherEditor"
|
||||||
|
@openCreateBuffer="(nameSuggestion) => openCreateBuffer('currentBlock', nameSuggestion)"
|
||||||
|
@close="closeMoveToBufferSelector"
|
||||||
|
/>
|
||||||
<Settings
|
<Settings
|
||||||
v-if="showSettings"
|
v-if="showSettings"
|
||||||
:initialSettings="settingsStore.settings"
|
:initialSettings="settingsStore.settings"
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
import fuzzysort from 'fuzzysort'
|
import fuzzysort from 'fuzzysort'
|
||||||
|
|
||||||
import { mapState, mapActions } from 'pinia'
|
import { mapState, mapActions } from 'pinia'
|
||||||
import { toRaw } from 'vue';
|
|
||||||
import { SCRATCH_FILE_NAME } from "../common/constants"
|
import { SCRATCH_FILE_NAME } from "../common/constants"
|
||||||
import { useHeynoteStore } from "../stores/heynote-store"
|
import { useHeynoteStore } from "../stores/heynote-store"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
headline: String,
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selected: 0,
|
selected: 0,
|
||||||
@ -94,7 +97,6 @@
|
|||||||
"updateBuffers",
|
"updateBuffers",
|
||||||
"editBufferMetadata",
|
"editBufferMetadata",
|
||||||
"deleteBuffer",
|
"deleteBuffer",
|
||||||
"openCreateBuffer",
|
|
||||||
]),
|
]),
|
||||||
|
|
||||||
buildItems() {
|
buildItems() {
|
||||||
@ -170,9 +172,9 @@
|
|||||||
selectItem(item) {
|
selectItem(item) {
|
||||||
if (item.createNew) {
|
if (item.createNew) {
|
||||||
if (this.filteredItems.length === 1) {
|
if (this.filteredItems.length === 1) {
|
||||||
this.openCreateBuffer("new", this.filter)
|
this.$emit("openCreateBuffer", this.filter)
|
||||||
} else {
|
} else {
|
||||||
this.openCreateBuffer("new", "")
|
this.$emit("openCreateBuffer", "")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$emit("openBuffer", item.path)
|
this.$emit("openBuffer", item.path)
|
||||||
@ -237,6 +239,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<form class="note-selector" tabindex="-1" @focusout="onFocusOut" ref="container">
|
<form class="note-selector" tabindex="-1" @focusout="onFocusOut" ref="container">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
<h1 v-if="headline">{{headline}}</h1>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
ref="input"
|
ref="input"
|
||||||
@ -310,11 +313,15 @@
|
|||||||
+dark-mode
|
+dark-mode
|
||||||
background: #151516
|
background: #151516
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.5)
|
box-shadow: 0 0 10px rgba(0,0,0,0.5)
|
||||||
|
color: rgba(255,255,255, 0.7)
|
||||||
+webapp-mobile
|
+webapp-mobile
|
||||||
max-width: calc(100% - 80px)
|
max-width: calc(100% - 80px)
|
||||||
|
|
||||||
.input-container
|
.input-container
|
||||||
padding: 10px
|
padding: 10px
|
||||||
|
h1
|
||||||
|
font-weight: bold
|
||||||
|
margin-bottom: 14px
|
||||||
input
|
input
|
||||||
background: #fff
|
background: #fff
|
||||||
padding: 4px 5px
|
padding: 4px 5px
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script>
|
<script>
|
||||||
import { HeynoteEditor } from '../editor/editor.js'
|
|
||||||
import { syntaxTree } from "@codemirror/language"
|
import { syntaxTree } from "@codemirror/language"
|
||||||
import { toRaw } from 'vue';
|
import { toRaw } from 'vue';
|
||||||
import { mapState, mapWritableState, mapActions, mapStores } from 'pinia'
|
import { mapState, mapWritableState, mapActions, mapStores } from 'pinia'
|
||||||
@ -28,6 +27,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
// initialize editorCacheStore (sets up watchers for settings changes, propagating them to all editors)
|
||||||
|
this.editorCacheStore.setUp(this.$refs.editor);
|
||||||
|
|
||||||
this.loadBuffer(this.currentBufferPath)
|
this.loadBuffer(this.currentBufferPath)
|
||||||
|
|
||||||
// set up window close handler that will save the buffer and quit
|
// set up window close handler that will save the buffer and quit
|
||||||
@ -46,9 +48,6 @@
|
|||||||
window.heynote.mainProcess.on(WINDOW_CLOSE_EVENT, this.onWindowClose)
|
window.heynote.mainProcess.on(WINDOW_CLOSE_EVENT, this.onWindowClose)
|
||||||
window.heynote.mainProcess.on(REDO_EVENT, this.onRedo)
|
window.heynote.mainProcess.on(REDO_EVENT, this.onRedo)
|
||||||
|
|
||||||
// initialize editorCacheStore (sets up watchers for settings changes, propagating them to all editors)
|
|
||||||
this.editorCacheStore.setUp();
|
|
||||||
|
|
||||||
// if debugSyntaxTree prop is set, display syntax tree for debugging
|
// if debugSyntaxTree prop is set, display syntax tree for debugging
|
||||||
if (this.debugSyntaxTree) {
|
if (this.debugSyntaxTree) {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@ -112,7 +111,7 @@
|
|||||||
toRaw(this.editor).show()
|
toRaw(this.editor).show()
|
||||||
} else {
|
} else {
|
||||||
//console.log("create new editor")
|
//console.log("create new editor")
|
||||||
this.editor = this.editorCacheStore.createEditor(path, this.$refs.editor)
|
this.editor = this.editorCacheStore.createEditor(path)
|
||||||
this.editorCacheStore.addEditor(path, toRaw(this.editor))
|
this.editorCacheStore.addEditor(path, toRaw(this.editor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
dialogTitle() {
|
dialogTitle() {
|
||||||
return this.createBufferParams.mode === "currentBlock" ? "New Buffer from Block" : "New Buffer"
|
return this.createBufferParams.mode === "currentBlock" ? "Move Block to New Buffer" : "New Buffer"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -7,3 +7,4 @@ export const SET_CONTENT = "heynote-set-content"
|
|||||||
export const ADD_NEW_BLOCK = "heynote-add-new-block"
|
export const ADD_NEW_BLOCK = "heynote-add-new-block"
|
||||||
export const DELETE_BLOCK = "heynote-delete-block"
|
export const DELETE_BLOCK = "heynote-delete-block"
|
||||||
export const CURSOR_CHANGE = "heynote-cursor-change"
|
export const CURSOR_CHANGE = "heynote-cursor-change"
|
||||||
|
export const APPEND_BLOCK = "heynote-append-block"
|
||||||
|
@ -169,8 +169,9 @@ const blockLayer = layer({
|
|||||||
idx++;
|
idx++;
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const fromCoordsTop = view.coordsAtPos(Math.max(block.content.from, view.visibleRanges[0].from)).top
|
// view.coordsAtPos returns null if the editor is not visible
|
||||||
let toCoordsBottom = view.coordsAtPos(Math.min(block.content.to, view.visibleRanges[view.visibleRanges.length - 1].to)).bottom
|
const fromCoordsTop = view.coordsAtPos(Math.max(block.content.from, view.visibleRanges[0].from))?.top
|
||||||
|
let toCoordsBottom = view.coordsAtPos(Math.min(block.content.to, view.visibleRanges[view.visibleRanges.length - 1].to))?.bottom
|
||||||
if (idx === blocks.length - 1) {
|
if (idx === blocks.length - 1) {
|
||||||
// Calculate how much extra height we need to add to the last block
|
// Calculate how much extra height we need to add to the last block
|
||||||
let extraHeight = view.viewState.editorHeight - (
|
let extraHeight = view.viewState.editorHeight - (
|
||||||
|
@ -12,7 +12,7 @@ import { getFontTheme } from "./theme/font-theme.js";
|
|||||||
import { customSetup } from "./setup.js"
|
import { customSetup } from "./setup.js"
|
||||||
import { heynoteLang } from "./lang-heynote/heynote.js"
|
import { heynoteLang } from "./lang-heynote/heynote.js"
|
||||||
import { noteBlockExtension, blockLineNumbers, blockState, getActiveNoteBlock, triggerCursorChange } from "./block/block.js"
|
import { noteBlockExtension, blockLineNumbers, blockState, getActiveNoteBlock, triggerCursorChange } from "./block/block.js"
|
||||||
import { heynoteEvent, SET_CONTENT, DELETE_BLOCK } from "./annotation.js";
|
import { heynoteEvent, SET_CONTENT, DELETE_BLOCK, APPEND_BLOCK } from "./annotation.js";
|
||||||
import { changeCurrentBlockLanguage, triggerCurrenciesLoaded, getBlockDelimiter, deleteBlock } from "./block/commands.js"
|
import { changeCurrentBlockLanguage, triggerCurrenciesLoaded, getBlockDelimiter, deleteBlock } from "./block/commands.js"
|
||||||
import { formatBlockContent } from "./block/format-code.js"
|
import { formatBlockContent } from "./block/format-code.js"
|
||||||
import { heynoteKeymap } from "./keymap.js"
|
import { heynoteKeymap } from "./keymap.js"
|
||||||
@ -127,7 +127,8 @@ export class HeynoteEditor {
|
|||||||
|
|
||||||
//this.setContent(content)
|
//this.setContent(content)
|
||||||
this.setReadOnly(true)
|
this.setReadOnly(true)
|
||||||
this.loadContent().then(() => {
|
this.contentLoadedPromise = this.loadContent();
|
||||||
|
this.contentLoadedPromise.then(() => {
|
||||||
this.setReadOnly(false)
|
this.setReadOnly(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -166,7 +167,6 @@ export class HeynoteEditor {
|
|||||||
const content = await window.heynote.buffer.load(this.path)
|
const content = await window.heynote.buffer.load(this.path)
|
||||||
this.diskContent = content
|
this.diskContent = content
|
||||||
this.contentLoaded = true
|
this.contentLoaded = true
|
||||||
this.setContent(content)
|
|
||||||
|
|
||||||
// set up content change listener
|
// set up content change listener
|
||||||
this.onChange = (content) => {
|
this.onChange = (content) => {
|
||||||
@ -174,6 +174,8 @@ export class HeynoteEditor {
|
|||||||
this.setContent(content)
|
this.setContent(content)
|
||||||
}
|
}
|
||||||
window.heynote.buffer.addOnChangeCallback(this.path, this.onChange)
|
window.heynote.buffer.addOnChangeCallback(this.path, this.onChange)
|
||||||
|
|
||||||
|
await this.setContent(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent(content) {
|
setContent(content) {
|
||||||
@ -278,6 +280,10 @@ export class HeynoteEditor {
|
|||||||
this.notesStore.openCreateBuffer(createMode)
|
this.notesStore.openCreateBuffer(createMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openMoveToBufferSelector() {
|
||||||
|
this.notesStore.openMoveToBufferSelector()
|
||||||
|
}
|
||||||
|
|
||||||
async createNewBuffer(path, name) {
|
async createNewBuffer(path, name) {
|
||||||
const data = getBlockDelimiter(this.defaultBlockToken, this.defaultBlockAutoDetect)
|
const data = getBlockDelimiter(this.defaultBlockToken, this.defaultBlockAutoDetect)
|
||||||
await this.notesStore.saveNewBuffer(path, name, data)
|
await this.notesStore.saveNewBuffer(path, name, data)
|
||||||
@ -302,8 +308,35 @@ export class HeynoteEditor {
|
|||||||
// by using requestAnimationFrame we avoid a race condition where rendering the block backgrounds
|
// by using requestAnimationFrame we avoid a race condition where rendering the block backgrounds
|
||||||
// would fail if we immediately opened the new note (since the block UI wouldn't have time to update
|
// would fail if we immediately opened the new note (since the block UI wouldn't have time to update
|
||||||
// after the block was deleted)
|
// after the block was deleted)
|
||||||
requestAnimationFrame(() => {
|
//requestAnimationFrame(() => {
|
||||||
this.notesStore.openBuffer(path)
|
// this.notesStore.openBuffer(path)
|
||||||
|
//})
|
||||||
|
|
||||||
|
// add new buffer to recent list so that it shows up at the top of the buffer selector
|
||||||
|
this.notesStore.addRecentBuffer(path)
|
||||||
|
this.notesStore.addRecentBuffer(this.notesStore.currentBufferPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
getActiveBlockContent() {
|
||||||
|
const block = getActiveNoteBlock(this.view.state)
|
||||||
|
if (!block) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return this.view.state.sliceDoc(block.range.from, block.range.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteActiveBlock() {
|
||||||
|
deleteBlock(this)(this.view)
|
||||||
|
}
|
||||||
|
|
||||||
|
appendBlockContent(content) {
|
||||||
|
this.view.dispatch({
|
||||||
|
changes: {
|
||||||
|
from: this.view.state.doc.length,
|
||||||
|
to: this.view.state.doc.length,
|
||||||
|
insert: content,
|
||||||
|
},
|
||||||
|
annotations: [heynoteEvent.of(APPEND_BLOCK)],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export function heynoteKeymap(editor) {
|
|||||||
["Alt-ArrowDown", moveLineDown],
|
["Alt-ArrowDown", moveLineDown],
|
||||||
["Mod-l", () => editor.openLanguageSelector()],
|
["Mod-l", () => editor.openLanguageSelector()],
|
||||||
["Mod-p", () => editor.openBufferSelector()],
|
["Mod-p", () => editor.openBufferSelector()],
|
||||||
["Mod-s", () => editor.openCreateBuffer("currentBlock")],
|
["Mod-s", () => editor.openMoveToBufferSelector()],
|
||||||
["Mod-n", () => editor.openCreateBuffer("new")],
|
["Mod-n", () => editor.openCreateBuffer("new")],
|
||||||
["Mod-Shift-d", deleteBlock(editor)],
|
["Mod-Shift-d", deleteBlock(editor)],
|
||||||
["Alt-Shift-f", formatBlockContent],
|
["Alt-Shift-f", formatBlockContent],
|
||||||
|
@ -7,7 +7,6 @@ import App from './components/App.vue'
|
|||||||
import { loadCurrencies } from './currency'
|
import { loadCurrencies } from './currency'
|
||||||
import { useErrorStore } from './stores/error-store'
|
import { useErrorStore } from './stores/error-store'
|
||||||
import { useHeynoteStore, initHeynoteStore } from './stores/heynote-store'
|
import { useHeynoteStore, initHeynoteStore } from './stores/heynote-store'
|
||||||
import { useEditorCacheStore } from './stores/editor-cache'
|
|
||||||
|
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
@ -20,7 +19,6 @@ app.mount('#app').$nextTick(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const errorStore = useErrorStore()
|
const errorStore = useErrorStore()
|
||||||
const editorCacheStore = useEditorCacheStore()
|
|
||||||
//errorStore.addError("test error")
|
//errorStore.addError("test error")
|
||||||
window.heynote.getInitErrors().then((errors) => {
|
window.heynote.getInitErrors().then((errors) => {
|
||||||
errors.forEach((e) => errorStore.addError(e))
|
errors.forEach((e) => errorStore.addError(e))
|
||||||
|
@ -4,6 +4,7 @@ import { NoteFormat } from "../common/note-format"
|
|||||||
|
|
||||||
import { useSettingsStore } from './settings-store'
|
import { useSettingsStore } from './settings-store'
|
||||||
import { useErrorStore } from './error-store'
|
import { useErrorStore } from './error-store'
|
||||||
|
import { useHeynoteStore } from './heynote-store'
|
||||||
import { HeynoteEditor } from '../editor/editor'
|
import { HeynoteEditor } from '../editor/editor'
|
||||||
|
|
||||||
const NUM_EDITOR_INSTANCES = 5
|
const NUM_EDITOR_INSTANCES = 5
|
||||||
@ -15,16 +16,17 @@ export const useEditorCacheStore = defineStore("editorCache", {
|
|||||||
cache: {},
|
cache: {},
|
||||||
watchHandler: null,
|
watchHandler: null,
|
||||||
themeWatchHandler: null,
|
themeWatchHandler: null,
|
||||||
|
containerElement: null,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
createEditor(path, element) {
|
createEditor(path) {
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
const errorStore = useErrorStore()
|
const errorStore = useErrorStore()
|
||||||
try {
|
try {
|
||||||
return new HeynoteEditor({
|
return new HeynoteEditor({
|
||||||
element: element,
|
element: this.containerElement,
|
||||||
path: path,
|
path: path,
|
||||||
theme: settingsStore.theme,
|
theme: settingsStore.theme,
|
||||||
keymap: settingsStore.settings.keymap,
|
keymap: settingsStore.settings.keymap,
|
||||||
@ -43,11 +45,29 @@ export const useEditorCacheStore = defineStore("editorCache", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getOrCreateEditor(path, updateLru) {
|
||||||
|
if (updateLru) {
|
||||||
|
// move to end of LRU
|
||||||
|
this.editorCache.lru = this.editorCache.lru.filter(p => p !== path)
|
||||||
|
this.editorCache.lru.push(path)
|
||||||
|
}
|
||||||
|
if (this.editorCache.cache[path]) {
|
||||||
|
return this.editorCache.cache[path]
|
||||||
|
} else {
|
||||||
|
const editor = this.createEditor(path)
|
||||||
|
this.addEditor(path, editor)
|
||||||
|
if (!updateLru) {
|
||||||
|
// if need to add the editor to the LRU, but at the top so that it is the first to be removed
|
||||||
|
this.editorCache.lru.unshift(path)
|
||||||
|
}
|
||||||
|
return editor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getEditor(path) {
|
getEditor(path) {
|
||||||
// move to end of LRU
|
// move to end of LRU
|
||||||
this.editorCache.lru = this.editorCache.lru.filter(p => p !== path)
|
this.editorCache.lru = this.editorCache.lru.filter(p => p !== path)
|
||||||
this.editorCache.lru.push(path)
|
this.editorCache.lru.push(path)
|
||||||
|
|
||||||
if (this.editorCache.cache[path]) {
|
if (this.editorCache.cache[path]) {
|
||||||
return this.editorCache.cache[path]
|
return this.editorCache.cache[path]
|
||||||
}
|
}
|
||||||
@ -90,7 +110,8 @@ export const useEditorCacheStore = defineStore("editorCache", {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setUp() {
|
setUp(containerElement) {
|
||||||
|
this.containerElement = containerElement
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
this.watchHandler = watch(() => settingsStore.settings, (newSettings, oldSettings) => {
|
this.watchHandler = watch(() => settingsStore.settings, (newSettings, oldSettings) => {
|
||||||
//console.log("Settings changed (watch)", newSettings, oldSettings)
|
//console.log("Settings changed (watch)", newSettings, oldSettings)
|
||||||
@ -144,5 +165,25 @@ export const useEditorCacheStore = defineStore("editorCache", {
|
|||||||
|
|
||||||
window.document.removeEventListener("currenciesLoaded", this.onCurrenciesLoaded)
|
window.document.removeEventListener("currenciesLoaded", this.onCurrenciesLoaded)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
moveCurrentBlockToOtherEditor(targetPath) {
|
||||||
|
const heynoteStore = useHeynoteStore()
|
||||||
|
|
||||||
|
const editor = toRaw(this.getEditor(heynoteStore.currentBufferPath))
|
||||||
|
let otherEditor = toRaw(this.getOrCreateEditor(targetPath, false))
|
||||||
|
otherEditor.hide()
|
||||||
|
|
||||||
|
const content = editor.getActiveBlockContent()
|
||||||
|
otherEditor.contentLoadedPromise.then(() => {
|
||||||
|
otherEditor.appendBlockContent(content)
|
||||||
|
editor.deleteActiveBlock()
|
||||||
|
|
||||||
|
// add the target buffer to recent buffers so that it shows up at the top of the buffer selector
|
||||||
|
heynoteStore.addRecentBuffer(targetPath)
|
||||||
|
heynoteStore.addRecentBuffer(heynoteStore.currentBufferPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
//console.log("LRU", this.editorCache.lru)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -27,6 +27,7 @@ export const useHeynoteStore = defineStore("heynote", {
|
|||||||
showLanguageSelector: false,
|
showLanguageSelector: false,
|
||||||
showCreateBuffer: false,
|
showCreateBuffer: false,
|
||||||
showEditBuffer: false,
|
showEditBuffer: false,
|
||||||
|
showMoveToBufferSelector: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@ -41,7 +42,10 @@ export const useHeynoteStore = defineStore("heynote", {
|
|||||||
openBuffer(path) {
|
openBuffer(path) {
|
||||||
this.closeDialog()
|
this.closeDialog()
|
||||||
this.currentBufferPath = path
|
this.currentBufferPath = path
|
||||||
|
this.addRecentBuffer(path)
|
||||||
|
},
|
||||||
|
|
||||||
|
addRecentBuffer(path) {
|
||||||
const recent = this.recentBufferPaths.filter((p) => p !== path)
|
const recent = this.recentBufferPaths.filter((p) => p !== path)
|
||||||
recent.unshift(path)
|
recent.unshift(path)
|
||||||
this.recentBufferPaths = recent.slice(0, 100)
|
this.recentBufferPaths = recent.slice(0, 100)
|
||||||
@ -55,6 +59,10 @@ export const useHeynoteStore = defineStore("heynote", {
|
|||||||
this.closeDialog()
|
this.closeDialog()
|
||||||
this.showBufferSelector = true
|
this.showBufferSelector = true
|
||||||
},
|
},
|
||||||
|
openMoveToBufferSelector() {
|
||||||
|
this.closeDialog()
|
||||||
|
this.showMoveToBufferSelector = true
|
||||||
|
},
|
||||||
openCreateBuffer(createMode, nameSuggestion) {
|
openCreateBuffer(createMode, nameSuggestion) {
|
||||||
createMode = createMode || "new"
|
createMode = createMode || "new"
|
||||||
this.closeDialog()
|
this.closeDialog()
|
||||||
@ -69,12 +77,17 @@ export const useHeynoteStore = defineStore("heynote", {
|
|||||||
this.showBufferSelector = false
|
this.showBufferSelector = false
|
||||||
this.showLanguageSelector = false
|
this.showLanguageSelector = false
|
||||||
this.showEditBuffer = false
|
this.showEditBuffer = false
|
||||||
|
this.showMoveToBufferSelector = false
|
||||||
},
|
},
|
||||||
|
|
||||||
closeBufferSelector() {
|
closeBufferSelector() {
|
||||||
this.showBufferSelector = false
|
this.showBufferSelector = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
closeMoveToBufferSelector() {
|
||||||
|
this.showMoveToBufferSelector = false
|
||||||
|
},
|
||||||
|
|
||||||
editBufferMetadata(path) {
|
editBufferMetadata(path) {
|
||||||
if (this.currentBufferPath !== path) {
|
if (this.currentBufferPath !== path) {
|
||||||
this.openBuffer(path)
|
this.openBuffer(path)
|
||||||
|
@ -3,7 +3,7 @@ import {HeynotePage} from "./test-utils.js";
|
|||||||
|
|
||||||
import { AUTO_SAVE_INTERVAL } from "../src/common/constants.js"
|
import { AUTO_SAVE_INTERVAL } from "../src/common/constants.js"
|
||||||
import { NoteFormat } from "../src/common/note-format.js"
|
import { NoteFormat } from "../src/common/note-format.js"
|
||||||
import exp from "constants";
|
|
||||||
|
|
||||||
let heynotePage
|
let heynotePage
|
||||||
|
|
||||||
@ -40,11 +40,12 @@ test("default buffer saved", async ({page}) => {
|
|||||||
test("create new buffer from block", async ({page}) => {
|
test("create new buffer from block", async ({page}) => {
|
||||||
await page.locator("body").press(heynotePage.agnosticKey("Mod+S"))
|
await page.locator("body").press(heynotePage.agnosticKey("Mod+S"))
|
||||||
await page.waitForTimeout(50)
|
await page.waitForTimeout(50)
|
||||||
|
await page.locator("body").press("ArrowUp")
|
||||||
|
await page.locator("body").press("Enter")
|
||||||
|
await page.waitForTimeout(50)
|
||||||
await page.locator("body").pressSequentially("My New Buffer")
|
await page.locator("body").pressSequentially("My New Buffer")
|
||||||
await page.locator("body").press("Enter")
|
await page.locator("body").press("Enter")
|
||||||
await page.waitForTimeout(150)
|
await page.waitForTimeout(150)
|
||||||
await page.locator("body").press("Enter")
|
|
||||||
await page.locator("body").pressSequentially("New buffer content")
|
|
||||||
await page.waitForTimeout(AUTO_SAVE_INTERVAL + 50);
|
await page.waitForTimeout(AUTO_SAVE_INTERVAL + 50);
|
||||||
|
|
||||||
const buffers = Object.keys(await heynotePage.getStoredBufferList())
|
const buffers = Object.keys(await heynotePage.getStoredBufferList())
|
||||||
@ -62,8 +63,7 @@ Block B`)
|
|||||||
|
|
||||||
expect(newBuffer.content).toBe(`
|
expect(newBuffer.content).toBe(`
|
||||||
∞∞∞text
|
∞∞∞text
|
||||||
Block C
|
Block C`)
|
||||||
New buffer content`)
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
101
tests/move-block.spec.js
Normal file
101
tests/move-block.spec.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import {expect, test} from "@playwright/test";
|
||||||
|
import {HeynotePage} from "./test-utils.js";
|
||||||
|
|
||||||
|
import { AUTO_SAVE_INTERVAL } from "../src/common/constants.js"
|
||||||
|
import { NoteFormat } from "../src/common/note-format.js"
|
||||||
|
|
||||||
|
|
||||||
|
let heynotePage
|
||||||
|
|
||||||
|
test.beforeEach(async ({page}) => {
|
||||||
|
heynotePage = new HeynotePage(page)
|
||||||
|
await heynotePage.goto()
|
||||||
|
|
||||||
|
expect((await heynotePage.getBlocks()).length).toBe(1)
|
||||||
|
await heynotePage.setContent(`
|
||||||
|
∞∞∞text
|
||||||
|
Block A
|
||||||
|
∞∞∞text
|
||||||
|
Block B
|
||||||
|
∞∞∞text
|
||||||
|
Block C`)
|
||||||
|
await page.waitForTimeout(100);
|
||||||
|
// check that blocks are created
|
||||||
|
expect((await heynotePage.getBlocks()).length).toBe(3)
|
||||||
|
|
||||||
|
// check that visual block layers are created
|
||||||
|
await expect(page.locator("css=.heynote-blocks-layer > div")).toHaveCount(3)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("move block to other buffer", async ({page}) => {
|
||||||
|
await heynotePage.saveBuffer("other.txt", `
|
||||||
|
∞∞∞text-a
|
||||||
|
First block
|
||||||
|
∞∞∞math
|
||||||
|
Second block`)
|
||||||
|
await page.locator("body").press(heynotePage.agnosticKey("Mod+S"))
|
||||||
|
await page.waitForTimeout(50)
|
||||||
|
await page.locator("body").press("Enter")
|
||||||
|
await page.waitForTimeout(AUTO_SAVE_INTERVAL + 50);
|
||||||
|
|
||||||
|
const buffers = Object.keys(await heynotePage.getStoredBufferList())
|
||||||
|
expect(buffers).toContain("other.txt")
|
||||||
|
|
||||||
|
const otherBuffer = NoteFormat.load(await heynotePage.getStoredBuffer("other.txt"))
|
||||||
|
|
||||||
|
expect(await heynotePage.getContent()).toBe(`
|
||||||
|
∞∞∞text
|
||||||
|
Block A
|
||||||
|
∞∞∞text
|
||||||
|
Block B`)
|
||||||
|
|
||||||
|
expect(otherBuffer.content).toBe(`
|
||||||
|
∞∞∞text-a
|
||||||
|
First block
|
||||||
|
∞∞∞math
|
||||||
|
Second block
|
||||||
|
∞∞∞text
|
||||||
|
Block C`)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test("move block to other open/cached buffer", async ({page}) => {
|
||||||
|
await heynotePage.saveBuffer("other.txt", `
|
||||||
|
∞∞∞text-a
|
||||||
|
First block
|
||||||
|
∞∞∞math
|
||||||
|
Second block`)
|
||||||
|
await page.locator("body").press(heynotePage.agnosticKey("Mod+P"))
|
||||||
|
await page.locator("body").press("Enter")
|
||||||
|
await page.waitForTimeout(50)
|
||||||
|
await page.locator("body").press(heynotePage.agnosticKey("Mod+P"))
|
||||||
|
await page.locator("body").press("Enter")
|
||||||
|
await page.waitForTimeout(50)
|
||||||
|
await page.locator("body").press(heynotePage.agnosticKey("Mod+S"))
|
||||||
|
await page.waitForTimeout(50)
|
||||||
|
await page.locator("body").press("Enter")
|
||||||
|
await page.waitForTimeout(AUTO_SAVE_INTERVAL + 50);
|
||||||
|
|
||||||
|
const buffers = Object.keys(await heynotePage.getStoredBufferList())
|
||||||
|
expect(buffers).toContain("other.txt")
|
||||||
|
|
||||||
|
const otherBuffer = NoteFormat.load(await heynotePage.getStoredBuffer("other.txt"))
|
||||||
|
|
||||||
|
expect(await heynotePage.getContent()).toBe(`
|
||||||
|
∞∞∞text
|
||||||
|
Block A
|
||||||
|
∞∞∞text
|
||||||
|
Block B`)
|
||||||
|
|
||||||
|
expect(otherBuffer.content).toBe(`
|
||||||
|
∞∞∞text-a
|
||||||
|
First block
|
||||||
|
∞∞∞math
|
||||||
|
Second block
|
||||||
|
∞∞∞text
|
||||||
|
Block C`)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
@ -38,7 +38,10 @@ export class HeynotePage {
|
|||||||
|
|
||||||
async setContent(content) {
|
async setContent(content) {
|
||||||
await expect(this.page.locator("css=.cm-editor")).toBeVisible()
|
await expect(this.page.locator("css=.cm-editor")).toBeVisible()
|
||||||
await this.page.evaluate((content) => window._heynote_editor.setContent(content), content)
|
await this.page.evaluate(async (content) => {
|
||||||
|
await window._heynote_editor.setContent(content)
|
||||||
|
await window._heynote_editor.save()
|
||||||
|
}, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCursorPosition() {
|
async getCursorPosition() {
|
||||||
@ -65,6 +68,12 @@ export class HeynotePage {
|
|||||||
return await this.page.evaluate((path) => window.heynote.buffer.load(path), path)
|
return await this.page.evaluate((path) => window.heynote.buffer.load(path), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async saveBuffer(path, content) {
|
||||||
|
const format = new NoteFormat()
|
||||||
|
format.content = content
|
||||||
|
await this.page.evaluate(({path, content}) => window.heynote.buffer.save(path, content), {path, content:format.serialize()})
|
||||||
|
}
|
||||||
|
|
||||||
agnosticKey(key) {
|
agnosticKey(key) {
|
||||||
return key.replace("Mod", this.isMac ? "Meta" : "Control")
|
return key.replace("Mod", this.isMac ? "Meta" : "Control")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user