Fix slug input: free typing with live space→hyphen and lowercasing
Live-filtering through slugify ate hyphens and spaces (trailing hyphens are stripped) and jumped the cursor to the end on mid-text edits. Now only spaces→hyphens and lowercasing happen oninput (length-preserving, cursor stays put); the full slugify runs at commit before the server call, which keeps its own validation.
This commit is contained in:
@@ -106,7 +106,8 @@ function discardPending() {
|
|||||||
async function commitPending() {
|
async function commitPending() {
|
||||||
const node = pending.value
|
const node = pending.value
|
||||||
if (!node) return
|
if (!node) return
|
||||||
// Empty slug: derive one from the title (transliterated to ASCII).
|
// The typed slug is slugified at commit; empty derives one from the
|
||||||
|
// title (transliterated to ASCII).
|
||||||
const slug = slugify(node.slug.trim()) || slugify(node.title)
|
const slug = slugify(node.slug.trim()) || slugify(node.title)
|
||||||
if (!slug) {
|
if (!slug) {
|
||||||
return
|
return
|
||||||
@@ -216,10 +217,13 @@ function onTitleInput(node, ev) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// The slug inputs are filtered as you type (StructureTree onSlugInput,
|
// Slug inputs are typed freely (spaces become hyphens live, see
|
||||||
// see slugify.js); the server re-validates and its reason is shown.
|
// StructureTree onSlugInput); the value is slugified here at commit
|
||||||
|
// (blur/Enter) before talking to the server, which re-validates (e.g.
|
||||||
|
// reserved names) and its reason is shown.
|
||||||
async function commitSlug(node, ev) {
|
async function commitSlug(node, ev) {
|
||||||
const slug = ev.target.value.trim()
|
const slug = slugify(ev.target.value.trim())
|
||||||
|
ev.target.value = slug
|
||||||
if (slug === node.slug) return
|
if (slug === node.slug) return
|
||||||
const parent = node.path.split('/').slice(0, -1).join('/')
|
const parent = node.path.split('/').slice(0, -1).join('/')
|
||||||
// Empty slug at top level = the front page (path "").
|
// Empty slug at top level = the front page (path "").
|
||||||
|
|||||||
@@ -34,16 +34,17 @@ const props = defineProps({
|
|||||||
|
|
||||||
const handlers = inject('structureHandlers')
|
const handlers = inject('structureHandlers')
|
||||||
|
|
||||||
// Live-filter the slug inputs as they are typed (oninput): invalid
|
// Slug inputs accept free typing; the only live rewrites are turning
|
||||||
// characters are simply not accepted, spaces become hyphens and unicode
|
// spaces into hyphens and lowercasing (both keep the length for ASCII,
|
||||||
// folds to ASCII (see slugify.js). Existing rows commit on change, the
|
// so the cursor stays put). Anything else (unicode folding, stripping,
|
||||||
// pending row is v-modeled.
|
// collapsing) is left for commit time, where the value is run through
|
||||||
function onSlugInput(ev) {
|
// slugify before talking to the server (StructureEditor). `element` is
|
||||||
ev.target.value = slugify(ev.target.value)
|
// the pending row (v-modeled), null for existing rows (plain :value
|
||||||
}
|
// binding, read back on commit).
|
||||||
|
function onSlugInput(element, ev) {
|
||||||
function onPendingSlugInput(element, ev) {
|
const v = ev.target.value.replace(/\s/g, '-').toLowerCase()
|
||||||
element.slug = slugify(ev.target.value)
|
ev.target.value = v
|
||||||
|
if (element) element.slug = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus the title input of a fresh pending row.
|
// Focus the title input of a fresh pending row.
|
||||||
@@ -113,7 +114,7 @@ function onEnd() {
|
|||||||
class="edit slug-edit"
|
class="edit slug-edit"
|
||||||
:placeholder="slugify(element.title)"
|
:placeholder="slugify(element.title)"
|
||||||
title="Slug (last path segment) — empty: derived from the title"
|
title="Slug (last path segment) — empty: derived from the title"
|
||||||
@input="onPendingSlugInput(element, $event)"
|
@input="onSlugInput(element, $event)"
|
||||||
@keyup.enter="handlers.commitPending()"
|
@keyup.enter="handlers.commitPending()"
|
||||||
@keyup.esc="handlers.discardPending()"
|
@keyup.esc="handlers.discardPending()"
|
||||||
/>
|
/>
|
||||||
@@ -135,7 +136,7 @@ function onEnd() {
|
|||||||
:value="element.slug"
|
:value="element.slug"
|
||||||
placeholder="front page"
|
placeholder="front page"
|
||||||
title="Slug (last path segment) — renames move the whole subtree. Empty at top level = front page"
|
title="Slug (last path segment) — renames move the whole subtree. Empty at top level = front page"
|
||||||
@input="onSlugInput"
|
@input="onSlugInput(null, $event)"
|
||||||
@change="handlers.commitSlug(element, $event)"
|
@change="handlers.commitSlug(element, $event)"
|
||||||
/>
|
/>
|
||||||
<span class="acts">
|
<span class="acts">
|
||||||
|
|||||||
Reference in New Issue
Block a user