mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-23 09:31:04 +00:00
Merge pull request #4326 from wallabag/mass-actions
Added mass actions for Material design in list view
This commit is contained in:
commit
8a8a78a64c
9 changed files with 191 additions and 2 deletions
|
@ -2,6 +2,42 @@
|
||||||
* Entries
|
* Entries
|
||||||
* ========================================================================== */
|
* ========================================================================== */
|
||||||
|
|
||||||
|
.mass-buttons {
|
||||||
|
margin: 5px;
|
||||||
|
|
||||||
|
#selectAll {
|
||||||
|
position: relative;
|
||||||
|
opacity: initial;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
i {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-stacked {
|
||||||
|
input[type=checkbox] {
|
||||||
|
position: relative;
|
||||||
|
opacity: initial;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-checkbox {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.collection {
|
.collection {
|
||||||
margin: 15px 15px 0;
|
margin: 15px 15px 0;
|
||||||
|
|
||||||
|
|
|
@ -105,4 +105,17 @@ $(document).ready(() => {
|
||||||
$('.nav-panels').css('background', 'transparent');
|
$('.nav-panels').css('background', 'transparent');
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mainCheckboxes = document.querySelectorAll('[data-js="checkboxes-toggle"]');
|
||||||
|
if (mainCheckboxes.length) {
|
||||||
|
[...mainCheckboxes].forEach((el) => {
|
||||||
|
el.addEventListener('click', () => {
|
||||||
|
const checkboxes = document.querySelectorAll(el.dataset.toggle);
|
||||||
|
[...checkboxes].forEach((checkbox) => {
|
||||||
|
const checkboxClone = checkbox;
|
||||||
|
checkboxClone.checked = el.checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,6 +20,48 @@ use Wallabag\CoreBundle\Form\Type\SearchEntryType;
|
||||||
|
|
||||||
class EntryController extends Controller
|
class EntryController extends Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/mass", name="mass_action")
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
*/
|
||||||
|
public function massAction(Request $request)
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$values = $request->request->all();
|
||||||
|
|
||||||
|
$action = 'toggle-read';
|
||||||
|
if (isset($values['toggle-star'])) {
|
||||||
|
$action = 'toggle-star';
|
||||||
|
} elseif (isset($values['delete'])) {
|
||||||
|
$action = 'delete';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($values['entry-checkbox'])) {
|
||||||
|
foreach ($values['entry-checkbox'] as $id) {
|
||||||
|
/** @var Entry * */
|
||||||
|
$entry = $this->get('wallabag_core.entry_repository')->findById((int) $id)[0];
|
||||||
|
|
||||||
|
$this->checkUserAction($entry);
|
||||||
|
|
||||||
|
if ('toggle-read' === $action) {
|
||||||
|
$entry->toggleArchive();
|
||||||
|
} elseif ('toggle-star' === $action) {
|
||||||
|
$entry->toggleStar();
|
||||||
|
} elseif ('delete' === $action) {
|
||||||
|
$this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
|
||||||
|
$em->remove($entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'));
|
||||||
|
|
||||||
|
return $this->redirect($redirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $page
|
* @param int $page
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="entry-checkbox">
|
||||||
|
<input type="checkbox" data-js="entry-checkbox" name="entry-checkbox[]" value="{{ entry.id }}" />
|
||||||
|
</div>
|
|
@ -1,4 +1,5 @@
|
||||||
<div class="card-stacked">
|
<div class="card-stacked">
|
||||||
|
{% include "@WallabagCore/themes/material/Entry/Card/_mass_checkbox.html.twig" with {'entry': entry} only %}
|
||||||
<div class="card-preview">
|
<div class="card-preview">
|
||||||
<a href="{{ path('view', { 'id': entry.id }) }}">
|
<a href="{{ path('view', { 'id': entry.id }) }}">
|
||||||
{% set previewClassModifier = entry.previewPicture ? '' : ' preview--default' %}
|
{% set previewClassModifier = entry.previewPicture ? '' : ' preview--default' %}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{% if currentRoute == 'homepage' %}
|
{% if currentRoute == 'homepage' %}
|
||||||
{% set currentRoute = 'unread' %}
|
{% set currentRoute = 'unread' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<form name="form_mass_action" action="{{ path('mass_action') }}" method="post">
|
||||||
<div class="results">
|
<div class="results">
|
||||||
<div class="nb-results">
|
<div class="nb-results">
|
||||||
{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}
|
{{ 'entry.list.number_on_the_page'|transchoice(entries.count) }}
|
||||||
|
@ -38,6 +39,21 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="{% if listMode == 1 %}collection{% else %}row data{% endif %}">
|
<ul class="{% if listMode == 1 %}collection{% else %}row data{% endif %}">
|
||||||
|
|
||||||
|
<li class="mass-buttons">
|
||||||
|
{% if entries.count > 0 and listMode == 1 %}
|
||||||
|
<span>
|
||||||
|
<input id="selectAll" type="checkbox" data-toggle="[data-js='entry-checkbox']" data-js="checkboxes-toggle" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<button class="btn cyan darken-1" type="submit" name="toggle-read" title="{{ 'entry.list.toogle_as_read'|trans }}"><i class="material-icons">done</i></button>
|
||||||
|
<button class="btn cyan darken-1" type="submit" name="toggle-star" title="{{ 'entry.list.toogle_as_star'|trans }}" ><i class="material-icons">star</i></button>
|
||||||
|
<button class="btn cyan darken-1" type="submit" name="delete" title="{{ 'entry.list.delete'|trans }}"><i class="material-icons">delete</i></button>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
|
||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<li id="entry-{{ entry.id|e }}" class="entry col {% if listMode == 0 %}l3 m6{% else %}collection-item{% endif %} s12">
|
<li id="entry-{{ entry.id|e }}" class="entry col {% if listMode == 0 %}l3 m6{% else %}collection-item{% endif %} s12">
|
||||||
{% if listMode == 1 %}
|
{% if listMode == 1 %}
|
||||||
|
@ -50,6 +66,7 @@
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
</form>
|
||||||
|
|
||||||
{% if entries.getNbPages > 1 %}
|
{% if entries.getNbPages > 1 %}
|
||||||
<div class="results">
|
<div class="results">
|
||||||
|
|
|
@ -1557,4 +1557,81 @@ class EntryControllerTest extends WallabagCoreTestCase
|
||||||
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
$this->assertContains('/view/', $client->getResponse()->getTargetUrl(), 'All random');
|
$this->assertContains('/view/', $client->getResponse()->getTargetUrl(), 'All random');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMass()
|
||||||
|
{
|
||||||
|
$this->logInAs('admin');
|
||||||
|
$client = $this->getClient();
|
||||||
|
|
||||||
|
$entry1 = new Entry($this->getLoggedInUser());
|
||||||
|
$entry1->setUrl($this->url);
|
||||||
|
$this->getEntityManager()->persist($entry1);
|
||||||
|
|
||||||
|
$entry2 = new Entry($this->getLoggedInUser());
|
||||||
|
$entry2->setUrl($this->url);
|
||||||
|
$this->getEntityManager()->persist($entry2);
|
||||||
|
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
$this->getEntityManager()->clear();
|
||||||
|
|
||||||
|
$entries = [];
|
||||||
|
$entries[] = $entry1->getId();
|
||||||
|
$entries[] = $entry2->getId();
|
||||||
|
|
||||||
|
// Mass actions : archive
|
||||||
|
$client->request('POST', '/mass', [
|
||||||
|
'toggle-archive' => '',
|
||||||
|
'entry-checkbox' => $entries,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$res = $client->getContainer()
|
||||||
|
->get('doctrine.orm.entity_manager')
|
||||||
|
->getRepository('WallabagCoreBundle:Entry')
|
||||||
|
->find($entry1->getId());
|
||||||
|
|
||||||
|
$this->assertSame(1, $res->isArchived());
|
||||||
|
|
||||||
|
$res = $client->getContainer()
|
||||||
|
->get('doctrine.orm.entity_manager')
|
||||||
|
->getRepository('WallabagCoreBundle:Entry')
|
||||||
|
->find($entry2->getId());
|
||||||
|
|
||||||
|
$this->assertSame(1, $res->isArchived());
|
||||||
|
|
||||||
|
// Mass actions : star
|
||||||
|
$client->request('POST', '/mass', [
|
||||||
|
'toggle-star' => '',
|
||||||
|
'entry-checkbox' => $entries,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(302, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$res = $client->getContainer()
|
||||||
|
->get('doctrine.orm.entity_manager')
|
||||||
|
->getRepository('WallabagCoreBundle:Entry')
|
||||||
|
->find($entry1->getId());
|
||||||
|
|
||||||
|
$this->assertSame(1, $res->isStarred());
|
||||||
|
|
||||||
|
$res = $client->getContainer()
|
||||||
|
->get('doctrine.orm.entity_manager')
|
||||||
|
->getRepository('WallabagCoreBundle:Entry')
|
||||||
|
->find($entry2->getId());
|
||||||
|
|
||||||
|
$this->assertSame(1, $res->isStarred());
|
||||||
|
|
||||||
|
// Mass actions : delete
|
||||||
|
$client->request('POST', '/mass', [
|
||||||
|
'delete' => '',
|
||||||
|
'entry-checkbox' => $entries,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$client->request('GET', '/delete/' . $entry1->getId());
|
||||||
|
$this->assertSame(404, $client->getResponse()->getStatusCode());
|
||||||
|
|
||||||
|
$client->request('GET', '/delete/' . $entry2->getId());
|
||||||
|
$this->assertSame(404, $client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue