33 *
44 * How to use in your template :
55 *
6- * 1. attach JS module to the container containing : SELECT element, all posts, pagination
6+ * 1. attach JS module to the container containing : SELECT element, filter links, all posts, pagination
77 *
8- * <section data-module="filtered-posts-list" data-filtered-posts-list ></section>
8+ * <section data-module="filtered-posts-list"></section>
99 *
10- * 2. attach data-selector to SELECT element
10+ * 2. attach data-selector to SELECT element AND filter links
1111 *
12- * <select class="my-ctp-archive__filter" data-filtered-posts-list-filters >
12+ * <select class="my-ctp-archive__filter" data-filtered-posts-list-filters>
1313 * <option value="{{ my-ctp_archive_link }}">{{ __('Filter by', 'mill3wp') }}</option>
1414 * <option value="{{ term.link }}">{{ term.name }}</option>
15+ *
16+ * <nav class="my-cpt-archive__links" data-filtered-posts-list-links>
17+ * <a href="#">All</a>
18+ * <a href="#">Filter 1</a>
19+ * <a href="#">Filter 2</a>
20+ * </nav>
1521 *
1622 * 3. attach data-selector to posts container
1723 *
18- * <ol data-filtered-posts-list-results >
24+ * <ol data-filtered-posts-list-results>
1925 * {% for post in posts %}
2026 * ...
2127 * </ol>
2228 *
2329 * 4. attach data-selector to pagination element
2430 *
2531 * <div data-filtered-posts-list-pagination>
26- * {% include 'partial/pagination.twig' }
32+ * {% include 'partial/pagination.twig' % }
2733 * </div>
2834 *
2935*/
@@ -36,6 +42,7 @@ import { on, off } from "@utils/listener";
3642
3743const LOCKED_CLASSNAME = "--js-filtered-posts-list-locked" ;
3844const FILTERS_SELECTOR = "[data-filtered-posts-list-filters]" ;
45+ const LINKS_SELECTOR = "[data-filtered-posts-list-links]" ;
3946const PAGINATION_SELECTOR = "[data-filtered-posts-list-pagination]" ;
4047const RESULTS_SELECTOR = "[data-filtered-posts-list-results]" ;
4148
@@ -45,6 +52,7 @@ class FilteredPostsList {
4552 this . emitter = emitter ;
4653
4754 this . filters = $ ( FILTERS_SELECTOR , this . el ) ;
55+ this . links = $ ( LINKS_SELECTOR , this . el ) ;
4856 this . pagination = $ ( PAGINATION_SELECTOR , this . el ) ;
4957 this . results = $ ( RESULTS_SELECTOR , this . el ) ;
5058
@@ -54,6 +62,7 @@ class FilteredPostsList {
5462 this . _newResultsHTML = null ;
5563
5664 this . _onTypeChange = this . _onTypeChange . bind ( this ) ;
65+ this . _onLinkClick = this . _onLinkClick . bind ( this ) ;
5766 this . _onAjaxCallback = this . _onAjaxCallback . bind ( this ) ;
5867 this . _onAjaxResponse = this . _onAjaxResponse . bind ( this ) ;
5968 this . _onAjaxError = this . _onAjaxError . bind ( this ) ;
@@ -70,6 +79,7 @@ class FilteredPostsList {
7079 this . el = null ;
7180 this . emitter = null ;
7281 this . filters = null ;
82+ this . links = null ;
7383 this . pagination = null ;
7484 this . results = null ;
7585
@@ -79,6 +89,7 @@ class FilteredPostsList {
7989 this . _newResultsHTML = null ;
8090
8191 this . _onTypeChange = null ;
92+ this . _onLinkClick = null ;
8293 this . _onAjaxCallback = null ;
8394 this . _onAjaxResponse = null ;
8495 this . _onAjaxError = null ;
@@ -88,9 +99,11 @@ class FilteredPostsList {
8899
89100 _bindEvents ( ) {
90101 if ( this . filters ) on ( this . filters , 'change' , this . _onTypeChange ) ;
102+ if ( this . links ) on ( this . links , 'click' , this . _onLinkClick ) ;
91103 }
92104 _unbindEvents ( ) {
93105 if ( this . filters ) off ( this . filters , 'change' , this . _onTypeChange ) ;
106+ if ( this . links ) off ( this . links , 'click' , this . _onLinkClick ) ;
94107 }
95108
96109 _onTypeChange ( ) {
@@ -108,6 +121,39 @@ class FilteredPostsList {
108121 . then ( this . _onAjaxResponse )
109122 . catch ( this . _onAjaxError ) ;
110123 }
124+ _onLinkClick ( event ) {
125+ if ( event ) {
126+ event . preventDefault ( ) ;
127+ event . stopImmediatePropagation ( ) ;
128+ }
129+
130+
131+ let href , target = event . target ;
132+
133+ // check all parent elements until we reach [data-filtered-posts-list-links]
134+ while ( target && target !== this . links ) {
135+ if ( target . tagName . toString ( ) . toUpperCase ( ) === 'A' ) {
136+ href = target . href ;
137+ break ;
138+ }
139+
140+ target = target . parentElement ;
141+ }
142+
143+ if ( ! href ) return ;
144+
145+ // replace current history state
146+ windmill . replace ( href ) ;
147+
148+ // block UI
149+ if ( this . el ) this . el . classList . add ( LOCKED_CLASSNAME ) ;
150+
151+ // fetch HTML
152+ fetch ( href )
153+ . then ( this . _onAjaxCallback )
154+ . then ( this . _onAjaxResponse )
155+ . catch ( this . _onAjaxError ) ;
156+ }
111157 _onAjaxCallback ( response ) {
112158 // stop here if module has been destroyed during Fetch request
113159 if ( ! this . el ) return ;
@@ -125,6 +171,8 @@ class FilteredPostsList {
125171
126172 const doc = this . _parser . parseFromString ( html , "text/html" ) ;
127173 const title = $ ( 'html title' , doc ) ;
174+ const filters = $ ( FILTERS_SELECTOR , doc ) ;
175+ const links = $ ( LINKS_SELECTOR , doc ) ;
128176 const results = $ ( RESULTS_SELECTOR , doc ) ;
129177 const pagination = $ ( PAGINATION_SELECTOR , doc ) ;
130178
@@ -134,6 +182,10 @@ class FilteredPostsList {
134182 return ;
135183 }
136184
185+ // update filters and links immediately
186+ if ( filters && this . filters ) this . filters . innerHTML = filters . innerHTML ;
187+ if ( links && this . links ) this . links . innerHTML = links . innerHTML ;
188+
137189 // save new content
138190 this . _newPageTitle = title . innerText ;
139191 this . _newResultsHTML = results . innerHTML ;
0 commit comments