diff --git a/app/javascript/packs/controllers/reorder_controller.js b/app/javascript/packs/controllers/reorder_controller.js index 00c94d6e..fd7b2c86 100644 --- a/app/javascript/packs/controllers/reorder_controller.js +++ b/app/javascript/packs/controllers/reorder_controller.js @@ -22,94 +22,9 @@ import { Controller } from 'stimulus' * El objetivo es poder mover filas en tablas de miles de elementos. */ export default class extends Controller { - static targets = [ 'row', 'unselect', 'top', 'bottom', 'direction', 'counter' ] + static targets = [ 'row', 'counter' ] connect () { - // Deseleccionar - this.unselectTarget.addEventListener('click', event => { - event.preventDefault() - event.stopPropagation() - - for (const r of Object.values(this.selected_rows)) { - r.row.querySelector('[data-reorder-handler]').click() - } - }) - - // Enviar arriba de todo - this.topTarget.addEventListener('click', event => { - event.preventDefault() - event.stopPropagation() - - if (this.empty) return - - const rows = this.sorted_rows() - const first = rows[0].row.parentElement.firstElementChild - - for (const r of rows) { - const row = r.row - - if (row === first) continue - - row.parentElement.insertBefore(row, first) - } - - // Reacomodamos el orden - this.reorder() - - // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() - }) - - // Enviar al final - this.bottomTarget.addEventListener('click', event => { - event.preventDefault() - event.stopPropagation() - - if (this.empty) return - - const rows = this.sorted_rows() - - for (const r of rows) { - const row = r.row - - row.parentElement.appendChild(row) - } - - // Reacomodamos el orden - this.reorder() - - // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() - }) - - this.rowTargets.forEach(row => { - // Al cambiar los inputs, mantener la lista de filas actualizadas. - // Necesitamos saber la posición para poder mover las filas en - // orden en lugar del orden en que fueron seleccionadas. - row.querySelector('[data-reorder-handler]').addEventListener('change', event => { - if (event.target.checked) { - this.selected_rows[row.id] = { - row, - order: this.rowTargets.indexOf(row) - } - } else { - delete this.selected_rows[row.id] - } - - this.counter() - }) - }) - - this.directionTargets.forEach(dir => { - dir.addEventListener('click', event => { - event.preventDefault() - event.stopPropagation() - if (this.empty) return - - this.move(dir.dataset.direction) - }) - }) - // Lo asociamos al documento porque en la tabla se pierde el foco // luego del primer evento. document.addEventListener('keydown', event => { @@ -139,6 +54,13 @@ export default class extends Controller { return (Object.keys(this.selected_rows).length === 0) } + /* + * Las filas siempre ordenadas + */ + get sorted_rows () { + return Object.values(this.selected_rows).sort((a,b) => a.order - b.order) + } + /* * Aplica el nuevo orden en las filas y sus campos */ @@ -154,10 +76,6 @@ export default class extends Controller { }) } - sorted_rows () { - return Object.values(this.selected_rows).sort((a,b) => a.order - b.order) - } - move (direction) { if (this.empty) return @@ -166,7 +84,7 @@ export default class extends Controller { const direction_sibling = up ? 'previousElementSibling' : 'nextElementSibling' // Los movemos en orden - const rows = this.sorted_rows() + const rows = this.sorted_rows if (down) rows.reverse() for (const r of rows) { @@ -193,4 +111,102 @@ export default class extends Controller { counter () { this.counterTarget.innerText = Object.keys(this.selected_rows).length } + + // Deseleccionar todos + unselect (event) { + event.preventDefault() + event.stopPropagation() + + for (const r of Object.values(this.selected_rows)) { + r.row.querySelector('[data-action="reorder#select"]').click() + } + } + + // Enviar arriba de todo + top (event) { + event.preventDefault() + event.stopPropagation() + + if (this.empty) return + + const rows = this.sorted_rows + const first = rows[0].row.parentElement.firstElementChild + + for (const r of rows) { + const row = r.row + + if (row === first) continue + + row.parentElement.insertBefore(row, first) + } + + // Reacomodamos el orden + this.reorder() + + // Mantenemos el primero a la vista + rows[0].row.scrollIntoViewIfNeeded() + } + + bottom (event) { + event.preventDefault() + event.stopPropagation() + + if (this.empty) return + + const rows = this.sorted_rows + + for (const r of rows) { + const row = r.row + + row.parentElement.appendChild(row) + } + + // Reacomodamos el orden + this.reorder() + + // Mantenemos el primero a la vista + rows[0].row.scrollIntoViewIfNeeded() + } + + /* + * Al cambiar los inputs, mantener la lista de filas actualizadas. + * Necesitamos saber la posición para poder mover las filas en orden + * en lugar del orden en que fueron seleccionadas. + */ + select (event) { + const row = event.target.closest('tr') + + if (event.target.checked) { + this.selected_rows[row.id] = { + row, + order: this.rowTargets.indexOf(row) + } + } else { + delete this.selected_rows[row.id] + } + + this.counter() + } + + /* + * Mover hacia arriba + */ + up (event) { + event.preventDefault() + event.stopPropagation() + if (this.empty) return + + this.move('up') + } + + /* + * Mover hacia abajo + */ + down (event) { + event.preventDefault() + event.stopPropagation() + if (this.empty) return + + this.move('down') + } } diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 31d608bc..26945b58 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -52,13 +52,13 @@ %tr %th.border-0.background-white.position-sticky{ style: 'top: 0', colspan: '4' } = submit_tag t('posts.reorder.submit'), class: 'btn' - %button.btn{ data: { target: 'reorder.unselect' } } + %button.btn{ data: { action: 'reorder#unselect' } } = t('posts.reorder.unselect') %span.badge{ data: { target: 'reorder.counter' } } 0 - %button.btn{ data: { target: 'reorder.direction', direction: 'up' } }= t('posts.reorder.up') - %button.btn{ data: { target: 'reorder.direction', direction: 'down' } }= t('posts.reorder.down') - %button.btn{ data: { target: 'reorder.top' } }= t('posts.reorder.top') - %button.btn{ data: { target: 'reorder.bottom' } }= t('posts.reorder.bottom') + %button.btn{ data: { action: 'reorder#up' } }= t('posts.reorder.up') + %button.btn{ data: { action: 'reorder#down' } }= t('posts.reorder.down') + %button.btn{ data: { action: 'reorder#top' } }= t('posts.reorder.top') + %button.btn{ data: { action: 'reorder#bottom' } }= t('posts.reorder.bottom') %tbody - dir = t("locales.#{@locale}.dir") - @posts.each_with_index do |post, i| @@ -68,7 +68,7 @@ - cache_if @usuarie, post do %tr{ id: post.uuid.value, data: { target: 'reorder.row' } } %td - %input{ type: 'checkbox', autocomplete: 'off', data: { reorder: { handler: true } } } + %input{ type: 'checkbox', autocomplete: 'off', data: { action: 'reorder#select' } } -# Orden más alto es mayor prioridad = hidden_field 'post[reorder]', post.uuid.value, value: @posts.length - i,