docbrown/app/assets/javascripts/initializers/initializeEllipsisMenu.js
Dana Scheider b2a8f69f83 Allow archiving of posts (#2798)
* This commit adds the "archived" attribute to the Article model, which will
enable users to automatically filter archived articles/drafts from appearing
on their dashboard. It also adds an ellipsis menu with a link to archive the
article. I've also moved the Mute Notifications button into the ellipsis menu
as well.

* Add ellipsis menu and make it work

* Fix logic error

* Hide ellipsis menus when you click elsewhere on the body

* Extract function to remove duplication

* Ensure that menu is hidden when the ellipsis button is clicked on an open menu

* Ensure that archiving post button works and that 'archived' param is accepted by the controller

* Enable link to toggle showing/hiding archived articles

* Make 'mute' and 'archive' buttons in ellipsis dropdown list work

* Refactor to make Code Climate happy

* Minor JS refactors
2019-05-13 15:40:52 -04:00

150 lines
3.7 KiB
JavaScript

// SUBMITTING FORM //
function getFormValues(form) {
var articleId = form.action.match(/\/(\d+)$/)[1];
var inputs = form.querySelectorAll('input');
var formData = { id: articleId, article: {} };
for (var i = 0; i < inputs.length; i += 1) {
var input = inputs[i];
var name = input.getAttribute('name');
var value = input.getAttribute('value');
if (name.match(/\[(.*)\]/)) {
var key = name.match(/\[(.*)\]$/)[1];
formData.article[key] = value;
} else {
formData[name] = value;
}
}
return formData;
}
function toggleArchived(article, needsArchived) {
if (needsArchived === 'true') {
article.classList.add('single-article-archived', 'hidden');
} else {
article.classList.remove('single-article-archived');
}
}
function toggleNotifications(submit, action) {
if (action === 'Mute Notifications') {
submit.setAttribute('value', 'Receive Notifications');
} else {
submit.setAttribute('value', 'Mute Notifications');
}
}
function onXhrSuccess(form, article, values) {
if (values.article.archived) {
toggleArchived(article, values.article.archived);
} else {
var submit = form.querySelector('input[type="submit"]');
var submitValue = submit.getAttribute('value');
toggleNotifications(submit, submitValue);
}
article.querySelector('ul.ellipsis-menu').classList.add('hidden');
}
function handleFormSubmit(e) {
e.preventDefault();
e.stopPropagation();
var form = e.target;
var values = getFormValues(form);
var data = JSON.stringify(values);
var xhr = new XMLHttpRequest();
xhr.open('PATCH', form.action);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(data);
xhr.onload = function() {
var article = form.closest('div.single-article');
if (xhr.status === 200) {
onXhrSuccess(form, article, values);
} else {
article.querySelector('.dashboard-meta-details').innerHTML =
'Failed to update article.';
}
};
}
function initializeFormSubmit() {
var forms = document.querySelectorAll('ul.ellipsis-menu > li > form');
for (var i = 0; i < forms.length; i += 1) {
forms[i].addEventListener('submit', handleFormSubmit);
}
}
// TOGGLING MENU //
function getMenu(el) {
var parentDiv = el.closest('div.ellipsis-menu');
var menu = parentDiv.querySelector('ul.ellipsis-menu');
return menu;
}
function hideIfNotAlreadyHidden(menu) {
if (!menu.classList.contains('hidden')) {
menu.classList.add('hidden');
}
}
function hideAllEllipsisMenusExcept(menu) {
var menus = document.querySelectorAll('ul.ellipsis-menu');
for (var i = 0; i < menus.length; i += 1) {
if (menus[i] !== menu) {
hideIfNotAlreadyHidden(menus[i]);
}
}
}
function hideEllipsisMenus(e) {
if (!e.target.closest('div.ellipsis-menu')) {
var menus = document.querySelectorAll('ul.ellipsis-menu');
for (var i = 0; i < menus.length; i += 1) {
hideIfNotAlreadyHidden(menus[i]);
}
}
}
function toggleEllipsisMenu(e) {
var menu = getMenu(e.target);
// Make sure other ellipsis menus close when a new one
// is opened
hideAllEllipsisMenusExcept(menu);
if (menu.classList.contains('hidden')) {
menu.classList.remove('hidden');
} else {
menu.classList.add('hidden');
}
}
function initializeEllipsisMenuToggle() {
var buttons = document.getElementsByClassName('ellipsis-menu-btn');
for (var i = 0; i < buttons.length; i += 1) {
buttons[i].addEventListener('click', toggleEllipsisMenu);
}
// Hide ellipsis menus when you click outside of the ellipsis menu parent div
document
.getElementsByTagName('BODY')[0]
.addEventListener('click', hideEllipsisMenus);
}
function initializeEllipsisMenu() {
initializeEllipsisMenuToggle();
initializeFormSubmit();
}