diff --git a/management/editor/editor.go b/management/editor/editor.go index 39bb25f2..8f0185e8 100644 --- a/management/editor/editor.go +++ b/management/editor/editor.go @@ -150,12 +150,14 @@ func Form(post Editable, fields ...Field) ([]byte, error) { external = form.find('.post-controls.external'), id = form.find('input[name=id]'), timestamp = $('.__ponzu.content-only'), - slug = $('input[name=slug]'); + slug = $('input[name=slug]'), + allowEmptySlug = false; // hide if this is a new post, or a non-post editor page if (id.val() === '-1' || form.attr('action') !== '/admin/edit') { del.hide(); external.hide(); + allowEmptySlug = true; } // hide approval if not on a pending content item @@ -167,11 +169,19 @@ func Form(post Editable, fields ...Field) ([]byte, error) { if (form.attr('action') === '/admin/addon') { timestamp.hide(); slug.parent().hide(); + allowEmptySlug = true; } save.on('click', function(e) { e.preventDefault(); + if (!allowEmptySlug) { + if (slug.length > 1 && slug.eq(1).val() === "") { + alert("Slug cannot be empty"); + return; + } + } + if (getParam('status') === 'pending') { var action = form.attr('action'); form.attr('action', action + '?status=pending') @@ -238,8 +248,7 @@ func addPostDefaultFieldsToEditorView(p Editable, e *Editor) error { View: Input("Slug", p, map[string]string{ "label": "URL Slug", "type": "text", - "disabled": "true", - "placeholder": "Will be set automatically", + "placeholder": "Can be left empty, only for new item", }), }, { diff --git a/system/db/content.go b/system/db/content.go index 43d60239..e57e8734 100644 --- a/system/db/content.go +++ b/system/db/content.go @@ -108,6 +108,42 @@ func update(ns, id string, data url.Values, existingContent *[]byte) (int, error return err } + // get slugs data + var ( + existingSlug, newSlug string + ) + existingSlug = data.Get("slug") + if len(data["slug"]) > 1 { + newSlug = data["slug"][1] + } + + // update the slug (type:id) in contentIndex if public content + if specifier == "" { + + target := fmt.Sprintf("%s:%d", ns, cid) + // if slug changed and valid + if existingSlug != newSlug && newSlug != "" { + ci := tx.Bucket([]byte("__contentIndex")) + if ci == nil { + return bolt.ErrBucketNotFound + } + + // remove existing slug from __contentIndex + err = ci.Delete([]byte(fmt.Sprintf("%s", existingSlug))) + if err != nil { + return err + } + + // insert new slug to __contentIndex + k := []byte(newSlug) + v := []byte(target) + err := ci.Put(k, v) + if err != nil { + return err + } + } + } + return nil }) if err != nil { @@ -770,21 +806,45 @@ func postToJSON(ns string, data url.Values) ([]byte, error) { return nil, err } + // get slugs data + var ( + existingSlug, newSlug string + ) + existingSlug = data.Get("slug") + if len(data["slug"]) > 1 { + newSlug = data["slug"][1] + } + + // for new item // if the content has no slug, and has no specifier, create a slug, check it // for duplicates, and add it to our values - if data.Get("slug") == "" && data.Get("__specifier") == "" { - slug, err := item.Slug(post.(item.Identifiable)) - if err != nil { - return nil, err - } + if existingSlug == "" && data.Get("__specifier") == "" { - slug, err = checkSlugForDuplicate(slug) - if err != nil { - return nil, err + // if no new slug specified, generate slug + if newSlug == "" { + slug, err := item.Slug(post.(item.Identifiable)) + if err != nil { + return nil, err + } + + slug, err = checkSlugForDuplicate(slug) + if err != nil { + return nil, err + } + + post.(item.Sluggable).SetSlug(slug) + data.Set("slug", slug) + } else { + post.(item.Sluggable).SetSlug(newSlug) + data.Set("slug", newSlug) } + } - post.(item.Sluggable).SetSlug(slug) - data.Set("slug", slug) + // for editing item + // prevent edit to empty slug + if existingSlug != "" && newSlug == "" { + post.(item.Sluggable).SetSlug(existingSlug) + data.Set("slug", existingSlug) } // marshall content struct to json for db storage