@penskemediacorp/larva-js 1.24.1 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/video-showcase.js +7 -7
- package/package.json +2 -2
- package/src/__tests__/fixtures/markup.js +1 -1
- package/src/__tests__/utils/removeDesktopXlClasses.test.js +6 -4
- package/src/interface/Collapsible/Collapsible.js +31 -17
- package/src/interface/Collapsible/index.js +6 -2
- package/src/interface/EmailCapture/EmailCapture.js +17 -13
- package/src/interface/EmailCapture/index.js +6 -3
- package/src/interface/ExpandableSearch/ExpandableSearch.js +21 -21
- package/src/interface/ExpandableSearch/index.js +4 -4
- package/src/interface/Flickity/index.js +16 -11
- package/src/interface/MegaMenu/MegaMenu.js +22 -13
- package/src/interface/MegaMenu/index.js +12 -10
- package/src/interface/MobileHeightToggle/MobileHeightToggle.js +5 -4
- package/src/interface/MobileHeightToggle/MobileHeightToggle.test.js +22 -21
- package/src/interface/MobileHeightToggle/index.js +9 -8
- package/src/interface/Navigable/Navigable.js +29 -18
- package/src/interface/Navigable/index.js +1 -1
- package/src/interface/PopOver/PopOver.js +15 -15
- package/src/interface/PopOver/index.js +4 -4
- package/src/interface/ProfileFilter/ProfileFilter.js +40 -35
- package/src/interface/ProfileFilter/__test__/ProfileFilter.test.js +38 -31
- package/src/interface/ProfileFilter/index.js +2 -2
- package/src/interface/SelectNav/SelectNav.js +8 -6
- package/src/interface/SelectNav/index.js +2 -3
- package/src/interface/SideSkinAd/SideSkinAd.js +0 -2
- package/src/interface/SideSkinAd/index.js +10 -10
- package/src/interface/TabsManager/TabsManager.js +11 -6
- package/src/interface/TabsManager/index.js +1 -1
- package/src/interface/Tooltip/Tooltip.js +0 -1
- package/src/interface/VideoShowcase/VideoShowcase.js +77 -49
- package/src/interface/VideoShowcase/index.js +6 -2
- package/src/utils/ajaxIconSprite.js +4 -4
- package/src/utils/dom.js +6 -3
- package/src/utils/removeDesktopXlClasses.js +5 -7
- package/src/utils/webfontConfig.js +26 -40
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import Flickity from '@npm/flickity';
|
|
2
2
|
|
|
3
3
|
export default function initFlickity() {
|
|
4
|
-
const carousels = [ ...
|
|
4
|
+
const carousels = [ ...document.querySelectorAll( '.js-Flickity' ) ];
|
|
5
5
|
|
|
6
6
|
carousels.forEach( ( el ) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const isContained = el.classList.contains( 'js-Flickity--isContained' );
|
|
8
|
+
const isFreeScroll = el.classList.contains(
|
|
9
|
+
'js-Flickity--isFreeScroll'
|
|
10
|
+
);
|
|
11
|
+
const isWrapAround = el.classList.contains(
|
|
12
|
+
'js-Flickity--isWrapAround'
|
|
13
|
+
);
|
|
14
|
+
const hasPageDots = el.classList.contains( 'js-Flickity--pageDots' );
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
const slider = new Flickity( el, {
|
|
13
17
|
cellSelector: '.js-Flickity-cell',
|
|
14
18
|
pageDots: hasPageDots,
|
|
15
19
|
imagesLoaded: true,
|
|
@@ -19,13 +23,14 @@ export default function initFlickity() {
|
|
|
19
23
|
freeScroll: isFreeScroll,
|
|
20
24
|
arrowShape: {
|
|
21
25
|
x0: 10,
|
|
22
|
-
x1: 60,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
x1: 60,
|
|
27
|
+
y1: 50,
|
|
28
|
+
x2: 65,
|
|
29
|
+
y2: 45,
|
|
30
|
+
x3: 20,
|
|
31
|
+
},
|
|
26
32
|
} );
|
|
27
33
|
|
|
28
34
|
return slider;
|
|
29
35
|
} );
|
|
30
|
-
|
|
31
36
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
export default class MegaMenu {
|
|
3
2
|
constructor( el ) {
|
|
4
3
|
this.el = el;
|
|
5
|
-
this.inputs = [ ...
|
|
4
|
+
this.inputs = [ ...this.el.querySelectorAll( 'input' ) ];
|
|
6
5
|
this.container = document.documentElement;
|
|
7
6
|
|
|
8
|
-
this.inputs.forEach( input => {
|
|
7
|
+
this.inputs.forEach( ( input ) => {
|
|
9
8
|
input.addEventListener( 'focus', () => this.handleFocus( input ) );
|
|
10
9
|
} );
|
|
11
10
|
|
|
@@ -24,7 +23,6 @@ export default class MegaMenu {
|
|
|
24
23
|
* @return {void}
|
|
25
24
|
*/
|
|
26
25
|
trapFocus( modal ) {
|
|
27
|
-
|
|
28
26
|
/**
|
|
29
27
|
* .js-MegaMenu class has been added twice in the template, we may remove this check after removing
|
|
30
28
|
* this other class from div.mega-menu__main from all themes.
|
|
@@ -33,11 +31,14 @@ export default class MegaMenu {
|
|
|
33
31
|
return;
|
|
34
32
|
}
|
|
35
33
|
|
|
36
|
-
const focusableElements =
|
|
34
|
+
const focusableElements =
|
|
35
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
37
36
|
|
|
38
|
-
const firstFocusableElement =
|
|
37
|
+
const firstFocusableElement =
|
|
38
|
+
modal.querySelectorAll( focusableElements )[ 0 ];
|
|
39
39
|
const focusableContent = modal.querySelectorAll( focusableElements );
|
|
40
|
-
const lastFocusableElement =
|
|
40
|
+
const lastFocusableElement =
|
|
41
|
+
focusableContent[ focusableContent.length - 1 ];
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Handle keydown event.
|
|
@@ -47,24 +48,32 @@ export default class MegaMenu {
|
|
|
47
48
|
* @return {void}
|
|
48
49
|
*/
|
|
49
50
|
const handleKeyDown = ( event ) => {
|
|
50
|
-
|
|
51
|
+
const isTabPressed = event.key === 'Tab' || event.keyCode === 9;
|
|
51
52
|
|
|
52
53
|
if ( ! isTabPressed ) {
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
if ( event.shiftKey ) {
|
|
57
|
-
|
|
57
|
+
if ( event.shiftKey ) {
|
|
58
|
+
// shift + tab combination
|
|
59
|
+
if (
|
|
60
|
+
document.activeElement === firstFocusableElement &&
|
|
61
|
+
lastFocusableElement
|
|
62
|
+
) {
|
|
58
63
|
lastFocusableElement.focus();
|
|
59
64
|
event.preventDefault();
|
|
60
65
|
}
|
|
61
|
-
} else {
|
|
62
|
-
|
|
66
|
+
} else {
|
|
67
|
+
// tab key
|
|
68
|
+
if (
|
|
69
|
+
document.activeElement === lastFocusableElement &&
|
|
70
|
+
firstFocusableElement
|
|
71
|
+
) {
|
|
63
72
|
firstFocusableElement.focus();
|
|
64
73
|
event.preventDefault();
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
|
-
}
|
|
76
|
+
};
|
|
68
77
|
|
|
69
78
|
document.addEventListener( 'keydown', handleKeyDown );
|
|
70
79
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import MegaMenu from './MegaMenu.js';
|
|
2
2
|
|
|
3
3
|
export default function initMegaMenu() {
|
|
4
|
-
const megaMenus = [ ...
|
|
5
|
-
const triggers = [ ...
|
|
4
|
+
const megaMenus = [ ...document.querySelectorAll( '.js-MegaMenu' ) ];
|
|
5
|
+
const triggers = [ ...document.querySelectorAll( '.js-MegaMenu-Trigger' ) ];
|
|
6
6
|
|
|
7
7
|
let lastFocusedElement;
|
|
8
8
|
|
|
9
|
-
megaMenus.forEach( el => el.pmcMegaMenu = new MegaMenu( el ) );
|
|
9
|
+
megaMenus.forEach( ( el ) => ( el.pmcMegaMenu = new MegaMenu( el ) ) );
|
|
10
10
|
|
|
11
|
-
triggers.forEach( trigger => {
|
|
11
|
+
triggers.forEach( ( trigger ) => {
|
|
12
12
|
trigger.addEventListener( 'click', openOrCloseMegaMenu );
|
|
13
13
|
} );
|
|
14
14
|
|
|
@@ -19,21 +19,23 @@ export default function initMegaMenu() {
|
|
|
19
19
|
} );
|
|
20
20
|
|
|
21
21
|
function openOrCloseMegaMenu() {
|
|
22
|
-
|
|
22
|
+
const isMegaOpen =
|
|
23
|
+
document.documentElement.classList.contains( 'is-mega-open' );
|
|
23
24
|
|
|
24
25
|
// This is a very brittle focus switching solution.
|
|
25
26
|
// @TODO: Move this into the MegaMenu class.
|
|
26
27
|
const menu = document.querySelector( '.js-MegaMenu' );
|
|
27
28
|
const focusableElementsString = 'input, [tabindex="0"]';
|
|
28
|
-
const focusableElements = [
|
|
29
|
+
const focusableElements = [
|
|
30
|
+
...menu.querySelectorAll( focusableElementsString ),
|
|
31
|
+
];
|
|
29
32
|
|
|
30
33
|
if ( ! isMegaOpen ) {
|
|
31
34
|
document.documentElement.classList.add( 'is-mega-open' );
|
|
32
35
|
|
|
33
|
-
if ( focusableElements[0] !== document.activeElement ) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
focusableElements[0].focus();
|
|
36
|
+
if ( focusableElements[ 0 ] !== document.activeElement ) {
|
|
37
|
+
setTimeout( function () {
|
|
38
|
+
focusableElements[ 0 ].focus();
|
|
37
39
|
}, 100 );
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -40,11 +40,13 @@ export default class MobileHeightToggle {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
onClick( e ) {
|
|
43
|
-
|
|
44
43
|
if ( undefined !== this.el.pmcMobileHeightToggle ) {
|
|
45
|
-
|
|
46
44
|
// Bubble event
|
|
47
|
-
if (
|
|
45
|
+
if (
|
|
46
|
+
e.target.classList.contains(
|
|
47
|
+
'lrv-js-MobileHeightToggle-trigger'
|
|
48
|
+
)
|
|
49
|
+
) {
|
|
48
50
|
this.toggle( e );
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -60,5 +62,4 @@ export default class MobileHeightToggle {
|
|
|
60
62
|
this.isExpanded = false;
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
|
-
|
|
64
65
|
}
|
|
@@ -6,34 +6,37 @@ import initMobileHeightToggles from './index';
|
|
|
6
6
|
const TABLET = 768;
|
|
7
7
|
|
|
8
8
|
describe( 'MobileHeightToggle', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
it( 'starts with an initially closed state', () => {
|
|
10
|
+
const dropdown = new MobileHeightToggle(
|
|
11
|
+
document.querySelector( '.test' )
|
|
12
|
+
);
|
|
12
13
|
assert.equal( dropdown.isExpanded, false );
|
|
13
|
-
});
|
|
14
|
+
} );
|
|
14
15
|
|
|
15
16
|
it( 'adds the class is expanded when trigger is clicked', () => {
|
|
16
|
-
|
|
17
|
-
document.querySelector('.test').innerHTML = `
|
|
17
|
+
document.querySelector( '.test' ).innerHTML = `
|
|
18
18
|
<div class="lrv-js-MobileHeightToggle">
|
|
19
19
|
<div class="lrv-js-MobileHeightToggle-trigger"></div>
|
|
20
20
|
<div class="lrv-js-MobileHeightToggle-target"></div>
|
|
21
21
|
</div>
|
|
22
22
|
`;
|
|
23
23
|
|
|
24
|
-
const dropdown = new MobileHeightToggle(
|
|
24
|
+
const dropdown = new MobileHeightToggle(
|
|
25
|
+
document.querySelector( '.lrv-js-MobileHeightToggle' )
|
|
26
|
+
);
|
|
25
27
|
|
|
26
|
-
dropdown.toggle({
|
|
27
|
-
preventDefault: () => {},
|
|
28
|
-
target: document.querySelector(
|
|
29
|
-
|
|
28
|
+
dropdown.toggle( {
|
|
29
|
+
preventDefault: () => {},
|
|
30
|
+
target: document.querySelector(
|
|
31
|
+
'.lrv-js-MobileHeightToggle-trigger'
|
|
32
|
+
),
|
|
33
|
+
} );
|
|
30
34
|
|
|
31
35
|
assert.equal( dropdown.el.classList.contains( 'is-expanded' ), true );
|
|
32
|
-
});
|
|
36
|
+
} );
|
|
33
37
|
|
|
34
38
|
it( 'does not initialize MobileHeightToggles on tablet', () => {
|
|
35
|
-
|
|
36
|
-
document.querySelector('.test').innerHTML = `
|
|
39
|
+
document.querySelector( '.test' ).innerHTML = `
|
|
37
40
|
<div class="lrv-js-MobileHeightToggle">
|
|
38
41
|
<div class="lrv-js-MobileHeightToggle-trigger"></div>
|
|
39
42
|
<div class="lrv-js-MobileHeightToggle-target"></div>
|
|
@@ -43,13 +46,12 @@ describe( 'MobileHeightToggle', () => {
|
|
|
43
46
|
initMobileHeightToggles( TABLET + 1 );
|
|
44
47
|
|
|
45
48
|
const el = document.querySelector( '.lrv-js-MobileHeightToggle' );
|
|
46
|
-
|
|
49
|
+
|
|
47
50
|
assert.equal( el.pmcMobileHeightToggle, undefined );
|
|
48
|
-
});
|
|
51
|
+
} );
|
|
49
52
|
|
|
50
53
|
it( 'does initialize MobileHeightToggles on below tablet', () => {
|
|
51
|
-
|
|
52
|
-
document.querySelector('.test').innerHTML = `
|
|
54
|
+
document.querySelector( '.test' ).innerHTML = `
|
|
53
55
|
<div class="lrv-js-MobileHeightToggle">
|
|
54
56
|
<div class="lrv-js-MobileHeightToggle-trigger"></div>
|
|
55
57
|
<div class="lrv-js-MobileHeightToggle-target"></div>
|
|
@@ -61,6 +63,5 @@ describe( 'MobileHeightToggle', () => {
|
|
|
61
63
|
const el = document.querySelector( '.lrv-js-MobileHeightToggle' );
|
|
62
64
|
|
|
63
65
|
assert.notEqual( el.pmcMobileHeightToggle, undefined );
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
});
|
|
66
|
+
} );
|
|
67
|
+
} );
|
|
@@ -2,17 +2,18 @@ import MobileHeightToggle from './MobileHeightToggle';
|
|
|
2
2
|
|
|
3
3
|
// Initialize all Dropdowns.
|
|
4
4
|
|
|
5
|
-
export default function( width ) {
|
|
6
|
-
const dropdowns = [
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export default function ( width ) {
|
|
6
|
+
const dropdowns = [
|
|
7
|
+
...document.querySelectorAll( '.lrv-js-MobileHeightToggle' ),
|
|
8
|
+
];
|
|
9
9
|
|
|
10
|
+
dropdowns.forEach( ( el ) => {
|
|
10
11
|
if ( 768 > width && undefined === el.pmcMobileHeightToggle ) {
|
|
11
|
-
new MobileHeightToggle( el );
|
|
12
|
+
new MobileHeightToggle( el );
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
+
|
|
14
15
|
if ( 768 <= width && undefined !== el.pmcMobileHeightToggle ) {
|
|
15
16
|
el.pmcMobileHeightToggle.destroy();
|
|
16
17
|
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
18
|
+
} );
|
|
19
|
+
}
|
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Navigable
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Allows o-nav object to be accessible/navigable by keyboard tab.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* The HTML attributes required for the navigation to work:
|
|
7
7
|
* - class lrv-js-Navigable to initiate the module, on a `nav` element
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
export default class Navigable {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
|
|
11
|
+
constructor( el ) {
|
|
12
|
+
this.el = el;
|
|
13
|
+
this.oNavList = el.querySelector( '.o-nav__list' );
|
|
14
|
+
this.oNavListItems = [
|
|
15
|
+
...el.querySelectorAll( '.o-nav__list-item a' ),
|
|
16
|
+
];
|
|
16
17
|
|
|
17
18
|
this.el.addEventListener( 'focus', this.onFocus.bind( this ) );
|
|
18
19
|
this.el.addEventListener( 'focusout', this.onFocusOut.bind( this ) );
|
|
19
20
|
this.el.addEventListener( 'keyup', this.onKeyup.bind( this ) );
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
if ( this.oNavListItems.length ) {
|
|
22
23
|
this.oNavListItems.forEach( ( oNavListItem ) => {
|
|
23
|
-
oNavListItem.addEventListener(
|
|
24
|
-
|
|
24
|
+
oNavListItem.addEventListener(
|
|
25
|
+
'focus',
|
|
26
|
+
this.onFocusListItem.bind( this )
|
|
27
|
+
);
|
|
28
|
+
oNavListItem.addEventListener(
|
|
29
|
+
'focusout',
|
|
30
|
+
this.onFocusOutListItem.bind( this )
|
|
31
|
+
);
|
|
25
32
|
} );
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
onFocus() {
|
|
30
37
|
this.oNavList.style.visibility = 'visible';
|
|
31
|
-
this.oNavList.style.opacity
|
|
38
|
+
this.oNavList.style.opacity = '1';
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
onFocusOut( event ) {
|
|
@@ -36,22 +43,26 @@ export default class Navigable {
|
|
|
36
43
|
return;
|
|
37
44
|
}
|
|
38
45
|
this.oNavList.style.visibility = 'hidden';
|
|
39
|
-
this.oNavList.style.opacity
|
|
46
|
+
this.oNavList.style.opacity = '0';
|
|
40
47
|
}
|
|
41
|
-
|
|
48
|
+
|
|
42
49
|
onFocusListItem( event ) {
|
|
43
|
-
event.currentTarget.classList.add(
|
|
50
|
+
event.currentTarget.classList.add(
|
|
51
|
+
'lrv-u-background-color-brand-primary'
|
|
52
|
+
);
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
onFocusOutListItem( event ) {
|
|
47
|
-
event.currentTarget.classList.remove(
|
|
56
|
+
event.currentTarget.classList.remove(
|
|
57
|
+
'lrv-u-background-color-brand-primary'
|
|
58
|
+
);
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
onKeyup( event ) {
|
|
51
62
|
// Hide nav if Escape key is pressed.
|
|
52
|
-
if (
|
|
63
|
+
if ( 'Escape' === event.key ) {
|
|
53
64
|
this.oNavList.style.visibility = 'hidden';
|
|
54
|
-
this.oNavList.style.opacity
|
|
55
|
-
}
|
|
65
|
+
this.oNavList.style.opacity = '0';
|
|
66
|
+
}
|
|
56
67
|
}
|
|
57
68
|
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
export default class PopOver {
|
|
2
|
-
constructor(el) {
|
|
2
|
+
constructor( el ) {
|
|
3
3
|
this.el = el;
|
|
4
4
|
this.isOpen = false;
|
|
5
|
-
this.target = this.el.querySelector('.js-PopOver-target');
|
|
5
|
+
this.target = this.el.querySelector( '.js-PopOver-target' );
|
|
6
6
|
|
|
7
7
|
// Close PopOver on ESC.
|
|
8
|
-
document.addEventListener('keydown', () => {
|
|
8
|
+
document.addEventListener( 'keydown', () => {
|
|
9
9
|
this.closePopOver();
|
|
10
|
-
});
|
|
10
|
+
} );
|
|
11
11
|
|
|
12
12
|
// Open PopOver on mouseover.
|
|
13
|
-
this.el.addEventListener('mouseover', () => {
|
|
13
|
+
this.el.addEventListener( 'mouseover', () => {
|
|
14
14
|
this.openPopOver();
|
|
15
|
-
});
|
|
15
|
+
} );
|
|
16
16
|
|
|
17
17
|
// Open PopOver on mouseover.
|
|
18
|
-
this.el.addEventListener('mouseout', () => {
|
|
18
|
+
this.el.addEventListener( 'mouseout', () => {
|
|
19
19
|
this.closePopOver();
|
|
20
|
-
});
|
|
20
|
+
} );
|
|
21
21
|
|
|
22
22
|
// Open PopOver on focus.
|
|
23
|
-
this.el.addEventListener('focus', () => {
|
|
23
|
+
this.el.addEventListener( 'focus', () => {
|
|
24
24
|
this.openPopOver();
|
|
25
|
-
});
|
|
25
|
+
} );
|
|
26
26
|
|
|
27
27
|
// Open PopOver on blur.
|
|
28
|
-
this.el.addEventListener('blur', () => {
|
|
28
|
+
this.el.addEventListener( 'blur', () => {
|
|
29
29
|
this.closePopOver();
|
|
30
|
-
});
|
|
30
|
+
} );
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
openPopOver() {
|
|
34
34
|
this.isOpen = true;
|
|
35
|
-
this.target.classList.add('js-PopOver-is-opened');
|
|
35
|
+
this.target.classList.add( 'js-PopOver-is-opened' );
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
closePopOver() {
|
|
39
|
-
if (this.isOpen) {
|
|
40
|
-
this.target.classList.remove('js-PopOver-is-opened');
|
|
39
|
+
if ( this.isOpen ) {
|
|
40
|
+
this.target.classList.remove( 'js-PopOver-is-opened' );
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import PopOver from './PopOver.js';
|
|
2
2
|
|
|
3
3
|
export default function initPopOver() {
|
|
4
|
-
const searches = [...document.querySelectorAll('.js-PopOver')];
|
|
4
|
+
const searches = [ ...document.querySelectorAll( '.js-PopOver' ) ];
|
|
5
5
|
|
|
6
|
-
searches.forEach((el) => {
|
|
7
|
-
return new PopOver(el);
|
|
8
|
-
});
|
|
6
|
+
searches.forEach( ( el ) => {
|
|
7
|
+
return new PopOver( el );
|
|
8
|
+
} );
|
|
9
9
|
}
|
|
@@ -24,11 +24,17 @@ export default class ProfileFilter {
|
|
|
24
24
|
this.el.pmcProfileFilter = this;
|
|
25
25
|
|
|
26
26
|
// UI
|
|
27
|
-
this.resultContainer = this.el.querySelector(
|
|
27
|
+
this.resultContainer = this.el.querySelector(
|
|
28
|
+
'.js-ProfileFilter-results'
|
|
29
|
+
);
|
|
28
30
|
this.form = this.el.querySelector( '.js-ProfileFilter-form' );
|
|
29
|
-
this.loadMoreButton = this.el.querySelector(
|
|
31
|
+
this.loadMoreButton = this.el.querySelector(
|
|
32
|
+
'.js-ProfileFilter-loadMore'
|
|
33
|
+
);
|
|
30
34
|
|
|
31
|
-
this.submitButton = this.form.querySelector(
|
|
35
|
+
this.submitButton = this.form.querySelector(
|
|
36
|
+
'.js-ProfileFilter-submit'
|
|
37
|
+
);
|
|
32
38
|
|
|
33
39
|
// Event handlers
|
|
34
40
|
this.onSubmit = this.onSubmit.bind( this );
|
|
@@ -41,7 +47,9 @@ export default class ProfileFilter {
|
|
|
41
47
|
this.actionUrl = this.form.getAttribute( 'action' );
|
|
42
48
|
|
|
43
49
|
// The endpoint where we will fetch the posts
|
|
44
|
-
this.restUrlBase =
|
|
50
|
+
this.restUrlBase =
|
|
51
|
+
window.location.origin +
|
|
52
|
+
'/wp-json/pmc_core/v1/pmc_core_modules/pmc-profiles';
|
|
45
53
|
|
|
46
54
|
// Object to hold the data from which we will create the request URL.
|
|
47
55
|
// This should be created fresh each time it is used with this.setQueryObject
|
|
@@ -53,15 +61,15 @@ export default class ProfileFilter {
|
|
|
53
61
|
if ( undefined !== window.wp ) {
|
|
54
62
|
this.template = wp.template( 'profile-card' );
|
|
55
63
|
}
|
|
56
|
-
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
getCheckedBoxes() {
|
|
60
|
-
return [
|
|
67
|
+
return [
|
|
68
|
+
...this.form.querySelectorAll( 'input[type="checkbox"]:checked' ),
|
|
69
|
+
];
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
setQueryObject( url = false ) {
|
|
64
|
-
|
|
65
73
|
const els = this.getCheckedBoxes();
|
|
66
74
|
|
|
67
75
|
// Get query from checkboxes, if they are checked,
|
|
@@ -76,12 +84,11 @@ export default class ProfileFilter {
|
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
setQueryObjectFromCheckboxes( els ) {
|
|
79
|
-
|
|
87
|
+
const obj = {};
|
|
80
88
|
|
|
81
89
|
els.map( ( el ) => {
|
|
82
|
-
|
|
83
90
|
// If the key doesn't exist, create it
|
|
84
|
-
|
|
91
|
+
const key = el.getAttribute( 'name' );
|
|
85
92
|
|
|
86
93
|
if ( ! ( key in obj ) ) {
|
|
87
94
|
obj[ key ] = [];
|
|
@@ -96,19 +103,19 @@ export default class ProfileFilter {
|
|
|
96
103
|
|
|
97
104
|
// filterQueryString should be window.location.search, e.g. ?filter_top200location=scottdale&filter_sourceofwealth=money
|
|
98
105
|
setQueryObjectFromUrl( filterQueryString ) {
|
|
99
|
-
|
|
106
|
+
const queryObject = {};
|
|
100
107
|
|
|
101
|
-
|
|
108
|
+
const params = new URLSearchParams( filterQueryString );
|
|
102
109
|
|
|
103
110
|
params.forEach( ( value, key ) => {
|
|
104
|
-
|
|
111
|
+
const values = value.split( ',' );
|
|
105
112
|
|
|
106
113
|
if ( ! ( key in queryObject ) ) {
|
|
107
114
|
queryObject[ key ] = [];
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
queryObject[ key ] = [];
|
|
111
|
-
queryObject[ key ].push( ...
|
|
118
|
+
queryObject[ key ].push( ...values );
|
|
112
119
|
} );
|
|
113
120
|
|
|
114
121
|
this.queryObject = Object.assign( {}, queryObject );
|
|
@@ -119,9 +126,12 @@ export default class ProfileFilter {
|
|
|
119
126
|
}
|
|
120
127
|
|
|
121
128
|
getRestEndpointUrl() {
|
|
122
|
-
|
|
123
129
|
// REST params do not have filter_ prefix, so replace with empty string
|
|
124
|
-
return
|
|
130
|
+
return (
|
|
131
|
+
this.restUrlBase +
|
|
132
|
+
'?' +
|
|
133
|
+
this.createQueryStringFromObject().replace( /filter_/g, '' )
|
|
134
|
+
);
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
updateActionAttr() {
|
|
@@ -140,7 +150,6 @@ export default class ProfileFilter {
|
|
|
140
150
|
// If fetch is supported, fetch posts from REST API endpoint, otherwise
|
|
141
151
|
// we use default form behavior and window will reload to the action URL
|
|
142
152
|
if ( window.fetch ) {
|
|
143
|
-
|
|
144
153
|
e.preventDefault();
|
|
145
154
|
|
|
146
155
|
// TODO: add better error handling - output result of e in updateResults
|
|
@@ -161,11 +170,13 @@ export default class ProfileFilter {
|
|
|
161
170
|
}
|
|
162
171
|
|
|
163
172
|
fetchData() {
|
|
164
|
-
|
|
173
|
+
const url = this.getRestEndpointUrl();
|
|
165
174
|
|
|
166
|
-
const response = fetch( url )
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
const response = fetch( url )
|
|
176
|
+
.then( ( result ) => {
|
|
177
|
+
return result.json();
|
|
178
|
+
} )
|
|
179
|
+
.catch( ( e ) => e );
|
|
169
180
|
|
|
170
181
|
return response;
|
|
171
182
|
}
|
|
@@ -176,7 +187,7 @@ export default class ProfileFilter {
|
|
|
176
187
|
|
|
177
188
|
updateWindowUrl() {
|
|
178
189
|
const url = '?' + this.createQueryStringFromObject();
|
|
179
|
-
|
|
190
|
+
const obj = this.queryObject;
|
|
180
191
|
|
|
181
192
|
if ( window.history.pushState ) {
|
|
182
193
|
window.history.pushState( obj, '', url );
|
|
@@ -184,7 +195,6 @@ export default class ProfileFilter {
|
|
|
184
195
|
}
|
|
185
196
|
|
|
186
197
|
updateResults( posts, shouldClearResults = true ) {
|
|
187
|
-
|
|
188
198
|
this.maybeHideLoadMore( this.maxPages );
|
|
189
199
|
|
|
190
200
|
// TODO: better as maybeClearResults func
|
|
@@ -194,16 +204,15 @@ export default class ProfileFilter {
|
|
|
194
204
|
|
|
195
205
|
this.updateWindowUrl();
|
|
196
206
|
|
|
197
|
-
if ( undefined === posts[0].name ) {
|
|
198
|
-
|
|
207
|
+
if ( undefined === posts[ 0 ].name ) {
|
|
199
208
|
// Update with "No posts found" text and exit
|
|
200
|
-
this.resultContainer.innerHTML = posts[0];
|
|
209
|
+
this.resultContainer.innerHTML = posts[ 0 ];
|
|
201
210
|
return;
|
|
202
211
|
}
|
|
203
212
|
|
|
204
|
-
posts.forEach( post => {
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
posts.forEach( ( post ) => {
|
|
214
|
+
const tmpl = this.template( post );
|
|
215
|
+
const li = document.createElement( 'li' );
|
|
207
216
|
li.innerHTML = tmpl;
|
|
208
217
|
|
|
209
218
|
// TODO: this should be removed upon finding solution for escaping {{data.url}} as an attribute
|
|
@@ -217,19 +226,15 @@ export default class ProfileFilter {
|
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
maybeHideLoadMore() {
|
|
220
|
-
|
|
221
229
|
const isHidden = this.loadMoreButton.classList.contains( 'a-hidden' );
|
|
222
230
|
|
|
223
231
|
if ( this.maxPages > this.page ) {
|
|
224
232
|
if ( isHidden ) {
|
|
225
233
|
this.loadMoreButton.classList.remove( 'a-hidden' );
|
|
226
234
|
}
|
|
227
|
-
} else {
|
|
228
|
-
|
|
229
|
-
this.loadMoreButton.classList.add( 'a-hidden' );
|
|
230
|
-
}
|
|
235
|
+
} else if ( ! isHidden ) {
|
|
236
|
+
this.loadMoreButton.classList.add( 'a-hidden' );
|
|
231
237
|
}
|
|
232
|
-
|
|
233
238
|
}
|
|
234
239
|
|
|
235
240
|
increasePage() {
|