Lists now features a new YAML option collapsed: [true|false] (default: false) and a new UI/UX that allows for collapsing / expanding collection items, allowing to better managing long lists of items. It is advised to always put as first field the most significant one, so that when a list is collapsed it can be still easily browsed.

Reworked List UI to better handle drag & drop sort. To sort it is now required to use the left drag handle (fixes #724)
This commit is contained in:
Djamil Legato
2016-08-01 17:37:31 -07:00
parent b23a194318
commit 352d80e9a3
10 changed files with 95 additions and 23 deletions

View File

@@ -4,8 +4,10 @@
1. [](#improved) 1. [](#improved)
* Get fresh media list for `Controller::getListMedia()` rather that cache so always latest. * Get fresh media list for `Controller::getListMedia()` rather that cache so always latest.
* Add translation strings for the new system.force_ssl option * Add translation strings for the new system.force_ssl option
* Reworked List UI to better handle drag & drop sort. To sort it is now required to use the left drag handle [#724](https://github.com/getgrav/grav-plugin-admin/issues/724)
* Lists now features a new YAML option `controls: [top|bottom|both]` (default: bottom) which will display the "Add Item" button at the Top and/or Bottom position relative to the list. When the Top button is pressed, a new item will be added at the beginning of the list, when the Bottom button is pressed, a new item will be appended to the list. * Lists now features a new YAML option `controls: [top|bottom|both]` (default: bottom) which will display the "Add Item" button at the Top and/or Bottom position relative to the list. When the Top button is pressed, a new item will be added at the beginning of the list, when the Bottom button is pressed, a new item will be appended to the list.
* Lists now features two new YAML options `sortby: [field]` (default: disabled) and `sortby_dir: [asc|desc]` (default: asc) which will display a new Sorting button in the list allowing to automatically reindex the collection based on the given sort field set. * Lists now features two new YAML options `sortby: [field]` (default: disabled) and `sortby_dir: [asc|desc]` (default: asc) which will display a new Sorting button in the list allowing to automatically reindex the collection based on the given sort field set.
* Lists now features a new YAML option `collapsed: [true|false]` (default: false) and a new UI/UX that allows for collapsing / expanding collection items, allowing to better managing long lists of items. It is advised to always put as first field the most significant one, so that when a list is collapsed it can be still easily browsed.
1. [](#bugfix) 1. [](#bugfix)
* Fixed issue in Admin favicon URL [#704](https://github.com/getgrav/grav-plugin-admin/issues/704) * Fixed issue in Admin favicon URL [#704](https://github.com/getgrav/grav-plugin-admin/issues/704)
* Fixed issue in `selfupgrade` where the package would get downloaded in the wrong destination * Fixed issue in `selfupgrade` where the package would get downloaded in the wrong destination

View File

@@ -17,7 +17,11 @@ export default class CollectionsField {
list.on('click', '> .collection-actions [data-action="add"]', (event) => this.addItem(event)); list.on('click', '> .collection-actions [data-action="add"]', (event) => this.addItem(event));
list.on('click', '> ul > li > .item-actions [data-action="delete"]', (event) => this.removeItem(event)); list.on('click', '> ul > li > .item-actions [data-action="delete"]', (event) => this.removeItem(event));
list.on('click', '> ul > li > .item-actions [data-action="collapse"]', (event) => this.collapseItem(event));
list.on('click', '> ul > li > .item-actions [data-action="expand"]', (event) => this.expandItem(event));
list.on('click', '> .collection-actions [data-action-sort="date"]', (event) => this.sortItems(event)); list.on('click', '> .collection-actions [data-action-sort="date"]', (event) => this.sortItems(event));
list.on('click', '> .collection-actions [data-action="collapse_all"]', (event) => this.collapseItems(event));
list.on('click', '> .collection-actions [data-action="expand_all"]', (event) => this.expandItems(event));
list.on('input', '[data-key-observe]', (event) => this.observeKey(event)); list.on('input', '[data-key-observe]', (event) => this.observeKey(event));
list.find('[data-collection-holder]').each((index, container) => { list.find('[data-collection-holder]').each((index, container) => {
@@ -26,6 +30,7 @@ export default class CollectionsField {
container.data('collection-sort', new Sortable(container.get(0), { container.data('collection-sort', new Sortable(container.get(0), {
forceFallback: false, forceFallback: false,
handle: '.collection-sort',
animation: 150, animation: 150,
filter: '.CodeMirror, .grav-editor-resizer', filter: '.CodeMirror, .grav-editor-resizer',
onUpdate: () => this.reindex(container) onUpdate: () => this.reindex(container)
@@ -74,6 +79,36 @@ export default class CollectionsField {
if (sortAction.length && items.length <= 1) { sortAction.addClass('hidden'); } if (sortAction.length && items.length <= 1) { sortAction.addClass('hidden'); }
} }
collapseItems(event) {
let button = $(event.currentTarget);
let items = $(button.closest('[data-type="collection"]')).find('> ul > [data-collection-item] > .item-actions [data-action="collapse"]');
items.click();
}
collapseItem(event) {
let button = $(event.currentTarget);
let item = button.closest('[data-collection-item]');
button.attr('data-action', 'expand').removeClass('fa-chevron-circle-down').addClass('fa-chevron-circle-right');
item.addClass('collection-collapsed');
}
expandItems(event) {
let button = $(event.currentTarget);
let items = $(button.closest('[data-type="collection"]')).find('> ul > [data-collection-item] > .item-actions [data-action="expand"]');
items.click();
}
expandItem(event) {
let button = $(event.currentTarget);
let item = button.closest('[data-collection-item]');
button.attr('data-action', 'collapse').removeClass('fa-chevron-circle-right').addClass('fa-chevron-circle-down');
item.removeClass('collection-collapsed');
}
sortItems(event) { sortItems(event) {
let button = $(event.currentTarget); let button = $(event.currentTarget);
let sortby = button.data('action-sort'); let sortby = button.data('action-sort');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -702,6 +702,11 @@ form {
} }
} }
} }
.collection-sort {
background: #e9e9e9;
border-right: 1px solid #ddd;
}
} }
.form-fieldset { .form-fieldset {

View File

@@ -435,7 +435,6 @@ textarea.frontmatter {
padding: 0; padding: 0;
> li { > li {
cursor: move;
padding: 1rem; padding: 1rem;
border-radius: $form-border-radius; border-radius: $form-border-radius;
margin: 3px 0; margin: 3px 0;
@@ -446,10 +445,15 @@ textarea.frontmatter {
right: 10px; right: 10px;
top: 4px; top: 4px;
.fa-trash-o { .fa {
cursor: pointer; cursor: pointer;
} }
} }
&.collection-collapsed {
height: 70px;
overflow: hidden;
}
} }
&[data-collection-nosort] > li { &[data-collection-nosort] > li {
@@ -460,6 +464,22 @@ textarea.frontmatter {
.collection-actions { .collection-actions {
text-align: right; text-align: right;
} }
.collection-sort {
position: absolute;
top: 0;
left: 0;
width: 32px;
bottom: 0;
cursor: move;
.fa {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
} }
.form-label.block { .form-label.block {

View File

@@ -39,6 +39,10 @@
<div class="form-list-wrapper {{ field.size }}" data-type="collection"> <div class="form-list-wrapper {{ field.size }}" data-type="collection">
{% if fieldControls in ['top', 'both'] %} {% if fieldControls in ['top', 'both'] %}
<div class="collection-actions{{ not value|length ? ' hidden' : '' }}"> <div class="collection-actions{{ not value|length ? ' hidden' : '' }}">
<button class="button" type="button" data-action="expand_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-down"></i> {{ "PLUGIN_ADMIN.EXPAND_ALL"|e|tu }}</button>
<button class="button" type="button" data-action="collapse_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-right"></i> {{ "PLUGIN_ADMIN.COLLAPSE_ALL"|e|tu }}</button>
{% if field.sortby %} {% if field.sortby %}
<button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}" <button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button>
@@ -54,7 +58,8 @@
{% if field.fields %} {% if field.fields %}
{% for key, val in value %} {% for key, val in value %}
{% set itemName = name ? name ~ '.' ~ key : key %} {% set itemName = name ? name ~ '.' ~ key : key %}
<li data-collection-item="{{ itemName }}" data-collection-key="{{ key }}"> <li data-collection-item="{{ itemName }}" data-collection-key="{{ key }}" class="{{ field.collapsed ? 'collection-collapsed' : '' }}">
<div class="collection-sort"><i class="fa fa-fw fa-bars"></i></div>
{% for childName, child in field.fields %} {% for childName, child in field.fields %}
{% if childName starts with '.' %} {% if childName starts with '.' %}
{% set childKey = childName|trim('.') %} {% set childKey = childName|trim('.') %}
@@ -84,7 +89,7 @@
{% endfor %} {% endfor %}
<div class="item-actions"> <div class="item-actions">
{% if field.sort is not same as(false) %} {% if field.sort is not same as(false) %}
<i class="fa fa-bars"></i> <i class="fa fa-chevron-circle-{{ field.collapsed ? 'right' : 'down' }}" data-action="{{ field.collapsed ? 'expand' : 'collapse' }}"></i>
<br /> <br />
{% endif %} {% endif %}
<i class="fa fa-trash-o" data-action="delete"></i> <i class="fa fa-trash-o" data-action="delete"></i>
@@ -95,6 +100,10 @@
</ul> </ul>
{% if fieldControls in ['bottom', 'both'] %} {% if fieldControls in ['bottom', 'both'] %}
<div class="collection-actions"> <div class="collection-actions">
<button class="button" type="button" data-action="expand_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-down"></i> {{ "PLUGIN_ADMIN.EXPAND_ALL"|e|tu }}</button>
<button class="button" type="button" data-action="collapse_all"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-chevron-circle-right"></i> {{ "PLUGIN_ADMIN.COLLAPSE_ALL"|e|tu }}</button>
{% if field.sortby %} {% if field.sortby %}
<button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}" <button class="button{{ not value|length ? ' hidden' : '' }}" type="button" data-action="sort" data-action-sort="{{ field.sortby }}" data-action-sort-dir="{{ field.sortby_dir|default('asc') }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button> {% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}><i class="fa fa-sort-amount-{{ field.sortby_dir|default('asc') }}"></i> {{ btnSortLabel|e|tu }} '{{ field.sortby }}'</button>
@@ -107,6 +116,7 @@
{%- set itemName = name ? name ~ '.*' : '*' -%} {%- set itemName = name ? name ~ '.*' : '*' -%}
<div style="display: none;" data-collection-template="new" data-collection-template-html="{%- filter replace({' ': ' ', '\n': ' '})|e('html_attr') -%} <div style="display: none;" data-collection-template="new" data-collection-template-html="{%- filter replace({' ': ' ', '\n': ' '})|e('html_attr') -%}
<li data-collection-item="{{ itemName }}"> <li data-collection-item="{{ itemName }}">
<div class="collection-sort"><i class="fa fa-fw fa-bars"></i></div>
{%- if field.fields -%} {%- if field.fields -%}
{%- for childName, child in field.fields -%} {%- for childName, child in field.fields -%}
{%- if childName starts with '.' -%} {%- if childName starts with '.' -%}
@@ -134,7 +144,7 @@
{%- endfor %} {%- endfor %}
<div class="item-actions"> <div class="item-actions">
{% if field.sort is not same as(false) %} {% if field.sort is not same as(false) %}
<i class="fa fa-bars"></i> <i class="fa fa-chevron-circle-down" data-action="collapse"></i>
<br /> <br />
{% endif %} {% endif %}
<i class="fa fa-trash-o" data-action="delete"></i> <i class="fa fa-trash-o" data-action="delete"></i>