1
0
Fork 0
mirror of https://github.com/Findus23/RPGnotes.git synced 2024-09-19 15:43:45 +02:00

autocomplete names in the editor

This commit is contained in:
Lukas Winkler 2024-08-07 23:37:26 +02:00
parent 3609095a4e
commit 46388002f5
Signed by: lukas
GPG key ID: 54DE4D798D244853
4 changed files with 130 additions and 30 deletions

View file

@ -4,4 +4,5 @@ from common import views
urlpatterns = [ urlpatterns = [
path("api/draft/save", views.save_draft, name="save_draft"), path("api/draft/save", views.save_draft, name="save_draft"),
path("api/suggestions",views.name_completions,name="name_completions"),
] ]

View file

@ -7,7 +7,12 @@ from django.views.generic import TemplateView
from ipware import get_client_ip from ipware import get_client_ip
from sentry_sdk import last_event_id from sentry_sdk import last_event_id
from characters.models import Character
from common.models import Draft from common.models import Draft
from factions.models import Faction
from locations.models import Location
from loot.models import Loot
from notes.models import Note
from rpg_notes.secrets import SENTRY_DSN from rpg_notes.secrets import SENTRY_DSN
from utils.assets import get_css, get_file_hash from utils.assets import get_css, get_file_hash
@ -51,6 +56,42 @@ def save_draft(request: HttpRequest) -> HttpResponse:
}) })
def name_completions(request: HttpRequest) -> HttpResponse:
response_data = []
for obj in (list(Location.objects.all()) +
list(Note.objects.all()) +
list(Faction.objects.all()) +
list(Loot.objects.all())):
response_data.append({
"name": obj.name
})
if obj.aliases:
for alias in obj.aliases:
response_data.append({
"name": alias,
"details":obj.name
})
for char in Character.objects.all():
response_data.append({
"name": char.name,
"details": char.subtitle
})
if char.aliases:
for alias in char.aliases:
response_data.append({
"name": alias,
"details":char.name
})
response = JsonResponse({
"suggestions": response_data
})
response['Cache-Control'] = f'max-age={24 * 60 * 60}'
return response
@condition(etag_func=calc_etag) @condition(etag_func=calc_etag)
def debug_css(request: HttpRequest) -> HttpResponse: def debug_css(request: HttpRequest) -> HttpResponse:
css, source_map = get_css(debug=True) css, source_map = get_css(debug=True)

View file

@ -1,6 +1,12 @@
import {EditorView, minimalSetup} from "codemirror" import {EditorView, minimalSetup} from "codemirror"
import {markdownLanguage} from "@codemirror/lang-markdown" import {markdown, markdownLanguage} from "@codemirror/lang-markdown"
import {foldGutter} from "@codemirror/language"; import {foldGutter} from "@codemirror/language";
import {
autocompletion,
Completion,
CompletionContext,
CompletionResult
} from "@codemirror/autocomplete"
interface DraftSaveResponse { interface DraftSaveResponse {
message: string message: string
@ -25,6 +31,53 @@ ids.forEach(function (id) {
// color: "red", // color: "red",
// colorLight: "lightred" // colorLight: "lightred"
// }) // })
interface Element {
name: string,
details?: string
}
interface HTTPResponse {
suggestions: Element[]
}
let names: Element[] = []
fetch("/api/suggestions", {})
.then(response => response.json())
.then((data: HTTPResponse) => {
names = data.suggestions
})
function myCompletions(context: CompletionContext): CompletionResult | null {
if (names.length == 0) {
return null
}
let word
if (!context.explicit) {
word = context.matchBefore(/@\w*/)
} else {
word = context.matchBefore(/\w*/)
}
if (!word) {
return null
}
if (word.from == word.to)
return null
const options = names.map((s: Element): Completion => ({
label: "@" + s.name,
apply: s.name,
displayLabel: s.name,
detail: s.details
}))
return {
from: word.from,
options: options
}
}
const labelEl = element.labels[0] const labelEl = element.labels[0]
const div = document.createElement("div") const div = document.createElement("div")
element.style.display = "none" element.style.display = "none"
@ -33,7 +86,11 @@ ids.forEach(function (id) {
extensions: [ extensions: [
minimalSetup, minimalSetup,
foldGutter(), foldGutter(),
markdownLanguage, markdown({base: markdownLanguage}),
autocompletion({
activateOnTyping: true,
override: [myCompletions],
}),
EditorView.lineWrapping, EditorView.lineWrapping,
EditorView.contentAttributes.of({spellcheck: "true"}), EditorView.contentAttributes.of({spellcheck: "true"}),
// yCollab(ytext, provider.awareness, {undoManager}) // yCollab(ytext, provider.awareness, {undoManager})
@ -88,4 +145,5 @@ ids.forEach(function (id) {
}) })
}, 1000 * 30) }, 1000 * 30)
}); })
;

View file

@ -3,9 +3,9 @@ import 'vite/modulepreload-polyfill'
// import "./scss/main.scss" // import "./scss/main.scss"
import "./js/sentry" import "./js/sentry"
// @ts-ignore // @ts-ignore
import {default as Dropdown} from 'bootstrap/js/src/dropdown' import Dropdown from 'bootstrap/js/src/dropdown'
// @ts-ignore // @ts-ignore
import {default as Collapse} from 'bootstrap/js/src/collapse' import Collapse from 'bootstrap/js/src/collapse'
import "./js/autocomplete" import "./js/autocomplete"
import "./js/popover" import "./js/popover"