Synchronize with Etiquette.

This commit is contained in:
voussoir 2020-09-15 15:04:50 -07:00
parent ec19301bcc
commit 76b1504353
3 changed files with 238 additions and 203 deletions

View file

@ -201,17 +201,26 @@ button:active
#message_area
{
display: flex;
flex-direction: column;
align-items: center;
display: grid;
grid-auto-flow: row;
grid-auto-rows: min-content;
grid-gap: 8px;
padding: 8px;
overflow-y: auto;
background-color: var(--color_transparency);
}
#message_area > :last-child
{
/*
For some reason, the message_area's 8px padding doesn't apply to the bottom
when the container is scrolled.
*/
margin-bottom: 8px;
}
.message_bubble
{
width: 80%;
margin: 4px;
padding: 2px;
word-wrap: break-word;
}
.message_bubble *

View file

@ -1,12 +1,12 @@
var common = {};
const common = {};
common.INPUT_TYPES = new Set(["INPUT", "TEXTAREA"]);
common._request =
function _request(method, url, callback)
{
let request = new XMLHttpRequest();
let response = {
const request = new XMLHttpRequest();
const response = {
"completed": false,
};
@ -29,7 +29,7 @@ function _request(method, url, callback)
}
callback(response);
};
let asynchronous = true;
const asynchronous = true;
request.open(method, url, asynchronous);
return request;
}
@ -61,7 +61,7 @@ function bind_box_to_button(box, button, ctrl_enter)
Thanks Yaroslav Yakovlev
http://stackoverflow.com/a/9343095
*/
let bound_box_hook = function(event)
const bound_box_hook = function(event)
{
if (event.key !== "Enter")
{return;}
@ -83,9 +83,9 @@ function create_message_bubble(message_area, message_positivity, message_text, l
{
lifespan = 8000;
}
let message = document.createElement("div");
const message = document.createElement("div");
message.className = "message_bubble " + message_positivity;
let span = document.createElement("span");
const span = document.createElement("span");
span.innerHTML = message_text;
message.appendChild(span);
message_area.appendChild(message);
@ -168,13 +168,13 @@ function entry_with_history_hook(event)
common.html_to_element =
function html_to_element(html)
{
let template = document.createElement("template");
template.innerHTML = html;
return template.content.firstChild;
const template = document.createElement("template");
template.innerHTML = html.trim();
return template.content.firstElementChild;
}
common.init_atag_merge_params =
function init_atag_merge_params()
function init_atag_merge_params(a)
{
/*
To create an <a> tag where the ?parameters written on the href are merged
@ -195,42 +195,47 @@ function init_atag_merge_params()
href: "?orderby=date"
Result: "?filter=hello&orderby=date"
*/
function ingest(params, new_params)
{
for (const [key, value] of params) { new_params.set(key, value); }
}
const page_params = Array.from(new URLSearchParams(window.location.search));
let as = Array.from(document.getElementsByClassName("merge_params"));
for (const a of as)
{
const a_params = new URLSearchParams(a.search);
const new_params = new URLSearchParams();
let to_merge;
if (a.dataset.mergeParams)
{
let keep = new Set(a.dataset.mergeParams.split(/[\s,]+/));
ingest(page_params.filter(key_value => keep.has(key_value[0])), new_params);
const keep = new Set(a.dataset.mergeParams.split(/[\s,]+/));
to_merge = page_params.filter(key_value => keep.has(key_value[0]));
delete a.dataset.mergeParams;
}
else if (a.dataset.mergeParamsExcept)
{
let remove = new Set(a.dataset.mergeParamsExcept.split(/[\s,]+/));
ingest(page_params.filter(key_value => (! remove.has(key_value[0]))), new_params);
const remove = new Set(a.dataset.mergeParamsExcept.split(/[\s,]+/));
to_merge = page_params.filter(key_value => (! remove.has(key_value[0])));
delete a.dataset.mergeParamsExcept;
}
else
{
ingest(page_params, new_params);
to_merge = page_params;
}
ingest(a_params, new_params);
to_merge = to_merge.concat(Array.from(new URLSearchParams(a.search)));
const new_params = new URLSearchParams();
for (const [key, value] of to_merge)
{ new_params.set(key, value); }
a.search = new_params.toString();
a.classList.remove("merge_params");
}
common.init_all_atag_merge_params =
function init_all_atag_merge_params()
{
const page_params = Array.from(new URLSearchParams(window.location.search));
const as = Array.from(document.getElementsByClassName("merge_params"));
for (const a of as)
{
setTimeout(() => common.init_atag_merge_params(a), 0);
}
}
common.init_button_with_confirm =
function init_button_with_confirm()
function init_button_with_confirm(button)
{
/*
To create a button that requires a second confirmation step, assign it the
@ -262,25 +267,19 @@ function init_button_with_confirm()
data-holder-class: CSS class for the new span that holds the menu.
*/
let buttons = Array.from(document.getElementsByClassName("button_with_confirm"));
for (const button of buttons)
{
button.classList.remove("button_with_confirm");
let holder = document.createElement("span");
holder.classList.add("confirm_holder");
holder.classList.add(button.dataset.holderClass || "confirm_holder");
const holder = document.createElement("span");
holder.className = "confirm_holder " + (button.dataset.holderClass || "");
button.parentElement.insertBefore(holder, button);
button.parentElement.removeChild(button);
let holder_stage1 = document.createElement("span");
holder_stage1.classList.add("confirm_holder_stage1");
const holder_stage1 = document.createElement("span");
holder_stage1.className = "confirm_holder_stage1";
holder_stage1.appendChild(button);
holder.appendChild(holder_stage1);
let holder_stage2 = document.createElement("span");
holder_stage2.classList.add("confirm_holder_stage2");
holder_stage2.classList.add("hidden");
const holder_stage2 = document.createElement("span");
holder_stage2.className = "confirm_holder_stage2 hidden";
holder.appendChild(holder_stage2);
let prompt;
@ -302,7 +301,7 @@ function init_button_with_confirm()
delete button.dataset.prompt;
delete button.dataset.promptClass;
let button_confirm = document.createElement("button");
const button_confirm = document.createElement("button");
button_confirm.innerText = (button.dataset.confirm || button.innerText).trim();
if (button.dataset.confirmClass === undefined)
{
@ -324,7 +323,7 @@ function init_button_with_confirm()
delete button.dataset.confirmClass;
delete button.dataset.isInput;
let button_cancel = document.createElement("button");
const button_cancel = document.createElement("button");
button_cancel.innerText = button.dataset.cancel || "Cancel";
button_cancel.className = button.dataset.cancelClass || "";
holder_stage2.appendChild(button_cancel);
@ -332,20 +331,20 @@ function init_button_with_confirm()
delete button.dataset.cancelClass;
// If this is stupid, let me know.
let confirm_onclick = button.dataset.onclick + `
;
const confirm_onclick = `
let holder = event.target.parentElement.parentElement;
holder.getElementsByClassName("confirm_holder_stage1")[0].classList.remove("hidden");
holder.getElementsByClassName("confirm_holder_stage2")[0].classList.add("hidden");
`
` + button.dataset.onclick;
button_confirm.onclick = Function(confirm_onclick);
button.removeAttribute("onclick");
button.onclick = function(event)
{
let holder = event.target.parentElement.parentElement;
const holder = event.target.parentElement.parentElement;
holder.getElementsByClassName("confirm_holder_stage1")[0].classList.add("hidden");
holder.getElementsByClassName("confirm_holder_stage2")[0].classList.remove("hidden");
let input = holder.getElementsByTagName("input")[0];
const input = holder.getElementsByTagName("input")[0];
if (input)
{
input.focus();
@ -354,54 +353,108 @@ function init_button_with_confirm()
button_cancel.onclick = function(event)
{
let holder = event.target.parentElement.parentElement;
const holder = event.target.parentElement.parentElement;
holder.getElementsByClassName("confirm_holder_stage1")[0].classList.remove("hidden");
holder.getElementsByClassName("confirm_holder_stage2")[0].classList.add("hidden");
}
delete button.dataset.onclick;
}
common.init_all_button_with_confirm =
function init_all_button_with_confirm()
{
const buttons = Array.from(document.getElementsByClassName("button_with_confirm"));
for (const button of buttons)
{
setTimeout(() => common.init_button_with_confirm(button), 0);
}
}
common.init_enable_on_pageload =
function init_enable_on_pageload()
function init_enable_on_pageload(element)
{
/*
To create an input element which is disabled at first, and is enabled when
the DOM has completed loading, give it the disabled attribute and the
class "enable_on_pageload".
*/
let elements = Array.from(document.getElementsByClassName("enable_on_pageload"));
for (const element of elements)
{
element.disabled = false;
element.classList.remove("enable_on_pageload");
}
common.init_all_enable_on_pageload =
function init_all_enable_on_pageload()
{
const elements = Array.from(document.getElementsByClassName("enable_on_pageload"));
for (const element of elements)
{
setTimeout(() => common.init_enable_on_pageload(element), 0);
}
}
common.init_entry_with_history =
function init_entry_with_history()
function init_entry_with_history(input)
{
input.addEventListener("keydown", common.entry_with_history_hook);
input.classList.remove("entry_with_history");
}
common.init_all_entry_with_history =
function init_all_entry_with_history()
{
const inputs = Array.from(document.getElementsByClassName("entry_with_history"));
for (const input of inputs)
{
input.addEventListener("keydown", common.entry_with_history_hook);
input.classList.remove("entry_with_history");
setTimeout(() => common.init_entry_with_history(input), 0);
}
}
common.init_tabbed_container =
function init_tabbed_container()
function init_tabbed_container(tabbed_container)
{
let switch_tab =
function switch_tab(event)
const button_container = document.createElement("div");
button_container.className = "tab_buttons";
tabbed_container.prepend(button_container);
const tabs = Array.from(tabbed_container.getElementsByClassName("tab"));
for (const tab of tabs)
{
let tab_button = event.target;
tab.classList.add("hidden");
const tab_id = tab.dataset.tabId || tab.dataset.tabTitle;
tab.dataset.tabId = tab_id;
tab.style.borderTopColor = "transparent";
const button = document.createElement("button");
button.className = "tab_button tab_button_inactive";
button.onclick = common.tabbed_container_switcher;
button.innerText = tab.dataset.tabTitle;
button.dataset.tabId = tab_id;
button_container.append(button);
}
tabs[0].classList.remove("hidden");
button_container.firstElementChild.classList.remove("tab_button_inactive");
button_container.firstElementChild.classList.add("tab_button_active");
}
common.init_all_tabbed_container =
function init_all_tabbed_container()
{
const tabbed_containers = Array.from(document.getElementsByClassName("tabbed_container"));
for (const tabbed_container of tabbed_containers)
{
setTimeout(() => common.init_tabbed_container(tabbed_container), 0);
}
}
common.tabbed_container_switcher =
function tabbed_container_switcher(event)
{
const tab_button = event.target;
if (tab_button.classList.contains("tab_button_active"))
{ return; }
let tab_id = tab_button.dataset.tabId;
let tab_buttons = tab_button.parentElement.getElementsByClassName("tab_button");
let tabs = tab_button.parentElement.parentElement.getElementsByClassName("tab");
const tab_id = tab_button.dataset.tabId;
const tab_buttons = tab_button.parentElement.getElementsByClassName("tab_button");
const tabs = tab_button.parentElement.parentElement.getElementsByClassName("tab");
for (const tab_button of tab_buttons)
{
if (tab_button.dataset.tabId === tab_id)
@ -422,33 +475,6 @@ function init_tabbed_container()
else
{ tab.classList.add("hidden"); }
}
}
let tabbed_containers = Array.from(document.getElementsByClassName("tabbed_container"));
for (const tabbed_container of tabbed_containers)
{
let button_container = document.createElement("div");
button_container.className = "tab_buttons";
tabbed_container.prepend(button_container);
let tabs = Array.from(tabbed_container.getElementsByClassName("tab"));
for (const tab of tabs)
{
tab.classList.add("hidden");
let tab_id = tab.dataset.tabId || tab.dataset.tabTitle;
tab.dataset.tabId = tab_id;
tab.style.borderTopColor = "transparent";
let button = document.createElement("button");
button.className = "tab_button tab_button_inactive";
button.onclick = switch_tab;
button.innerText = tab.dataset.tabTitle;
button.dataset.tabId = tab_id;
button_container.append(button);
}
tabs[0].classList.remove("hidden");
button_container.firstElementChild.classList.remove("tab_button_inactive");
button_container.firstElementChild.classList.add("tab_button_active");
}
}
common.refresh =
@ -460,10 +486,10 @@ function refresh()
common.on_pageload =
function on_pageload()
{
common.init_atag_merge_params();
common.init_button_with_confirm();
common.init_enable_on_pageload();
common.init_entry_with_history();
common.init_tabbed_container();
common.init_all_atag_merge_params();
common.init_all_button_with_confirm();
common.init_all_enable_on_pageload();
common.init_all_entry_with_history();
common.init_all_tabbed_container();
}
document.addEventListener("DOMContentLoaded", common.on_pageload);

View file

@ -1,4 +1,4 @@
var spinner = {};
const spinner = {};
/*
In general, spinners are used for functions that launch a callback, and the