Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions resources/js/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import './select/slimSelect'
import './pg-dropdown'
import './pg-export'
import './pg-toggle-detail'
import './pg-select-all'
import './pg-filter-panel'
import './directives'
import '../plugins'
62 changes: 62 additions & 0 deletions resources/js/components/pg-select-all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
window.pgAlpine.data('pgSelectAll', () => ({
init() {
this.pgTable = this.$el.closest('table')

this.onRowChange = (event) => {
const target = event.target

if (target === this.$el || !(target instanceof HTMLInputElement) || target.type !== 'checkbox') {
return
}

this.refresh()
}

this.pgTable?.addEventListener('change', this.onRowChange)

this.onFinished = () => this.refresh()
window.addEventListener('pg-select-all:refresh', this.onFinished)

this.$nextTick(() => this.refresh())
},

destroy() {
this.pgTable?.removeEventListener('change', this.onRowChange)
window.removeEventListener('pg-select-all:refresh', this.onFinished)
},

refresh() {
const table = this.pgTable

if (!table) {
return
}

const boxes = Array.from(table.querySelectorAll('tbody input[type="checkbox"]'))
.filter((checkbox) => !checkbox.disabled)

const total = boxes.length
const checked = boxes.filter((checkbox) => checkbox.checked).length

this.$el.checked = total > 0 && checked === total
this.$el.indeterminate = checked > 0 && checked < total
},
}))

if (!window.pgSelectAllCommitHook) {
window.pgSelectAllCommitHook = true

document.addEventListener('DOMContentLoaded', () => {
if (!window.Livewire) {
return
}

Livewire.hook('commit', ({ succeed }) => {
succeed(() => {
requestAnimationFrame(() => {
window.dispatchEvent(new CustomEvent('pg-select-all:refresh'))
})
})
})
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
<div class="{{ theme('checkbox.base') }}">
<label class="{{ theme('checkbox.label') }}">
<input
x-data="pgSelectAll"
class="{{ theme('checkbox.input') }}"
type="checkbox"
wire:click="selectCheckboxAll"
wire:model="checkboxAll"
x-on:change="$wire.selectCheckboxAll($event.target.checked)"
>
</label>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
<div class="{{ theme('table.checkbox.base') }}">
<label class="{{ theme('table.checkbox.label') }}">
<input
x-data="pgSelectAll"
class="{{ theme('table.checkbox.input') }}"
type="checkbox"
wire:click="selectCheckboxAll"
wire:model="checkboxAll"
x-on:change="$wire.selectCheckboxAll($event.target.checked)"
>
</label>
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/Concerns/Checkbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ trait Checkbox
/**
* @throws Exception|Throwable
*/
public function selectCheckboxAll(): void
public function selectCheckboxAll(?bool $checked = null): void
{
if ($checked !== null) {
$this->checkboxAll = $checked;
}

if (! $this->checkboxAll) {
$this->checkboxValues = [];

Expand Down
4 changes: 4 additions & 0 deletions src/PowerGridComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public function setSummaryValues(array $values): void

public function resetToFirstPage(string $pageName = 'page'): void
{
if ((int) $this->getPage($pageName) === 1) {
return;
}

$this->gotoPage(1, $pageName);
}

Expand Down
141 changes: 141 additions & 0 deletions tests/Feature/CheckboxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,147 @@ public function columns(): array
->toBe([]);
});

it('resetToFirstPage does not navigate when already on the first page', function () {
$component = new class() extends PowerGridComponent
{
public string $tableName = 'test-reset-first-page';

/** @var array<int, mixed> */
public array $gotoPageCalls = [];

public function datasource()
{
return collect([
['id' => 1, 'name' => 'Dish 1'],
['id' => 2, 'name' => 'Dish 2'],
]);
}

public function gotoPage($page, $pageName = 'page'): void
{
$this->gotoPageCalls[] = $page;

parent::gotoPage($page, $pageName);
}

public function setUp(): array
{
return [
PowerGrid::footer()->showPerPage(10),
];
}

public function fields(): PowerGridFields
{
return PowerGrid::fields()->add('id')->add('name');
}

public function columns(): array
{
return [Column::make('Id', 'id'), Column::make('Name', 'name')];
}
};

$lw = Livewire::test($component::class);

$lw->call('resetToFirstPage');
expect($lw->get('gotoPageCalls'))->toBe([]);

$lw->call('gotoPage', 3)
->call('resetToFirstPage');
expect($lw->get('gotoPageCalls'))->toContain(1);
});

it('preserves the row selection when the per-page size changes', function () {
$component = new class() extends PowerGridComponent
{
public string $tableName = 'test-checkbox-perpage-change';

public function datasource()
{
$data = [];
for ($i = 1; $i <= 30; $i++) {
$data[] = ['id' => $i, 'name' => 'Dish '.$i];
}

return collect($data);
}

public function setUp(): array
{
$this->showCheckBox();

return [
PowerGrid::footer()->showPerPage(10, [10, 30]),
];
}

public function fields(): PowerGridFields
{
return PowerGrid::fields()->add('id')->add('name');
}

public function columns(): array
{
return [Column::make('Id', 'id'), Column::make('Name', 'name')];
}
};

$lw = Livewire::test($component::class)
->set('checkboxAll', true)
->call('selectCheckboxAll');

expect($lw->checkboxValues)->toMatchArray(range(1, 10));

$lw->set('setUp.footer.perPage', 30);

expect($lw->checkboxValues)->toMatchArray(range(1, 10));
});

it('selectCheckboxAll honours the explicit checked intent argument', function () {
$component = new class() extends PowerGridComponent
{
public string $tableName = 'test-checkbox-intent';

public function datasource()
{
return collect([
['id' => 1, 'name' => 'Dish 1'],
['id' => 2, 'name' => 'Dish 2'],
['id' => 3, 'name' => 'Dish 3'],
]);
}

public function setUp(): array
{
$this->showCheckBox();

return [PowerGrid::footer()->showPerPage(10)];
}

public function fields(): PowerGridFields
{
return PowerGrid::fields()->add('id')->add('name');
}

public function columns(): array
{
return [Column::make('Id', 'id'), Column::make('Name', 'name')];
}
};

$lw = Livewire::test($component::class)
->call('selectCheckboxAll', true);

expect($lw->get('checkboxAll'))->toBeTrue()
->and($lw->checkboxValues)->toMatchArray(['1', '2', '3']);

$lw->call('selectCheckboxAll', false);

expect($lw->get('checkboxAll'))->toBeFalse()
->and($lw->checkboxValues)->toBe([]);
});

it('selectCheckboxAll works properly with actionRules disable', function () {
$component = new class() extends PowerGridComponent
{
Expand Down
Loading