Bookmark submission: Make bookmark submission form a reusable WebComponent.

Change-Id: I723d98208040db5b0d2d56d8c5e727c68399f843
diff --git a/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js
new file mode 100644
index 0000000..25de54b
--- /dev/null
+++ b/src/main/resources/META-INF/resources/bookmarks/MlkBookmarkSubmissionForm.js
@@ -0,0 +1,97 @@
+import {html, render} from "../../web_modules/lit-html.js";
+import ProgressSpinner from "../web_modules/elix/define/ProgressSpinner.js";
+
+export class MlkBookmarkSubmissionForm extends HTMLElement {
+  constructor() {
+    super();
+    this.attachShadow({mode: "open"});
+  }
+
+  static get observedAttributes() {
+    return ["greetee"];
+  }
+
+  connectedCallback () {
+    this.render();
+  }
+
+  attributeChangedCallback(name, oldValue, newValue) {
+    this.render();
+  }
+
+  focus() {
+    let uriInput = this.shadowRoot.getElementById('uri-input');
+    uriInput.focus();
+  }
+
+  async onUriBlur() {
+    let titleInput = this.shadowRoot.getElementById('title-input');
+    let uriInput = this.shadowRoot.getElementById('uri-input');
+    let uriSpinner = this.shadowRoot.getElementById('uri-spinner');
+
+    if (!uriInput.value) {
+      return;
+    }
+
+    uriSpinner.hidden = false;
+    uriSpinner.playing = true;
+    let searchParams = new URLSearchParams({'uri': uriInput.value});
+    console.log(`/bookmarks/page-info?${searchParams}`);
+    let fetchUrl = new URL(`/bookmarks/page-info?${searchParams}`, document.URL);
+    let r = await fetch(fetchUrl);
+    uriSpinner.hidden = true;
+    uriSpinner.playing = false;
+
+    if (!r.ok) {
+      return;
+    }
+
+    let pageInfo = await r.json();
+    titleInput.value = pageInfo.title;
+  }
+
+  render() {
+    const template = html`
+      <link rel="stylesheet" type="text/css" href="/cms2/base.css" />
+
+      <form class="pure-form pure-form-aligned" method="post">
+        <fieldset>
+          <legend>New Bookmark</legend>
+
+          <div class="pure-control-group">
+            <label for="uri-input">URI:</label>
+            <input name="uri" id="uri-input" type="text" placeholder="URI" required
+                   @blur=${this.onUriBlur.bind(this)}/>
+            <elix-progress-spinner id="uri-spinner" hidden></elix-progress-spinner>
+          </div>
+
+          <div class="pure-control-group">
+            <label for="title-input">Title:</label>
+            <input name="title" id="title-input" type="text" placeholder="Title" required/>
+          </div>
+
+          <div class="pure-control-group">
+            <label for="description-input">Description:</label>
+            <textarea name="description" id="description-input" placeholder="Description"></textarea>
+          </div>
+
+          <div class="pure-control-group">
+            <label for="visibility-input">Visibility:</label>
+            <select id="visibility-input" name="visibility" required>
+              <option value="public">Public</option>
+              <option value="semiprivate" selected>Semiprivate</option>
+              <option value="private">Private</option>
+            </select>
+          </div>
+
+          <div class="pure-controls">
+            <button type="submit" class="pure-button pure-button-primary">Submit Bookmark</button>
+          </div>
+        </fieldset>
+      </form>`;
+
+    render(template, this.shadowRoot);
+  }
+}
+
+customElements.define("mlk-bookmark-submission-form", MlkBookmarkSubmissionForm);
diff --git a/src/main/resources/META-INF/resources/bookmarks/bookmarkList.js b/src/main/resources/META-INF/resources/bookmarks/bookmarkList.js
index 4c8287a..a6f78e6 100644
--- a/src/main/resources/META-INF/resources/bookmarks/bookmarkList.js
+++ b/src/main/resources/META-INF/resources/bookmarks/bookmarkList.js
@@ -1,28 +1,9 @@
 document.addEventListener('DOMContentLoaded', () => {
   let bookmarkSubmissionPane = document.getElementById(
       'bookmark-submission-pane');
-  let titleInput = document.getElementById('title-input');
-  let uriInput = document.getElementById('uri-input');
-  let uriSpinner = document.getElementById('uri-spinner');
+  let bookmarkSubmissionForm = document.getElementById(
+      'bookmark-submission-form');
 
-  bookmarkSubmissionPane.addEventListener('opened', () => uriInput.focus());
-
-  uriInput.addEventListener('blur', async () => {
-    uriSpinner.hidden = false;
-    uriSpinner.playing = true;
-    let searchParams = new URLSearchParams({'uri': uriInput.value});
-    console.log(`/bookmarks/page-info?${searchParams}`);
-    let fetchUrl = new URL(`/bookmarks/page-info?${searchParams}`, document.URL);
-    let r = await fetch(fetchUrl);
-    uriSpinner.hidden = true;
-    uriSpinner.playing = false;
-
-    if (!r.ok) {
-      return;
-    }
-
-    let pageInfo = await r.json();
-    titleInput.value = pageInfo.title;
-  });
+  bookmarkSubmissionPane.addEventListener('opened', () => bookmarkSubmissionForm.focus());
 });
 
diff --git a/src/main/resources/templates/benki/bookmarks/bookmarkList.html b/src/main/resources/templates/benki/bookmarks/bookmarkList.html
index 2c35249..566bfb2 100644
--- a/src/main/resources/templates/benki/bookmarks/bookmarkList.html
+++ b/src/main/resources/templates/benki/bookmarks/bookmarkList.html
@@ -13,47 +13,13 @@
 
 {! #if authenticated !}
   <script type="module" src="/web_modules/elix/define/ExpandableSection.js"></script>
-  <script type="module" src="/web_modules/elix/define/ProgressSpinner.js"></script>
-
+  <script type="module" src="/bookmarks/MlkBookmarkSubmissionForm.js" defer></script>
   <script type="module" src="/bookmarks/bookmarkList.js" defer></script>
 
   <elix-expandable-section id="bookmark-submission-pane">
     <h2 slot="header" class="small-title"><button class="pure-button">Create New Bookmark</button></h2>
     <section id="bookmark-submission">
-      <form class="pure-form pure-form-aligned" method="post">
-        <fieldset>
-          <legend>New Bookmark</legend>
-
-          <div class="pure-control-group">
-            <label for="uri-input">URI:</label>
-            <input name="uri" id="uri-input" type="text" placeholder="URI" required/>
-            <elix-progress-spinner id="uri-spinner" hidden></elix-progress-spinner>
-          </div>
-
-          <div class="pure-control-group">
-            <label for="title-input">Title:</label>
-            <input name="title" id="title-input" type="text" placeholder="Title" required/>
-          </div>
-
-          <div class="pure-control-group">
-            <label for="description-input">Description:</label>
-            <textarea name="description" id="description-input" placeholder="Description"></textarea>
-          </div>
-
-          <div class="pure-control-group">
-            <label for="visibility-input">Visibility:</label>
-            <select id="visibility-input" name="visibility" required>
-              <option value="public">Public</option>
-              <option value="semiprivate" selected>Semiprivate</option>
-              <option value="private">Private</option>
-            </select>
-          </div>
-
-          <div class="pure-controls">
-            <button type="submit" class="pure-button pure-button-primary">Submit Bookmark</button>
-          </div>
-        </fieldset>
-      </form>
+      <mlk-bookmark-submission-form id="bookmark-submission-form"></mlk-bookmark-submission-form>
     </section>
   </elix-expandable-section>
 {! /if !}