Skip to content

Commit 648f31b

Browse files
gumacahinbfintal
andauthored
fix (accordion block): accordion wont open in old browsers (#2155)
* Add polyfill for summary/details elements. * Add polyfill for summary and details elements. * Replace wp_check_browser_version with $_SERVER["HTTP_USER_AGENT"]. * Update src/block/accordion/index.php Remember coding standard. Co-authored-by: Benjamin Intal <[email protected]> * Update src/block/accordion/index.php Remember coding standard, fix phpcbf. Co-authored-by: Benjamin Intal <[email protected]> * Update src/block/accordion/index.php Remember coding standard. Co-authored-by: Benjamin Intal <[email protected]> * Update polyfill script. * line breaks become br tags * added user agent matching for sarafi 13.1.3 and Android 7 * restructure to prevent preg_match Co-authored-by: Benjamin Intal <[email protected]>
1 parent 278337d commit 648f31b

File tree

4 files changed

+211
-0
lines changed

4 files changed

+211
-0
lines changed

.config/webpack.config.dev.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ module.exports = [ {
129129
entry: {
130130
'frontend_blocks': path.resolve( __dirname, '../src/block-frontend.js' ),
131131
'frontend_block_accordion': path.resolve( __dirname, '../src/block/accordion/frontend-accordion.js' ),
132+
'frontend_block_accordion_polyfill': path.resolve( __dirname, '../src/block/accordion/frontend-accordion-polyfill.js' ),
132133
'frontend_block_count_up': path.resolve( __dirname, '../src/block/count-up/frontend-count-up.js' ),
133134
'frontend_block_expand': path.resolve( __dirname, '../src/block/expand/frontend-expand.js' ),
134135
'frontend_block_notification': path.resolve( __dirname, '../src/block/notification/frontend-notification.js' ),

.config/webpack.config.prod.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ module.exports = [ {
118118
entry: {
119119
'frontend_blocks': path.resolve( __dirname, '../src/block-frontend.js' ),
120120
'frontend_block_accordion': path.resolve( __dirname, '../src/block/accordion/frontend-accordion.js' ),
121+
'frontend_block_accordion_polyfill': path.resolve( __dirname, '../src/block/accordion/frontend-accordion-polyfill.js' ),
121122
'frontend_block_count_up': path.resolve( __dirname, '../src/block/count-up/frontend-count-up.js' ),
122123
'frontend_block_expand': path.resolve( __dirname, '../src/block/expand/frontend-expand.js' ),
123124
'frontend_block_notification': path.resolve( __dirname, '../src/block/notification/frontend-notification.js' ),
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* @see https://gist.github.com/remy/370590
3+
*/
4+
( function( window, document ) {
5+
if ( 'open' in document.createElement( 'details' ) ) {
6+
return
7+
}
8+
9+
// made global by myself to be reused elsewhere
10+
const addEvent = ( function() {
11+
if ( document.addEventListener ) {
12+
return function( el, type, fn ) {
13+
if ( ( el && el.nodeName ) || el === window ) {
14+
el.addEventListener( type, fn, false )
15+
} else if ( el && el.length ) {
16+
for ( let i = 0; i < el.length; i++ ) {
17+
addEvent( el[ i ], type, fn )
18+
}
19+
}
20+
}
21+
}
22+
return function( el, type, fn ) {
23+
if ( ( el && el.nodeName ) || el === window ) {
24+
el.attachEvent( 'on' + type, function() {
25+
return fn.call( el, window.event )
26+
} )
27+
} else if ( el && el.length ) {
28+
for ( let i = 0; i < el.length; i++ ) {
29+
addEvent( el[ i ], type, fn )
30+
}
31+
}
32+
}
33+
}() )
34+
35+
function firstNode( source ) {
36+
if ( source.firstChild.nodeName !== '#text' ) {
37+
return source.firstChild
38+
}
39+
source = source.firstChild
40+
do {
41+
source = source.nextSibling
42+
} while ( source && source.nodeName === '#text' )
43+
44+
return source || null
45+
}
46+
47+
function isSummary( el ) {
48+
const nn = el.nodeName.toUpperCase()
49+
if ( nn === 'DETAILS' ) {
50+
return false
51+
} else if ( nn === 'SUMMARY' ) {
52+
return true
53+
}
54+
return isSummary( el.parentNode )
55+
}
56+
57+
function toggleDetails( event ) {
58+
// more sigh - need to check the clicked object
59+
let keypress = event.type === 'keypress'
60+
const target = event.target || event.srcElement
61+
if ( keypress || isSummary( target ) ) {
62+
if ( keypress ) {
63+
// if it's a keypress, make sure it was enter or space
64+
keypress = event.which || event.keyCode
65+
if ( keypress === 32 || keypress === 13 ) {
66+
// all's good, go ahead and toggle
67+
} else {
68+
return
69+
}
70+
}
71+
72+
const open = this.getAttribute( 'open' )
73+
if ( open === null ) {
74+
this.setAttribute( 'open', 'open' )
75+
} else {
76+
this.removeAttribute( 'open' )
77+
}
78+
79+
// this.className = open ? 'open' : ''; // Lame
80+
// trigger reflow (required in IE - sometimes in Safari too)
81+
setTimeout( function() {
82+
document.body.className = document.body.className
83+
}, 13 )
84+
85+
if ( keypress ) {
86+
event.preventDefault && event.preventDefault()
87+
return false
88+
}
89+
}
90+
}
91+
92+
function addStyle() {
93+
const style = document.createElement( 'style' )
94+
const head = document.getElementsByTagName( 'head' )[ 0 ]
95+
style.innerText === undefined ? 'textContent' : 'innerText'
96+
const key = style.innerText === undefined ? 'textContent' : 'innerText'
97+
98+
const rules = [
99+
'details{display: block;}',
100+
'details > *{display: none;}',
101+
'details.open > *{display: block;}',
102+
'details[open] > *{display: block;}',
103+
'details > summary:first-child{display: block;cursor: pointer;}',
104+
'details[open]{display: block;}',
105+
]
106+
i = rules.length
107+
108+
style[ key ] = rules.join( '' )
109+
head.insertBefore( style, head.firstChild )
110+
}
111+
112+
const details = document.querySelectorAll( '.stk-block-accordion' )
113+
const label = document.createElement( 'div' )
114+
label.className = 'stk-block-accordion stk-block-accordion__heading'
115+
let first = null,
116+
i = details.length,
117+
j, wrapper
118+
119+
label.appendChild( document.createTextNode( 'Details' ) )
120+
121+
while ( i-- ) {
122+
first = firstNode( details[ i ] )
123+
124+
if ( first !== null && first.nodeName.toUpperCase() === 'SUMMARY' ) {
125+
// we've found that there's a details label already
126+
} else {
127+
// first = label.cloneNode(true); // cloned nodes weren't picking up styles in IE - random
128+
first = document.createElement( 'summary' )
129+
first.appendChild( document.createTextNode( 'Details' ) )
130+
if ( details[ i ].firstChild ) {
131+
details[ i ].insertBefore( first, details[ i ].firstChild )
132+
} else {
133+
details[ i ].appendChild( first )
134+
}
135+
}
136+
137+
// this feels *really* nasty, but we can't target details :text in css :(
138+
j = details[ i ].childNodes.length
139+
while ( j-- ) {
140+
if (
141+
details[ i ].childNodes[ j ].nodeName === '#text' &&
142+
( details[ i ].childNodes[ j ].nodeValue || '' ).replace(
143+
/\s/g,
144+
''
145+
).length
146+
) {
147+
wrapper = document.createElement( 'text' )
148+
wrapper.appendChild( details[ i ].childNodes[ j ] )
149+
details[ i ].insertBefore( wrapper, details[ i ].childNodes[ j ] )
150+
}
151+
}
152+
153+
first.legend = true
154+
first.tabIndex = 0
155+
}
156+
157+
// trigger details in case this being used on it's own
158+
document.createElement( 'details' )
159+
addEvent( details, 'click', toggleDetails )
160+
addEvent( details, 'keypress', toggleDetails )
161+
addStyle()
162+
}( window, document ) )

src/block/accordion/index.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,50 @@ function stackable_load_accordion_frontend_script() {
1818
}
1919
add_action( 'stackable/accordion/enqueue_scripts', 'stackable_load_accordion_frontend_script' );
2020
}
21+
22+
if ( ! function_exists( 'stackable_load_accordion_frontend_polyfill_script' ) ) {
23+
/**
24+
* Adds polyfill for summary/details element that are * used in accordion blocks.
25+
*
26+
* TODO: confirm that this works on older browsers
27+
*/
28+
function stackable_load_accordion_frontend_polyfill_script() {
29+
30+
$user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
31+
32+
if ( ! $user_agent ) {
33+
return;
34+
}
35+
36+
$load_polyfill = false;
37+
38+
if (
39+
// Safari 13.1.3
40+
( stripos( $user_agent, 'Version/13.' ) !== false && stripos( $user_agent, 'Safari/' ) !== false ) ||
41+
// Adnroid 7.0 Samsung Galaxy J5
42+
( stripos( $user_agent, 'Android 7.' ) !== false && stripos( $user_agent, 'Chrome/' ) !== false ) ||
43+
// IE 11
44+
stripos( $user_agent, 'Trident/7.0; rv:11.0' ) !== false
45+
) {
46+
$load_polyfill = true;
47+
} else if ( stripos( $user_agent, ' Edge/' ) !== false || stripos( $user_agent, ' Edg/' ) !== false ) {
48+
$matches = array();
49+
if ( preg_match( '/(Edge?)\/(\d+)/', $user_agent, $matches ) ) {
50+
$version = intval( $matches[2] );
51+
if ( $version < 79 ) {
52+
$load_polyfill = true;
53+
}
54+
}
55+
}
56+
57+
if ( $load_polyfill ) {
58+
wp_enqueue_script(
59+
'stk-frontend-accordion-polyfill',
60+
plugins_url( 'dist/frontend_block_accordion_polyfill.js', STACKABLE_FILE ),
61+
array(),
62+
STACKABLE_VERSION
63+
);
64+
}
65+
}
66+
add_action( 'wp_footer', 'stackable_load_accordion_frontend_polyfill_script' );
67+
}

0 commit comments

Comments
 (0)