KB66 Add comment post form.

Change-Id: Iac22d115f0d1c59eb273a26d720c07f6d1b11077
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
index 8de4677..24a564b 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
@@ -93,6 +93,7 @@
         String pageTitle,
         Boolean showBookmarkForm,
         Boolean showLazychatForm,
+        Boolean showCommentBox,
         Boolean hasPreviousPage,
         Boolean hasNextPage,
         @CheckForNull Integer previousCursor,
@@ -160,6 +161,7 @@
         pageTitle,
         showBookmarkForm(),
         showLazychatForm(),
+        false,
         q.prevCursor != null,
         q.nextCursor != null,
         q.prevCursor,
@@ -206,6 +208,7 @@
         pageTitle,
         showBookmarkForm(),
         showLazychatForm(),
+        false,
         q.prevCursor != null,
         q.nextCursor != null,
         q.prevCursor,
@@ -248,6 +251,7 @@
         String.format("Post #%d", id),
         false,
         false,
+        true,
         false,
         false,
         null,
diff --git a/src/main/resources/META-INF/resources/lib.js b/src/main/resources/META-INF/resources/lib.js
index 9f54f5f..7a59751 100644
--- a/src/main/resources/META-INF/resources/lib.js
+++ b/src/main/resources/META-INF/resources/lib.js
@@ -2,6 +2,7 @@
 import './bookmarks/newBookmark.js';
 import './lazychat/MlkLazychatSubmissionForm.js';
 import './lazychat/newLazychatMessage.js';
+import './posts/commentBox.js';
 import './posts/postList.js';
 
 import './web_modules/elix/define/Button.js';
diff --git a/src/main/resources/META-INF/resources/posts/commentBox.js b/src/main/resources/META-INF/resources/posts/commentBox.js
new file mode 100644
index 0000000..d802a63
--- /dev/null
+++ b/src/main/resources/META-INF/resources/posts/commentBox.js
@@ -0,0 +1,51 @@
+document.addEventListener('DOMContentLoaded', () => {
+  const messageEncoder = new TextEncoder();
+
+  const acceptableHash = (hash) =>
+      hash[0] === 0 &&
+      hash[1] === 0;
+
+  const checkSalt = (message, salt, thenC, elseC) => {
+    const saltedMessage = `Hashcash-Salt: ${salt}\n\n${message}`;
+    const encodedSaltedMessage = messageEncoder.encode(saltedMessage);
+
+    crypto.subtle.digest('SHA-256', encodedSaltedMessage).then((hashBuf) => {
+      if (acceptableHash(new Uint8Array(hashBuf))) {
+        thenC();
+      } else {
+        elseC();
+      }
+    });
+  };
+
+  const commentForms = document.getElementsByClassName('comment-form');
+  for (const commentForm of commentForms) {
+    const hashcashSaltInput = commentForm.querySelector('input[name=hashcash-salt]');
+    const messageTextarea = commentForm.querySelector('textarea[name=message]');
+    const submitButton = commentForm.querySelector('input[type=submit]');
+
+    let salt = 0;
+    const tryHashcash = () => {
+      checkSalt(messageTextarea.value, salt, () => {
+        hashcashSaltInput.value = salt;
+        console.log(`hashcash ok ${salt}`);
+        submitButton.toggleAttribute('disabled');
+        commentForm.submit();
+      }, () => {
+        ++salt;
+        if (salt % 1000 === 0) {
+          console.log(`hashcash fail ${salt}, retrying`)
+        }
+        setTimeout(tryHashcash, 0);
+      });
+    };
+
+    commentForm.addEventListener(
+        'submit',
+        (event) => {
+          event.preventDefault();
+          submitButton.setAttribute('disabled', 'disabled');
+          setTimeout(tryHashcash, 0);
+        });
+  }
+});
diff --git a/src/main/resources/templates/benki/posts/postList.html b/src/main/resources/templates/benki/posts/postList.html
index fc874cf..0fc8a6d 100644
--- a/src/main/resources/templates/benki/posts/postList.html
+++ b/src/main/resources/templates/benki/posts/postList.html
@@ -83,7 +83,9 @@
               {post.descriptionHtml.raw}
             </div>
 
-            <div class="comment-box"></div>
+            {#if showCommentBox}
+              {#commentBox postId=post.id /}
+            {/if}
           </article>
         {#else}
           <article class="lazychat-message">
@@ -113,6 +115,10 @@
             <div class="lazychat-message-content post-content">
               {post.descriptionHtml.raw}
             </div>
+
+            {#if showCommentBox}
+              {#commentBox postId=post.id /}
+            {/if}
           </article>
         {/if}
       {/for}
diff --git a/src/main/resources/templates/tags/commentBox.html b/src/main/resources/templates/tags/commentBox.html
new file mode 100644
index 0000000..3049687
--- /dev/null
+++ b/src/main/resources/templates/tags/commentBox.html
@@ -0,0 +1,26 @@
+{@java.lang.Integer postId}
+
+<div class="comment-box">
+  <script type="module" src="/lib.js"></script>
+  <script type="module" src="/posts/commentBox.js"></script>
+
+  <hr/>
+
+  <form class="comment-form pure-form" method="post" action="/posts/{postId}/comments">
+    <fieldset>
+      <legend>Post Comment</legend>
+
+      <label for="comment-form-author-{postId}">Author (optional)</label>
+      <input name="author" id="comment-form-author-{postId}" type="text" placeholder="Anonymous Coward"/>
+
+      <label for="comment-form-message-{postId}">Message</label>
+      <textarea name="message" id="comment-form-message-{postId}" placeholder="Great article!" required></textarea>
+
+      <input name="hashcash-salt" id="comment-form-hashcash-salt-{postId}" type="hidden"/>
+
+      <div class="controls">
+        <input type="submit" class="pure-button"/>
+      </div>
+    </fieldset>
+  </form>
+</div>