Implement document linking feature for @ keypress.

This commit is contained in:
Gáspár József Dániel 2023-05-13 13:21:11 +02:00
parent d77daf8d65
commit 545ab74066
4 changed files with 119 additions and 21 deletions

View file

@ -102,7 +102,6 @@ import PouchDB from "pouchdb"
import { OptionsStateInteface } from "./store/module-options/state" import { OptionsStateInteface } from "./store/module-options/state"
import { colors } from "quasar" import { colors } from "quasar"
import { tipsTricks } from "src/scripts/utilities/tipsTricks" import { tipsTricks } from "src/scripts/utilities/tipsTricks"
import { shell } from "electron"
import { summonAllPlusheForms } from "src/scripts/utilities/plusheMascot" import { summonAllPlusheForms } from "src/scripts/utilities/plusheMascot"
import { saveCorkboard, retrieveCorkboard, retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent" import { saveCorkboard, retrieveCorkboard, retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent"
import documentPreview from "src/components/DocumentPreview.vue" import documentPreview from "src/components/DocumentPreview.vue"
@ -287,24 +286,9 @@ export default class App extends BaseClass {
// @ts-ignore // @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-call // eslint-disable-next-line @typescript-eslint/no-unsafe-call
if (event.target && event.target.tagName.toLowerCase() === "a" && event.target.closest(".fieldWysiwyg")) { if (event.target && event.target.tagName.toLowerCase() === "a" && event.target.closest(".fieldWysiwyg")) {
try { // @ts-ignore
// @ts-ignore this.openLink(event.target.href as string)
const url = new URL(event.target.href as string) // @ts-ignore
// @ts-ignore
console.log(url)
if (url.protocol === "http:" || url.protocol === "https:") {
shell.openExternal(url.href).catch(e => console.log(e))
}
else if (url.protocol === "document:") {
const doc = this.SGET_document(url.pathname)
/* eslint-disable */
this.openExistingDocumentRoute(doc)
/* eslint-enable */
}
}
catch (_) {
}
} }
} }

View file

@ -9,6 +9,7 @@ import { uid, colors, extend } from "quasar"
import { I_FieldRelationship } from "src/interfaces/I_FieldRelationship" import { I_FieldRelationship } from "src/interfaces/I_FieldRelationship"
import { I_KeyPressObject } from "src/interfaces/I_KeypressObject" import { I_KeyPressObject } from "src/interfaces/I_KeypressObject"
import { ProjectInterface } from "./store/module-project/state" import { ProjectInterface } from "./store/module-project/state"
import { shell } from "electron"
const Blueprints = namespace("blueprintsModule") const Blueprints = namespace("blueprintsModule")
const AllDocuments = namespace("allDocumentsModule") const AllDocuments = namespace("allDocumentsModule")
@ -678,4 +679,25 @@ export default class BaseClass extends Vue {
return hasLegacyValue return hasLegacyValue
}) })
} }
openLink (link: string) {
try {
// @ts-ignore
const url = new URL(link)
// @ts-ignore
console.log(url)
if (url.protocol === "http:" || url.protocol === "https:") {
shell.openExternal(url.href).catch(e => console.log(e))
}
else if (url.protocol === "document:") {
const doc = this.SGET_document(url.pathname)
/* eslint-disable */
this.openExistingDocumentRoute(doc)
/* eslint-enable */
}
}
catch (_) {
}
}
} }

View file

@ -241,7 +241,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Watch } from "vue-property-decorator" import { Component, Emit, Prop, Watch } from "vue-property-decorator"
import { I_OpenedDocument, I_ShortenedDocument } from "src/interfaces/I_OpenedDocument" import { I_OpenedDocument, I_ShortenedDocument } from "src/interfaces/I_OpenedDocument"
import { advancedDocumentFilter } from "src/scripts/utilities/advancedDocumentFilter" import { advancedDocumentFilter } from "src/scripts/utilities/advancedDocumentFilter"
import { extend, uid } from "quasar" import { extend, uid } from "quasar"
@ -260,6 +260,10 @@ import documentPreview from "src/components/DocumentPreview.vue"
} }
}) })
export default class ExistingDocumentDialog extends DialogBase { export default class ExistingDocumentDialog extends DialogBase {
@Prop({
default: false
}) readonly preventOpen!: boolean
/****************************************************************/ /****************************************************************/
// DIALOG CONTROL // DIALOG CONTROL
/****************************************************************/ /****************************************************************/
@ -490,6 +494,17 @@ export default class ExistingDocumentDialog extends DialogBase {
openExistingInput (e: I_ShortenedDocument) { openExistingInput (e: I_ShortenedDocument) {
// @ts-ignore // @ts-ignore
e = (Array.isArray(e)) ? e[0] : e e = (Array.isArray(e)) ? e[0] : e
// Signal to any listeners that care about this document being opened
this.signalDocumentSelected(e._id)
// If the caller doesn't want to open the document, don't actually open the document
if (this.preventOpen) {
this.dialogModel = false
this.existingDocumentModel = []
return
}
// Open document and close dialog // Open document and close dialog
if (!this.disableCloseAftertSelectQuickSearch) { if (!this.disableCloseAftertSelectQuickSearch) {
this.dialogModel = false this.dialogModel = false
@ -618,6 +633,12 @@ export default class ExistingDocumentDialog extends DialogBase {
this.SSET_setExportDialogState([node._id]) this.SSET_setExportDialogState([node._id])
} }
// Runs when a document would be opened by this dialog
@Emit()
signalDocumentSelected (document: string) {
return document
}
} }
</script> </script>

View file

@ -1,5 +1,14 @@
<template> <template>
<div> <div>
<template v-if="editMode">
<existingDocumentDialog
preventOpen="true"
:dialog-trigger="existingObjectDialogTrigger"
@trigger-dialog-close="existingObjectDialogClose"
@signal-document-selected="handleDocumentSelected"
/>
</template>
<div class="flex justify-center items-center text-weight-bolder q-mb-sm q-mt-md fieldWysiwygTitle"> <div class="flex justify-center items-center text-weight-bolder q-mb-sm q-mt-md fieldWysiwygTitle">
<span> <span>
<q-icon v-if="inputIcon" :name="inputIcon" :size="(inputIcon.includes('fas') || inputIcon.includes('fab'))? '15px': '20px'" class="q-mr-md"/> <q-icon v-if="inputIcon" :name="inputIcon" :size="(inputIcon.includes('fas') || inputIcon.includes('fab'))? '15px': '20px'" class="q-mr-md"/>
@ -29,6 +38,8 @@
v-if="editMode" v-if="editMode"
:definitions="definitions" :definitions="definitions"
min-height="350px" min-height="350px"
@keypress.native="handleEditorKeypress"
@click.native="handleEditorClick"
/> />
<div class="separatorWrapper"> <div class="separatorWrapper">
@ -43,9 +54,12 @@
import { Component, Emit, Prop, Watch } from "vue-property-decorator" import { Component, Emit, Prop, Watch } from "vue-property-decorator"
import FieldBase from "src/components/fields/_FieldBase" import FieldBase from "src/components/fields/_FieldBase"
import { QEditor } from "quasar"
@Component({ @Component({
components: { } components: {
existingDocumentDialog: () => import("src/components/dialogs/ExistingDocument.vue")
}
}) })
export default class Field_Wysiwyg extends FieldBase { export default class Field_Wysiwyg extends FieldBase {
/****************************************************************/ /****************************************************************/
@ -145,6 +159,63 @@ export default class Field_Wysiwyg extends FieldBase {
/* eslint-enable */ /* eslint-enable */
} }
existingObjectDialogTrigger: string | false = false
handleDocumentSelected (id: string) {
/*eslint-disable */
const editor = this.$refs[`wysiwygField${this.inputDataBluePrint.id}`] as any
editor.focus()
const doc = this.SGET_document(id)
// We need to timeout here to give time to the runtime to focus the editor.
// when focused the caret will return to it's previous position and we can insert the document link
setTimeout(() => {
editor.runCmd("insertHtml", `<a href="document:${id}">${doc.label}<a/>`)
}, 1)
/* eslint-enable */
}
existingObjectDialogClose () {
this.existingObjectDialogTrigger = false
}
existingObjectAssignUID () {
this.existingObjectDialogTrigger = this.generateUID()
}
handleEditorKeypress (evt: any) {
/*eslint-disable */
if (evt.key === '@' && this.editMode) {
const editor = this.$refs[`wysiwygField${this.inputDataBluePrint.id}`] as QEditor
// We don't want to paste anything special in the source mode editor, let the user do their thing
if ((editor as any).isViewingSource)
return;
// Prevent showing up `@` character
evt.preventDefault()
// Open the selector dialog
this.existingObjectAssignUID()
}
/* eslint-enable */
}
handleEditorClick (evt: any) {
/*eslint-disable */
if (evt.target.tagName.toLowerCase() === 'a') {
// Only follow links when ctrl is pressed
if (evt.ctrlKey) {
const link = evt.target.href
console.log(link)
console.log(evt.target.tagName)
evt.stopPropagation()
this.openLink(link)
}
}
/* eslint-enable */
}
/** /**
* Subsitution strings for toolbar * Subsitution strings for toolbar
*/ */