diff options
Diffstat (limited to 'src/main')
6 files changed, 142 insertions, 6 deletions
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java index 495e511..059335c 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java @@ -27,10 +27,13 @@ import javax.transaction.Transactional; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.ws.rs.Consumes; +import javax.ws.rs.ForbiddenException; import javax.ws.rs.FormParam; import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; @@ -76,6 +79,43 @@ public class BookmarkResource extends PostResource { return Response.seeOther(new URI("/bookmarks")).build(); } + @POST + @Transactional + @Authenticated + @Produces(WILDCARD) + @Consumes({APPLICATION_FORM_URLENCODED, MULTIPART_FORM_DATA}) + @Path("{id}/edit") + public Response patchMessage( + @PathParam("id") int id, + @FormParam("uri") @NotNull URI uri, + @FormParam("title") @NotEmpty String title, + @FormParam("description") @CheckForNull String description, + @FormParam("visibility") Post.Visibility visibility) + throws URISyntaxException { + + var user = Objects.requireNonNull(getCurrentUser()); + + var bookmark = getSession().byId(Bookmark.class).load(id); + + if (bookmark == null) { + throw new NotFoundException(); + } + + if (bookmark.owner == null || !Objects.equals(bookmark.owner.id, user.id)) { + throw new ForbiddenException(); + } + + bookmark.uri = uri.toString(); + bookmark.title = title; + bookmark.tags = Set.of(); + bookmark.description = description; + bookmark.owner = user; + + assignPostTargets(visibility, user, bookmark); + + return Response.seeOther(new URI("/bookmarks")).build(); + } + @GET @Authenticated @Path("new") diff --git a/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js index 3dd3754..3b93305 100644 --- a/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js +++ b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js @@ -8,7 +8,7 @@ template.innerHTML = ` <link rel="stylesheet" type="text/css" href="/cms2/base.css" /> <link rel="stylesheet" type="text/css" href="/bookmarks/MlkBookmarkSubmissionForm.css" /> - <form class="pure-form" method="post" action="/bookmarks"> + <form id="main-form" class="pure-form" method="post" action="/bookmarks"> <fieldset> <legend>Edit Bookmark</legend> @@ -37,10 +37,13 @@ template.innerHTML = ` export class MlkBookmarkSubmissionForm extends HTMLElement { /*:: + mainForm: HTMLFormElement; descriptionInput: HTMLTextAreaElement; titleInput: HTMLInputElement; uriInput: HTMLInputElement; uriSpinner: ProgressSpinner; + visibilityInput: HTMLInputElement; + loaded: boolean; */ constructor() { @@ -49,6 +52,8 @@ export class MlkBookmarkSubmissionForm extends HTMLElement { let shadow = this.attachShadow({mode: "open"}); shadow.appendChild(template.content.cloneNode(true)); + this.mainForm = + cast(shadow.getElementById('main-form')); this.descriptionInput = cast(shadow.getElementById('description-input')); this.titleInput = @@ -57,13 +62,34 @@ export class MlkBookmarkSubmissionForm extends HTMLElement { cast(shadow.getElementById('uri-input')); this.uriSpinner = cast(shadow.getElementById('uri-spinner')); + this.visibilityInput = + cast(shadow.getElementById('visibility-input')); + + this.loaded = false; } static get observedAttributes() { return []; } - connectedCallback () { + get editedId() /*:number | null*/ { + let attr = this.getAttribute("edited-id"); + if (attr === undefined || attr === null) { + return null; + } + return parseInt(attr, 10); + } + + get isEditor() { + return this.editedId !== null; + } + + connectedCallback() { + if (this.editedId !== null) { + this.mainForm.method = "post"; + this.mainForm.action = `/bookmarks/${this.editedId}/edit`; + } + this.uriInput.addEventListener('blur', this.onUriBlur.bind(this)); this.uriInput.value = this.uri || ""; this.titleInput.value = this.titleText || ""; @@ -98,10 +124,11 @@ export class MlkBookmarkSubmissionForm extends HTMLElement { } else { this.descriptionInput.focus(); } + this.load(); } async onUriBlur() { - if (!this.uriInput.value) { + if (this.isEditor || !this.uriInput.value) { return; } @@ -121,6 +148,27 @@ export class MlkBookmarkSubmissionForm extends HTMLElement { let pageInfo = await r.json(); this.titleInput.value = pageInfo.title; } + + async load() { + if (this.editedId === null || this.loaded) { + return; + } + + let fetchUrl = new URL(`/posts/${this.editedId}`, document.URL); + let r = await fetch(fetchUrl); + + if (!r.ok) { + return; + } + + let post = await r.json(); + this.uriInput.value = post.uri; + this.titleInput.value = post.title; + this.descriptionInput.innerText = post.description; + this.visibilityInput.value = post.visibility; + + this.loaded = true; + } } customElements.define("mlk-bookmark-submission-form", MlkBookmarkSubmissionForm); diff --git a/src/main/resources/META-INF/resources/cms2/base.css b/src/main/resources/META-INF/resources/cms2/base.css index 8811bb3..bc95300 100644 --- a/src/main/resources/META-INF/resources/cms2/base.css +++ b/src/main/resources/META-INF/resources/cms2/base.css @@ -153,10 +153,15 @@ body > footer { border-top: lightgray solid 1px; } +a.bookmark-title { + text-decoration: none; +} + h1.bookmark-title { font-size: 1em; margin: 0; padding: 0; + display: inline; } .bookmark-info { @@ -164,6 +169,7 @@ h1.bookmark-title { font-size: smaller; margin: 0; padding: 0; + flex: auto; } article.bookmark { @@ -173,6 +179,10 @@ article.bookmark { background: #f8f0f0; } +article.bookmark > header { + display: flex +} + .lazychat-message-info { font-style: italic; font-size: smaller; @@ -209,6 +219,14 @@ elix-expandable-section.editor-pane::part(header) { display: inline-block; } +.bookmark-edit-button { + font-size: small; +} + +.bookmark-message-controls { + flex: initial; +} + .lazychat-edit-button { font-size: small; } diff --git a/src/main/resources/META-INF/resources/lazychat/MlkLazychatSubmissionForm.js b/src/main/resources/META-INF/resources/lazychat/MlkLazychatSubmissionForm.js index e43e135..4c4aca8 100644 --- a/src/main/resources/META-INF/resources/lazychat/MlkLazychatSubmissionForm.js +++ b/src/main/resources/META-INF/resources/lazychat/MlkLazychatSubmissionForm.js @@ -61,7 +61,7 @@ export class MlkLazychatSubmissionForm extends HTMLElement { if (attr === undefined || attr === null) { return null; } - return parseInt(attr); + return parseInt(attr, 10); } get isEditor() { diff --git a/src/main/resources/META-INF/resources/posts/postList.js b/src/main/resources/META-INF/resources/posts/postList.js index 7bab4f9..8ffb7ca 100644 --- a/src/main/resources/META-INF/resources/posts/postList.js +++ b/src/main/resources/META-INF/resources/posts/postList.js @@ -23,4 +23,17 @@ document.addEventListener('DOMContentLoaded', () => { }); } } + + let bookmarks = document.getElementsByClassName('bookmark'); + for (let bookmark of bookmarks) { + let editorPane = bookmark.getElementsByClassName('editor-pane')[0]; + if (editorPane) { + let form = bookmark.getElementsByTagName('mlk-bookmark-submission-form')[0]; + let editButton = bookmark.getElementsByClassName('bookmark-edit-button')[0]; + editButton.addEventListener('click', () => { + editorPane.toggle(); + form.focus(); + }); + } + } }); diff --git a/src/main/resources/templates/benki/posts/postList.html b/src/main/resources/templates/benki/posts/postList.html index 5f88757..bc479f4 100644 --- a/src/main/resources/templates/benki/posts/postList.html +++ b/src/main/resources/templates/benki/posts/postList.html @@ -57,15 +57,32 @@ {#if post.isBookmark} <article class="bookmark"> <header> - <a href="{uri}"><h1 class="bookmark-title">{title}</h1></a> <div class="bookmark-info"> <a class="post-link" href="/posts/{post.id}"> <time datetime="{date.htmlDateTime}">{date.humanDateTime}</time> <span class="bookmark-owner">{owner.firstName} {owner.lastName}</span> </a> </div> + + <div class="bookmark-controls"> + {#if showBookmarkForm} + <button class="pure-button bookmark-edit-button">Edit</button> + {/if} + </div> </header> + <section class="bookmark-editor post-editor"> + {#if showBookmarkForm} + <elix-expandable-panel class="bookmark-editor-pane editor-pane"> + <mlk-bookmark-submission-form edited-id="{post.id}"></mlk-bookmark-submission-form> + </elix-expandable-panel> + {/if} + </section> + + <section class="bookmark-title-section"> + <a href="{uri}" class="bookmark-title"><h1 class="bookmark-title">⇢ {title}</h1></a> + </section> + <section class="bookmark-description"> {descriptionHtml.raw} </section> @@ -87,7 +104,7 @@ </div> </header> - <section class="lazychat-editor"> + <section class="lazychat-editor post-editor"> {#if showLazychatForm} <elix-expandable-panel class="lazychat-editor-pane editor-pane"> <mlk-lazychat-submission-form edited-id="{post.id}"></mlk-lazychat-submission-form> |