Skip to content

Commit ed002b1

Browse files
authored
Merge pull request #383 from linchpin/cursor/remove-frontend-jquery-dependency-e297
Cursor/remove frontend jquery dependency e297
2 parents a96cd87 + 590d971 commit ed002b1

File tree

6 files changed

+239
-99
lines changed

6 files changed

+239
-99
lines changed

assets/js/courier-notices.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@ import core from "./frontend/core";
22
import dismiss from "./frontend/dismiss";
33
import modal from "./frontend/modal";
44

5-
const $ = jQuery;
6-
7-
jQuery( function() {
5+
// Initialize modules when DOM is ready
6+
if (document.readyState === "loading") {
7+
document.addEventListener("DOMContentLoaded", function() {
8+
core();
9+
dismiss();
10+
modal();
11+
});
12+
} else {
13+
// DOM already loaded
814
core();
915
dismiss();
1016
modal();
11-
} );
17+
}

assets/js/frontend/core.js

Lines changed: 113 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { getItem } from './cookie';
22

3-
let $ = jQuery;
4-
53
export default function core() {
64

75
/**
@@ -21,10 +19,10 @@ export default function core() {
2119
*/
2220
function init() {
2321

24-
let $notice_containers = $( '.courier-notices[data-courier-ajax="true"]' );
22+
let noticeContainers = document.querySelectorAll( '.courier-notices[data-courier-ajax="true"]' );
2523

2624
// If no notice containers expecting ajax, die early.
27-
if ( $notice_containers.length === 0 ) {
25+
if ( noticeContainers.length === 0 ) {
2826
return;
2927
}
3028

@@ -35,12 +33,14 @@ export default function core() {
3533
}
3634

3735
// Mark all containers as not loaded
38-
$notice_containers.attr( 'data-loaded', false );
36+
noticeContainers.forEach( function( container ) {
37+
container.setAttribute( 'data-loaded', 'false' );
38+
});
3939

4040
// Collect all placements that have containers
4141
let placements = [];
42-
$notice_containers.each( function() {
43-
let placement = $( this ).data( 'courier-placement' );
42+
noticeContainers.forEach( function( container ) {
43+
let placement = container.getAttribute( 'data-courier-placement' );
4444
if ( placement && placements.indexOf( placement ) === -1 ) {
4545
placements.push( placement );
4646
}
@@ -65,8 +65,8 @@ export default function core() {
6565
}, { threshold: 1 });
6666

6767
// Observe all notice containers
68-
$notice_containers.each( function() {
69-
observer.observe( this );
68+
noticeContainers.forEach( function( container ) {
69+
observer.observe( container );
7070
});
7171
}
7272

@@ -78,8 +78,8 @@ export default function core() {
7878
*/
7979
function loadAllNotices( placements ) {
8080
// Check if we've already loaded notices
81-
let $loadedContainers = $( '.courier-notices[data-loaded="true"]' );
82-
if ( $loadedContainers.length > 0 ) {
81+
let loadedContainers = document.querySelectorAll( '.courier-notices[data-loaded="true"]' );
82+
if ( loadedContainers.length > 0 ) {
8383
return;
8484
}
8585

@@ -98,24 +98,47 @@ export default function core() {
9898
dismissed_notice_ids = JSON.parse( dismissed_notice_ids );
9999
dismissed_notice_ids = dismissed_notice_ids || [];
100100

101-
// Make single AJAX call to fetch all notices
102-
$.ajax({
103-
method: 'GET',
104-
beforeSend: function (xhr) {
105-
// only send nonce if the user is logged in.
106-
if ( courier_notices_data.user_id !== '0' ) {
107-
xhr.setRequestHeader( 'X-WP-Nonce', courier_notices_data.wp_rest_nonce );
101+
// Build query string from settings
102+
let queryParams = new URLSearchParams();
103+
for ( let key in settings ) {
104+
if ( key === 'post_info' ) {
105+
for ( let subKey in settings[key] ) {
106+
queryParams.append( `post_info[${subKey}]`, settings[key][subKey] );
108107
}
109-
},
110-
url: courier_notices_data.notices_all_endpoint,
111-
data: settings,
112-
}).done( function( response ) {
108+
} else if ( key === 'placements' ) {
109+
settings[key].forEach( function( placement ) {
110+
queryParams.append( 'placements[]', placement );
111+
});
112+
} else {
113+
queryParams.append( key, settings[key] );
114+
}
115+
}
116+
117+
// Make fetch call to get all notices
118+
let headers = {};
119+
// only send nonce if the user is logged in.
120+
if ( courier_notices_data.user_id !== '0' ) {
121+
headers['X-WP-Nonce'] = courier_notices_data.wp_rest_nonce;
122+
}
123+
124+
fetch( courier_notices_data.notices_all_endpoint + '?' + queryParams.toString(), {
125+
method: 'GET',
126+
headers: headers
127+
})
128+
.then( function( response ) {
129+
if ( !response.ok ) {
130+
throw new Error( 'Network response was not ok' );
131+
}
132+
return response.json();
133+
})
134+
.then( function( response ) {
113135
// Distribute notices to their appropriate containers
114136
if ( response && typeof response === 'object' ) {
115137
distributeNotices( response, dismissed_notice_ids );
116138
}
117-
}).fail( function( jqXHR, textStatus, errorThrown ) {
118-
console.error( 'Courier Notices: Failed to load notices', textStatus, errorThrown );
139+
})
140+
.catch( function( error ) {
141+
console.error( 'Courier Notices: Failed to load notices', error );
119142
});
120143
}
121144

@@ -130,10 +153,10 @@ export default function core() {
130153
// Process each placement
131154
Object.keys( response ).forEach( function( placement ) {
132155
let notices = response[ placement ];
133-
let $container = $( '.courier-notices[data-courier-placement="' + placement + '"]' );
156+
let container = document.querySelector( '.courier-notices[data-courier-placement="' + placement + '"]' );
134157

135158
// Skip if no container for this placement
136-
if ( $container.length === 0 ) {
159+
if ( !container ) {
137160
return;
138161
}
139162

@@ -148,11 +171,17 @@ export default function core() {
148171
return;
149172
}
150173

151-
let $notice = $( notices[ notice_id ] ).hide();
152-
$container.append( $notice );
174+
// Create temporary div to parse HTML
175+
let tempDiv = document.createElement( 'div' );
176+
tempDiv.innerHTML = notices[ notice_id ];
177+
let noticeElement = tempDiv.firstElementChild;
178+
179+
// Hide initially
180+
noticeElement.style.display = 'none';
181+
container.appendChild( noticeElement );
153182

154-
// Animate the notice in
155-
$notice.slideDown( 'fast', 'swing', function() {
183+
// Animate the notice in using CSS transition
184+
slideDown( noticeElement, function() {
156185
const event = new CustomEvent( 'courierNoticeDisplayed', {
157186
detail: {
158187
notice_id: notice_id,
@@ -165,7 +194,7 @@ export default function core() {
165194
}
166195

167196
// Mark container as loaded
168-
$container.attr( 'data-loaded', 'true' );
197+
container.setAttribute( 'data-loaded', 'true' );
169198
});
170199
}
171200

@@ -204,21 +233,67 @@ export default function core() {
204233
* @param index
205234
*/
206235
function displayModal ( index ) {
207-
let $notice = $( window.courier_notices_modal_notices[ index ] );
208-
$notice.hide();
236+
if ( !window.courier_notices_modal_notices || !window.courier_notices_modal_notices[ index ] ) {
237+
return;
238+
}
209239

210-
if ( $notice.length < 1 ) {
240+
// Create temporary div to parse HTML
241+
let tempDiv = document.createElement( 'div' );
242+
tempDiv.innerHTML = window.courier_notices_modal_notices[ index ];
243+
let noticeElement = tempDiv.firstElementChild;
244+
245+
if ( !noticeElement ) {
211246
return;
212247
}
213248

214-
$( '.courier-notices[data-courier-placement="popup-modal"] .courier-modal-overlay' )
215-
.append( $notice );
249+
noticeElement.style.display = 'none';
216250

217-
$('.courier-modal-overlay').removeClass('hide').show();
218-
$notice.slideDown( 'fast' );
251+
let modalOverlay = document.querySelector( '.courier-notices[data-courier-placement="popup-modal"] .courier-modal-overlay' );
252+
if ( modalOverlay ) {
253+
modalOverlay.appendChild( noticeElement );
254+
modalOverlay.classList.remove( 'hide' );
255+
modalOverlay.style.display = 'block';
256+
slideDown( noticeElement );
257+
}
219258

220259
window.courier_notices_modal_notices.splice( index, 1 );
221260
}
222261

262+
/**
263+
* Vanilla JavaScript slideDown animation
264+
*
265+
* @param {HTMLElement} element Element to slide down
266+
* @param {Function} callback Optional callback when animation completes
267+
*/
268+
function slideDown( element, callback ) {
269+
element.style.display = 'block';
270+
element.style.overflow = 'hidden';
271+
272+
let height = element.scrollHeight;
273+
element.style.height = '0px';
274+
element.style.transition = 'height 0.3s ease';
275+
276+
// Force browser reflow
277+
element.offsetHeight;
278+
279+
element.style.height = height + 'px';
280+
281+
setTimeout( function() {
282+
element.style.height = '';
283+
element.style.overflow = '';
284+
element.style.transition = '';
285+
if ( callback ) {
286+
callback();
287+
}
288+
}, 300 );
289+
}
290+
291+
// Listen for next modal event
292+
document.addEventListener( 'courierModalNext', function() {
293+
if ( window.courier_notices_modal_notices && window.courier_notices_modal_notices.length > 0 ) {
294+
displayModal( 0 );
295+
}
296+
});
297+
223298
domReady( init );
224299
}

0 commit comments

Comments
 (0)