add reusable babycode editor
This commit is contained in:
		@@ -394,6 +394,12 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.post-edit-form > textarea {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
.babycode-editor {
 | 
			
		||||
  height: 150px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul {
 | 
			
		||||
  margin: 10px 0 10px 30px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								js/post-editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								js/post-editor.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
{
 | 
			
		||||
  let ta = document.getElementById("post_content");
 | 
			
		||||
  const buttonBold = document.getElementById("post-editor-bold");
 | 
			
		||||
  const buttonItalics = document.getElementById("post-editor-italics");
 | 
			
		||||
  const buttonStrike = document.getElementById("post-editor-strike");
 | 
			
		||||
  const buttonCode = document.getElementById("post-editor-code");
 | 
			
		||||
 | 
			
		||||
  function insertTag(tagStart, newline = false) {
 | 
			
		||||
    const tagEnd = tagStart;
 | 
			
		||||
    const tagInsertStart = `[${tagStart}]${newline ? "\n" : ""}`;
 | 
			
		||||
    const tagInsertEnd = `${newline ? "\n" : ""}[/${tagEnd}]`;
 | 
			
		||||
    const hasSelection = ta.selectionStart !== ta.selectionEnd;
 | 
			
		||||
    const text = ta.value;
 | 
			
		||||
    if (hasSelection) {
 | 
			
		||||
      const realStart = Math.min(ta.selectionStart, ta.selectionEnd);
 | 
			
		||||
      const realEnd = Math.max(ta.selectionStart, ta.selectionEnd);
 | 
			
		||||
      const selectionLength = realEnd - realStart;
 | 
			
		||||
      
 | 
			
		||||
      const strStart = text.slice(0, realStart);
 | 
			
		||||
      const strEnd = text.substring(realEnd);
 | 
			
		||||
      const frag = `${tagInsertStart}${text.slice(realStart, realEnd)}${tagInsertEnd}`;
 | 
			
		||||
      const reconst = `${strStart}${frag}${strEnd}`;
 | 
			
		||||
      ta.value = reconst;
 | 
			
		||||
      ta.setSelectionRange(realStart + tagInsertStart.length, realStart + tagInsertStart.length + selectionLength);
 | 
			
		||||
      ta.focus()
 | 
			
		||||
    } else {
 | 
			
		||||
      const cursor = ta.selectionStart;
 | 
			
		||||
      const strStart = text.slice(0, cursor);
 | 
			
		||||
      const strEnd = text.substr(cursor);
 | 
			
		||||
      const newCursor = strStart.length + tagInsertStart.length;
 | 
			
		||||
      const reconst = `${strStart}${tagInsertStart}${tagInsertEnd}${strEnd}`;
 | 
			
		||||
      ta.value = reconst;
 | 
			
		||||
      ta.setSelectionRange(newCursor, newCursor);
 | 
			
		||||
      ta.focus()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  buttonBold.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("b")
 | 
			
		||||
  })
 | 
			
		||||
  buttonItalics.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("i")
 | 
			
		||||
  })
 | 
			
		||||
  buttonStrike.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("s")
 | 
			
		||||
  })
 | 
			
		||||
  buttonCode.addEventListener("click", (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    insertTag("code", true)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								js/thread.js
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								js/thread.js
									
									
									
									
									
								
							@@ -1,8 +1,10 @@
 | 
			
		||||
const ta = document.getElementById("post_content");
 | 
			
		||||
{
 | 
			
		||||
  const ta = document.getElementById("post_content");
 | 
			
		||||
 | 
			
		||||
for (let button of document.querySelectorAll(".reply-button")) {
 | 
			
		||||
  button.addEventListener("click", (e) => {
 | 
			
		||||
    ta.value += button.value;
 | 
			
		||||
    ta.scrollIntoView()
 | 
			
		||||
  })
 | 
			
		||||
  for (let button of document.querySelectorAll(".reply-button")) {
 | 
			
		||||
    button.addEventListener("click", (e) => {
 | 
			
		||||
      ta.value += button.value;
 | 
			
		||||
      ta.scrollIntoView()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -397,8 +397,14 @@ input[type="text"], input[type="password"], textarea, select {
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  
 | 
			
		||||
  &>textarea{
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.babycode-editor {
 | 
			
		||||
  height: 150px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ul {
 | 
			
		||||
  margin: 10px 0 10px 30px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								views/common/babycode-editor-component.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								views/common/babycode-editor-component.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<span>
 | 
			
		||||
  <button type=button id="post-editor-bold" title="Insert Bold">B</button>
 | 
			
		||||
  <button type=button id="post-editor-italics" title="Insert Italics">I</button>
 | 
			
		||||
  <button type=button id="post-editor-strike" title="Insert Strikethrough">S</button>
 | 
			
		||||
  <button type=button id="post-editor-code" title="Insert Code block">Code</button>
 | 
			
		||||
</span>
 | 
			
		||||
<textarea class="babycode-editor" name="<%= ta_name %>" id="post_content" placeholder="Post body" required><%- prefill or "" %></textarea>
 | 
			
		||||
<script src="/static/js/post-editor.js"></script>
 | 
			
		||||
							
								
								
									
										16
									
								
								views/common/babycode-editor.etlua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								views/common/babycode-editor.etlua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
<%
 | 
			
		||||
  local save_button_text = "Post reply"
 | 
			
		||||
  if cancel_url then
 | 
			
		||||
    save_button_text = "Save"
 | 
			
		||||
  end
 | 
			
		||||
%>
 | 
			
		||||
<form class="post-edit-form" method="post" action="<%= url or "" %>">
 | 
			
		||||
  <% render ("views.common.babycode-editor-component", {ta_name = ta_name, prefill = prefill}) %>
 | 
			
		||||
  <span>
 | 
			
		||||
  <input type=submit value="<%= save_button_text %>">
 | 
			
		||||
    <% if cancel_url then %>
 | 
			
		||||
      <a class="linkbutton warn" href="<%= cancel_url %>">Cancel</a>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  </span>
 | 
			
		||||
  <% render("views.common.bbcode_help") %>
 | 
			
		||||
</form>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<details>
 | 
			
		||||
  <summary>Supported babycode tags</summary>
 | 
			
		||||
  <summary>babycode guide</summary>
 | 
			
		||||
  <ul>
 | 
			
		||||
    <li>[b]<b>bold</b>[/b]</li>
 | 
			
		||||
    <li>[i]<i>italic</i>[/i]</li>
 | 
			
		||||
@@ -8,4 +8,4 @@
 | 
			
		||||
    <li>[url]<a href="https://unlabeled-url.example.com">https://unlabeled-url.example.com</a>[/url]</li>
 | 
			
		||||
    <li>[code]<code>code block</code>[/code]</li>
 | 
			
		||||
  </ul>
 | 
			
		||||
</details>
 | 
			
		||||
</details>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@
 | 
			
		||||
      </select><br>
 | 
			
		||||
      <label for="title">Thread title</label>
 | 
			
		||||
      <input type="text" id="title" name="title" placeholder="Required" required>
 | 
			
		||||
      <label for="initial_post">Post body</label>
 | 
			
		||||
      <textarea id="initial_post" name="initial_post" placeholder="Required" rows=5 required></textarea>
 | 
			
		||||
      <label for="initial_post">Post body</label><br>
 | 
			
		||||
      <% render("views.common.babycode-editor-component", {ta_name = "initial_post"}) %>
 | 
			
		||||
      <% render "views.common.bbcode_help" %>
 | 
			
		||||
      <input type="submit" value="Create thread">
 | 
			
		||||
    </form>
 | 
			
		||||
 
 | 
			
		||||
@@ -54,13 +54,11 @@
 | 
			
		||||
      <% if not edit then %>
 | 
			
		||||
        <%- post.content %>
 | 
			
		||||
      <% else %>
 | 
			
		||||
        <form class="post-edit-form" method="post">
 | 
			
		||||
          <textarea name="new_content" required><%- post.original_markup %></textarea>
 | 
			
		||||
          <span>
 | 
			
		||||
          <input type=submit value="Save">
 | 
			
		||||
          <a class="linkbutton warn" href="<%= url_for("thread", {slug = thread.slug}, {page = page}) .. "#post-" .. post.id %>">Cancel</a>
 | 
			
		||||
          </span>
 | 
			
		||||
        </form>
 | 
			
		||||
        <% render("views.common.babycode-editor", {
 | 
			
		||||
          cancel_url = url_for("thread", {slug = thread.slug}, {page = page}) .. "#post-" .. post.id,
 | 
			
		||||
          prefill = post.original_markup,
 | 
			
		||||
          ta_name = "new_content"
 | 
			
		||||
          }) %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,6 @@
 | 
			
		||||
<%
 | 
			
		||||
  local is_locked = ntob(thread.is_locked)
 | 
			
		||||
  local can_post = (not is_locked and not me:is_guest()) or me:is_mod()
 | 
			
		||||
  -- not locked, not guest, not mod = not false and not false or false = true and true or false = true
 | 
			
		||||
  -- locked, not guest, not mod = not true and not false or false = false and true or false = false
 | 
			
		||||
  -- not locked, guest, not mod = not false and not true or false = true and false or false = false
 | 
			
		||||
  -- not locked, not guest, mod = not false and not false or true = true and true and true
 | 
			
		||||
%>
 | 
			
		||||
<main>
 | 
			
		||||
  <nav class="darkbg">
 | 
			
		||||
@@ -24,10 +20,7 @@
 | 
			
		||||
  <% render("views.common.infobox", {kind = constants.InfoboxKind.LOCK, msg = "This thread is locked."}) %>
 | 
			
		||||
<% end -%>
 | 
			
		||||
<% if can_post then %>
 | 
			
		||||
<h1>Respond to "<%= thread.title %>"</h1>
 | 
			
		||||
<form method="post">
 | 
			
		||||
  <textarea id="post_content" name="post_content" placeholder="Response body" rows=7 required></textarea><br>
 | 
			
		||||
  <input type="submit" value="Post reply">
 | 
			
		||||
</form>
 | 
			
		||||
<script src="/static/js/thread.js"></script>
 | 
			
		||||
  <h1>Respond to "<%= thread.title %>"</h1>
 | 
			
		||||
  <% render("views.common.babycode-editor", {ta_name="post_content"}) %>
 | 
			
		||||
  <script src="/static/js/thread.js"></script>
 | 
			
		||||
<% end %>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user