1
1
<nav class =" navbar navbar-expand-lg navbar-filters mb-0 py-0 shadow-none" >
2
- {{-- Brand and toggle get grouped for better mobile display --}}
3
- <a class =" nav-item d-none d-lg-block my-auto" ><span class =" la la-filter" ></span ></a >
4
- <button class =" navbar-toggler ms-3"
5
- type =" button"
6
- data-toggle =" collapse" {{-- for Bootstrap v4 --}}
7
- data-target =" #bp-filters-navbar" {{-- for Bootstrap v4 --}}
8
- data-bs-toggle =" collapse" {{-- for Bootstrap v5 --}}
9
- data-bs-target =" #bp-filters-navbar" {{-- for Bootstrap v5 --}}
10
- aria-controls =" bp-filters-navbar"
11
- aria-expanded =" false"
12
- aria-label =" {{ trans (' backpack::crud.toggle_filters' ) } }" >
2
+ {{-- Brand and toggle get grouped for better mobile display --}}
3
+ <a class =" nav-item d-none d-lg-block my-auto" ><span class =" la la-filter" ></span ></a >
4
+ <button class =" navbar-toggler ms-3"
5
+ type =" button"
6
+ data-toggle =" collapse" {{-- for Bootstrap v4 --}}
7
+ data-target =" #bp-filters-navbar" {{-- for Bootstrap v4 --}}
8
+ data-bs-toggle =" collapse" {{-- for Bootstrap v5 --}}
9
+ data-bs-target =" #bp-filters-navbar" {{-- for Bootstrap v5 --}}
10
+ aria-controls =" bp-filters-navbar"
11
+ aria-expanded =" false"
12
+ aria-label =" {{ trans (' backpack::crud.toggle_filters' ) } }" >
13
13
<span class =" la la-filter" ></span > {{ trans (' backpack::crud.filters' ) } }
14
- </button >
14
+ </button >
15
15
16
- {{-- Collect the nav links, forms, and other content for toggling --}}
17
- <div class =" collapse navbar-collapse" id =" bp-filters-navbar" >
16
+ {{-- Collect the nav links, forms, and other content for toggling --}}
17
+ <div class =" collapse navbar-collapse" id =" bp-filters-navbar" >
18
18
<ul class =" nav navbar-nav" >
19
- {{-- THE ACTUAL FILTERS --}}
20
- @foreach ($crud -> filters () as $filter )
21
- @includeFirst ($filter -> getNamespacedViewWithFallbacks () )
22
- @endforeach
23
- <li class =" nav-item" ><a href =" #" id = " remove_filters_button " class =" nav-link {{ count (Request:: input ()) != 0 ? ' ' : ' invisible' } }" ><i class =" la la-eraser" ></i > {{ trans (' backpack::crud.remove_filters' ) } } </a ></li >
19
+ {{-- THE ACTUAL FILTERS --}}
20
+ @foreach ($crud -> filters () as $filter )
21
+ @includeFirst ($filter -> getNamespacedViewWithFallbacks () )
22
+ @endforeach
23
+ <li class =" nav-item" ><a href =" #" class =" nav-link remove_filters_button {{ count (Request:: input ()) != 0 ? ' ' : ' invisible' } }" ><i class =" la la-eraser" ></i > {{ trans (' backpack::crud.remove_filters' ) } } </a ></li >
24
24
</ul >
25
- </div >{{-- /.navbar-collapse --}}
26
- </nav >
27
-
28
- @push (' crud_list_scripts ' )
25
+ </div >{{-- /.navbar-collapse --}}
26
+ </nav >
27
+
28
+ @push (' after_scripts ' )
29
29
@basset (
' https://unpkg.com/[email protected] /src/URI.min.js' )
30
30
<script >
31
- function addOrUpdateUriParameter (uri , parameter , value ) {
32
- var new_url = normalizeAmpersand (uri);
33
-
34
- new_url = URI (new_url).normalizeQuery ();
31
+ if (typeof addOrUpdateUriParameter !== ' function' ) {
32
+ function addOrUpdateUriParameter (uri , parameter , value ) {
33
+ let new_url = URI (uri).normalizeQuery ();
35
34
36
35
// this param is only needed in datatables persistent url redirector
37
36
// not when applying filters so we remove it.
@@ -40,106 +39,160 @@ function addOrUpdateUriParameter(uri, parameter, value) {
40
39
}
41
40
42
41
if (new_url .hasQuery (parameter)) {
43
- new_url .removeQuery (parameter);
42
+ new_url .removeQuery (parameter);
44
43
}
45
44
46
45
if (value !== ' ' && value != null ) {
47
- new_url = new_url .addQuery (parameter, value);
46
+ new_url = new_url .addQuery (parameter, value);
48
47
}
49
48
50
49
$ (' #remove_filters_button' ).toggleClass (' invisible' , ! new_url .query ());
51
50
52
- return new_url .toString ();
53
-
54
- }
55
-
56
- function updateDatatablesOnFilterChange (filterName , filterValue , update_url = false , debounce = 500 ) {
57
- // behaviour for ajax table
58
- var current_url = crud .table .ajax .url ();
59
- var new_url = addOrUpdateUriParameter (current_url, filterName, filterValue);
60
-
61
- new_url = normalizeAmpersand (new_url);
62
-
63
- // add filter to URL
64
- crud .updateUrl (new_url);
65
- crud .table .ajax .url (new_url);
66
-
67
- // when we are clearing ALL filters, we would not update the table url here, because this is done PER filter
68
- // and we have a function that will do this update for us after all filters had been cleared.
69
- if (update_url) {
70
- // replace the datatables ajax url with new_url and reload it
71
- callFunctionOnce (function () { refreshDatatablesOnFilterChange (new_url) }, debounce, ' refreshDatatablesOnFilterChange' );
51
+ return new_url .normalizeQuery ().toString ();
52
+ }
53
+ }
54
+
55
+ if (typeof updatePageUrl !== ' function' ) {
56
+ function updatePageUrl (filterName , filterValue , currentUrl = null ) {
57
+ currentUrl = currentUrl || window .location .href ;
58
+ let newUrl = addOrUpdateUriParameter (currentUrl, filterName, filterValue);
59
+ crud .updateUrl (newUrl);
60
+ return newUrl;
72
61
}
62
+ }
63
+
64
+ if (typeof updateDatatablesOnFilterChange !== ' function' ) {
65
+ function updateDatatablesOnFilterChange (filterName , filterValue , update_url = false , debounce = 500 ) {
66
+ // behaviour for ajax tables
67
+ let new_url = updatePageUrl (filterName, filterValue, crud .table .ajax .url ());
68
+ crud .table .ajax .url (new_url);
69
+
70
+ // when we are clearing ALL filters, we would not update the table url here, because this is done PER filter
71
+ // and we have a function that will do this update for us after all filters had been cleared.
72
+ if (update_url) {
73
+ // replace the datatables ajax url with new_url and reload it
74
+ callFunctionOnce (function () { refreshDatatablesOnFilterChange (new_url) }, debounce, ' refreshDatatablesOnFilterChange' );
75
+ }
73
76
74
- return new_url;
75
- }
76
-
77
- /* *
78
- * calls the function func once within the within time window.
79
- * this is a debounce function which actually calls the func as
80
- * opposed to returning a function that would call func.
81
- *
82
- * @param func the function to call
83
- * @param within the time window in milliseconds, defaults to 300
84
- * @param timerId an optional key, defaults to func
85
- *
86
- * FROM: https://stackoverflow.com/questions/27787768/debounce-function-in-jquery
87
- */
88
- if (typeof callFunctionOnce !== ' function' ) {
77
+ return new_url;
78
+ }
79
+ }
80
+
81
+ /* *
82
+ * calls the function func once within the within time window.
83
+ * this is a debounce function which actually calls the func as
84
+ * opposed to returning a function that would call func.
85
+ *
86
+ * @param func the function to call
87
+ * @param within the time window in milliseconds, defaults to 300
88
+ * @param timerId an optional key, defaults to func
89
+ *
90
+ * FROM: https://stackoverflow.com/questions/27787768/debounce-function-in-jquery
91
+ */
92
+ if (typeof callFunctionOnce !== ' function' ) {
89
93
function callFunctionOnce (func , within = 300 , timerId = null ) {
90
- window .callOnceTimers = window .callOnceTimers || {};
91
- timerId = timerId || func;
92
- if (window .callOnceTimers [timerId]) {
93
- clearTimeout (window .callOnceTimers [timerId]);
94
- }
95
- window .callOnceTimers [timerId] = setTimeout (func, within);
94
+ window .callOnceTimers = window .callOnceTimers || {};
95
+ timerId = timerId || func;
96
+ if (window .callOnceTimers [timerId]) {
97
+ clearTimeout (window .callOnceTimers [timerId]);
98
+ }
99
+ window .callOnceTimers [timerId] = setTimeout (func, within);
96
100
}
97
- }
98
-
99
- function refreshDatatablesOnFilterChange (url )
100
- {
101
- // replace the datatables ajax url with new_url and reload it
102
- crud .table .ajax .url (url).load ();
103
- }
101
+ }
104
102
103
+ if (typeof refreshDatatablesOnFilterChange !== ' function' ) {
104
+ function refreshDatatablesOnFilterChange (url )
105
+ {
106
+ // replace the datatables ajax url with new_url and reload it
107
+ crud .table .ajax .url (url).load ();
108
+ }
109
+ }
105
110
106
- function normalizeAmpersand (string ) {
107
- return string .replace (/ &/ g , " &" ).replace (/ amp%3B/ g , " " );
108
- }
111
+ // button to remove all filters
112
+ document .addEventListener (' DOMContentLoaded' , function () {
109
113
110
- // button to remove all filters
111
- jQuery (document ).ready (function ($ ) {
112
- $ (" #remove_filters_button" ).click (function (e ) {
113
- e .preventDefault ();
114
+ // find all nav.navbar-filters
115
+ let filtersNavbar = document .querySelectorAll (' .navbar-filters' );
114
116
115
- // behaviour for ajax table
116
- var new_url = ' {{ url ($crud -> getOperationSetting (" datatablesUrl" ). ' /search' ) } }' ;
117
- var ajax_table = $ (" #crudTable" ).DataTable ();
117
+ // if there are no navbars, return
118
+ if (! filtersNavbar .length ) {
119
+ return ;
120
+ }
118
121
119
- // replace the datatables ajax url with new_url and reload it
120
- ajax_table .ajax .url (new_url).load ();
122
+ // run the init function for each filter
123
+ filtersNavbar .forEach (function (navbar ) {
124
+ let filters = navbar .querySelectorAll (' li[filter-init-function]' );
121
125
122
- // clear all filters
123
- $ (" .navbar-filters li[filter-name]" ).trigger (' filter:clear' );
126
+ if (filters .length === 0 ) {
127
+ return ;
128
+ }
124
129
125
- // remove filters from URL
126
- crud .updateUrl (new_url);
127
- });
130
+ document .addEventListener (' backpack:filter:changed' , function (event ) {
131
+
132
+ // check if any of the filters are active
133
+ let anyActiveFilters = false ;
134
+
135
+ filters .forEach (function (filter ) {
136
+ if (filter .classList .contains (' active' )) {
137
+ anyActiveFilters = true ;
138
+ }
139
+ });
140
+
141
+ if (anyActiveFilters === true ) {
142
+ navbar .querySelector (' .remove_filters_button' ).classList .remove (' invisible' );
143
+ }else {
144
+ navbar .querySelector (' .remove_filters_button' ).classList .add (' invisible' );
145
+ }
146
+ });
147
+
148
+ filters .forEach (function (filter ) {
149
+ let initFunction = filter .getAttribute (' filter-init-function' );
150
+ if (window [initFunction]) {
151
+ window [initFunction](filter, navbar);
152
+ }
153
+ });
154
+
155
+ if (filtersNavbar .length === 0 ) {
156
+ return ;
157
+ }
128
158
129
- // hide the Remove filters button when no filter is active
130
- $ (" .navbar-filters li[filter-name]" ).on (' filter:clear' , function () {
131
- var anyActiveFilters = false ;
132
- $ (" .navbar-filters li[filter-name]" ).each (function () {
133
- if ($ (this ).hasClass (' active' )) {
134
- anyActiveFilters = true ;
135
- // console.log('ACTIVE FILTER');
159
+ let removeFiltersButton = navbar .querySelector (' .remove_filters_button' );
160
+ if (removeFiltersButton) {
161
+ removeFiltersButton .addEventListener (' click' , function (e ) {
162
+ e .preventDefault ();
163
+
164
+ document .dispatchEvent (new Event (' backpack:filters:cleared' , {
165
+ detail: {
166
+ navbar: navbar,
167
+ filters: filters,
168
+ }
169
+ }));
170
+
171
+ filters .forEach (function (filter ) {
172
+ filter .dispatchEvent (new CustomEvent (' backpack:filter:clear' , {
173
+ detail: {
174
+ clearAllFilters: true ,
175
+ }
176
+ }));
177
+ });
178
+ });
136
179
}
137
- });
138
180
139
- if (anyActiveFilters == false ) {
140
- $ (' #remove_filters_button' ).addClass (' invisible' );
141
- }
181
+ filters .forEach (function (filter ) {
182
+ filter .addEventListener (' backpack:filter:clear' , function () {
183
+ let anyActiveFilters = false ;
184
+ filters .forEach (function (filterInstance ) {
185
+ if (filterInstance .classList .contains (' active' )) {
186
+ anyActiveFilters = true ;
187
+ }
188
+ });
189
+
190
+ if (anyActiveFilters === false ) {
191
+ removeFiltersButton? .classList .add (' invisible' );
192
+ }
193
+ });
194
+ });
142
195
});
143
- });
196
+ });
144
197
< / script>
145
- @endpush
198
+ @endpush
0 commit comments