forked from forem/forem
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow archiving of posts (forem#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
- Loading branch information
1 parent
ab34480
commit b2a8f69
Showing
12 changed files
with
290 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
app/assets/javascripts/initializers/initializeArchivedPostFilter.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
function archivedPosts() { | ||
return document.getElementsByClassName('single-article-archived'); | ||
} | ||
|
||
function showArchivedPosts() { | ||
var posts = archivedPosts(); | ||
|
||
for (var i = 0; i < posts.length; i += 1) { | ||
posts[i].classList.remove('hidden'); | ||
} | ||
} | ||
|
||
function hideArchivedPosts() { | ||
var posts = archivedPosts(); | ||
|
||
for (var i = 0; i < posts.length; i += 1) { | ||
posts[i].classList.add('hidden'); | ||
} | ||
} | ||
|
||
function toggleArchivedPosts(e) { | ||
var link = e.target; | ||
|
||
if (link.innerHTML.match(/Show/)) { | ||
link.innerHTML = 'Hide Archived'; | ||
showArchivedPosts(); | ||
} else { | ||
link.innerHTML = 'Show Archived'; | ||
hideArchivedPosts(); | ||
} | ||
} | ||
|
||
function initializeArchivedPostFilter() { | ||
var link = document.getElementById('toggleArchivedLink'); | ||
|
||
link.addEventListener('click', toggleArchivedPosts); | ||
} |
150 changes: 150 additions & 0 deletions
150
app/assets/javascripts/initializers/initializeEllipsisMenu.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// 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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class AddArchivedToArticles < ActiveRecord::Migration[5.2] | ||
def change | ||
add_column :articles, :archived, :boolean, default: false | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters