KB53 Support bookmark edition.
Change-Id: Ieacbb5c448b9afa4bc9524167e0c73618de6db48
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.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 @@
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 @@
<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 @@
export class MlkBookmarkSubmissionForm extends HTMLElement {
/*::
+ mainForm: HTMLFormElement;
descriptionInput: HTMLTextAreaElement;
titleInput: HTMLInputElement;
uriInput: HTMLInputElement;
uriSpinner: ProgressSpinner;
+ visibilityInput: HTMLInputElement;
+ loaded: boolean;
*/
constructor() {
@@ -49,6 +52,8 @@
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 @@
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 @@
} else {
this.descriptionInput.focus();
}
+ this.load();
}
async onUriBlur() {
- if (!this.uriInput.value) {
+ if (this.isEditor || !this.uriInput.value) {
return;
}
@@ -121,6 +148,27 @@
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 @@
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 @@
font-size: smaller;
margin: 0;
padding: 0;
+ flex: auto;
}
article.bookmark {
@@ -173,6 +179,10 @@
background: #f8f0f0;
}
+article.bookmark > header {
+ display: flex
+}
+
.lazychat-message-info {
font-style: italic;
font-size: smaller;
@@ -209,6 +219,14 @@
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 @@
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 @@
});
}
}
+
+ 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>