-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
519 additions
and
231 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
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,105 @@ | ||
/*! | ||
* This file is part of the Sonata Project package. | ||
* | ||
* (c) Thomas Rabaix <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import qs from 'qs'; | ||
import { Controller } from '@hotwired/stimulus'; | ||
import { controlValue, convertQueryStringToObject } from '../utils'; | ||
|
||
export default class extends Controller { | ||
static targets = ['form', 'group', 'advanced', 'submitter']; | ||
static outlets = ['filter-list']; | ||
static values = { | ||
defaultValues: Object, | ||
}; | ||
|
||
connect() { | ||
const withAdvanced = this.advancedTargets.find((advanced) => !advanced.hidden) !== null; | ||
this.advancedTargets.forEach((advanced) => { | ||
advanced.hidden = !withAdvanced; | ||
}); | ||
} | ||
|
||
prepareSubmit() { | ||
const defaults = convertQueryStringToObject( | ||
qs.stringify({ | ||
filter: this.defaultValuesValue, | ||
}) | ||
); | ||
|
||
const changed = []; | ||
this.formElements.forEach((element) => { | ||
const defaultValue = element.multiple ? [] : ''; | ||
const defaultElementValue = defaults[element.name] || defaultValue; | ||
const elementValue = controlValue(element) || defaultValue; | ||
|
||
if (element.closest('[hidden]')) { | ||
element.removeAttribute('name'); | ||
} else if (JSON.stringify(defaultElementValue) === JSON.stringify(elementValue)) { | ||
element.removeAttribute('name'); | ||
} else if (element.multiple && JSON.stringify(elementValue) === '[]') { | ||
// Empty array values will not be submitted, but we need to override | ||
// the default value provided by `AdminInterface::getDefaultFilterParameters()`. | ||
// So we change the empty select to an empty input in order to have a submitted value. | ||
// @see https://github.com/sonata-project/SonataAdminBundle/issues/7547 | ||
|
||
// We remove the `[]` from the select name in order to generate the input name | ||
const name = element.name.substring(0, element.name.length - 2); | ||
const input = document.createElement('input'); | ||
input.type = 'hidden'; | ||
input.name = name; | ||
input.value = ''; | ||
|
||
this.formTarget.appendChild(input); | ||
element.removeAttribute('name'); | ||
} else { | ||
changed.push(element); | ||
} | ||
}); | ||
|
||
if (changed.length === 0) { | ||
const input = document.createElement('input'); | ||
input.type = 'hidden'; | ||
input.name = 'filters'; | ||
input.value = 'reset'; | ||
|
||
this.formTarget.appendChild(input); | ||
} | ||
|
||
this.submitterTarget.disabled = true; | ||
} | ||
|
||
toggleAdvanced() { | ||
this.advancedTargets.forEach((advanced) => { | ||
advanced.hidden = !advanced.hidden; | ||
}); | ||
} | ||
|
||
toggleFilter(id, state) { | ||
const group = this.groupTargets.find((el) => id === el.id); | ||
if (group) { | ||
group.hidden = !state; | ||
this.element.hidden = !this.visibleGroups.length; | ||
} | ||
} | ||
|
||
hideFilter({ params }) { | ||
this.toggleFilter(params.id, false); | ||
this.filterListOutlet.disable(params.id); | ||
} | ||
|
||
get visibleGroups() { | ||
return this.groupTargets.filter((group) => !group.hidden); | ||
} | ||
|
||
get formElements() { | ||
return Array.from(this.formTarget.elements) | ||
.filter((tag) => ['select', 'textarea', 'input'].includes(tag.tagName.toLowerCase())) | ||
.filter((element) => element.name.includes('filter')); | ||
} | ||
} |
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,47 @@ | ||
/*! | ||
* This file is part of the Sonata Project package. | ||
* | ||
* (c) Thomas Rabaix <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { Controller } from '@hotwired/stimulus'; | ||
|
||
export default class extends Controller { | ||
static targets = ['counter', 'field']; | ||
static outlets = ['filter']; | ||
static classes = ['active']; | ||
|
||
connect() { | ||
this.updateCounter(); | ||
} | ||
|
||
updateCounter() { | ||
this.counterTarget.innerHTML = this.enabledFields.length; | ||
} | ||
|
||
disable(id) { | ||
const field = this.fieldTargets.find((el) => id === el.dataset.filter); | ||
if (field) { | ||
field.classList.remove(this.activeClass); | ||
this.updateCounter(); | ||
} | ||
} | ||
|
||
toggle(event) { | ||
const field = event.target; | ||
const state = field.classList.contains(this.activeClass); | ||
field.classList.toggle(this.activeClass, !state); | ||
|
||
this.filterOutlet.toggleFilter(field.dataset.filter, !state); | ||
this.updateCounter(); | ||
} | ||
|
||
get enabledFields() { | ||
return this.fieldTargets.filter((field) => { | ||
return field.classList.contains(this.activeClass); | ||
}); | ||
} | ||
} |
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 @@ | ||
/*! | ||
* This file is part of the Sonata Project package. | ||
* | ||
* (c) Thomas Rabaix <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
export function controlValue(el) { | ||
if (el.options && el.multiple) { | ||
// prettier-ignore | ||
return el.options | ||
.filter((option) => option.selected) | ||
.map((option) => option.value); | ||
} | ||
|
||
return el.value; | ||
} | ||
|
||
export function convertQueryStringToObject(str) { | ||
return str.split('&').reduce((accumulator, keyValue) => { | ||
const key = decodeURIComponent(keyValue.split('=')[0]); | ||
const val = keyValue.split('=')[1]; | ||
|
||
if (key.endsWith('[]')) { | ||
if (!Object.prototype.hasOwnProperty.call(accumulator, key)) { | ||
accumulator[key] = []; | ||
} | ||
accumulator[key].push(val); | ||
} else { | ||
accumulator[key] = val; | ||
} | ||
|
||
return accumulator; | ||
}, {}); | ||
} |
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
Oops, something went wrong.