Skip to content

Commit cc73b8c

Browse files
authored
Merge pull request #663 from ProgressPlanner/filip/interactive-tasks
Convert more tasks to Interactive
2 parents 1466073 + fc57280 commit cc73b8c

35 files changed

Lines changed: 2195 additions & 59 deletions
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* global prplInteractiveTaskFormListener, prplDocumentReady, progressPlanner */
2+
3+
/*
4+
* Set the permalink structure.
5+
*
6+
* Dependencies: progress-planner/recommendations/interactive-task, progress-planner/document-ready
7+
*/
8+
9+
prplInteractiveTaskFormListener.customSubmit( {
10+
taskId: 'core-permalink-structure',
11+
popoverId: 'prpl-popover-core-permalink-structure',
12+
callback: () => {
13+
const customPermalinkStructure = document.querySelector(
14+
'#prpl-popover-core-permalink-structure input[name="prpl_custom_permalink_structure"]'
15+
);
16+
17+
fetch( progressPlanner.ajaxUrl, {
18+
method: 'POST',
19+
headers: {
20+
'Content-Type': 'application/x-www-form-urlencoded',
21+
},
22+
body: new URLSearchParams( {
23+
action: 'prpl_interactive_task_submit_core-permalink-structure',
24+
nonce: progressPlanner.nonce,
25+
value: customPermalinkStructure.value,
26+
} ),
27+
} );
28+
},
29+
} );
30+
31+
prplDocumentReady( () => {
32+
// Handle custom date format input, this value is what is actually submitted to the server.
33+
const customPermalinkStructureInput = document.querySelector(
34+
'#prpl-popover-core-permalink-structure input[name="prpl_custom_permalink_structure"]'
35+
);
36+
37+
// If there is no custom permalink structure input, return.
38+
if ( ! customPermalinkStructureInput ) {
39+
return;
40+
}
41+
42+
// Handle date format radio button clicks.
43+
document
44+
.querySelectorAll(
45+
'#prpl-popover-core-permalink-structure input[name="prpl_permalink_structure"]'
46+
)
47+
.forEach( function ( input ) {
48+
input.addEventListener( 'click', function () {
49+
// Dont update the custom permalink structure input if the custom radio button is checked.
50+
if ( 'prpl_permalink_structure_custom_radio' !== this.id ) {
51+
customPermalinkStructureInput.value = this.value;
52+
}
53+
} );
54+
} );
55+
56+
// If users clicks on the custom permalink structure input, check the custom radio button.
57+
customPermalinkStructureInput.addEventListener( 'click', function () {
58+
document.getElementById(
59+
'prpl_permalink_structure_custom_radio'
60+
).checked = true;
61+
} );
62+
} );
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/* global prplInteractiveTaskFormListener, prplSiteIcon */
2+
/**
3+
* Core Site Icon recommendation.
4+
*
5+
* Dependencies: progress-planner/recommendations/interactive-task, wp-api
6+
*/
7+
( function () {
8+
/**
9+
* Core Site Icon class.
10+
*/
11+
class CoreSiteIcon {
12+
/**
13+
* Constructor.
14+
*/
15+
constructor() {
16+
this.mediaUploader = null;
17+
this.elements = this.getElements();
18+
this.init();
19+
}
20+
21+
/**
22+
* Get all DOM elements.
23+
*
24+
* @return {Object} Object containing all DOM elements.
25+
*/
26+
getElements() {
27+
return {
28+
uploadButton: document.getElementById(
29+
'prpl-upload-site-icon-button'
30+
),
31+
popover: document.getElementById(
32+
'prpl-popover-core-siteicon'
33+
),
34+
hiddenField: document.getElementById( 'prpl-site-icon-id' ),
35+
preview: document.getElementById( 'site-icon-preview' ),
36+
submitButton: document.getElementById(
37+
'prpl-set-site-icon-button'
38+
),
39+
};
40+
}
41+
42+
/**
43+
* Initialize the component.
44+
*/
45+
init() {
46+
if ( this.elements.uploadButton ) {
47+
this.bindEvents();
48+
}
49+
this.initFormListener();
50+
}
51+
52+
/**
53+
* Bind event listeners.
54+
*/
55+
bindEvents() {
56+
this.elements.uploadButton.addEventListener( 'click', ( e ) => {
57+
this.handleUploadButtonClick( e );
58+
} );
59+
}
60+
61+
/**
62+
* Handle upload button click.
63+
*
64+
* @param {Event} e The click event.
65+
*/
66+
handleUploadButtonClick( e ) {
67+
e.preventDefault();
68+
69+
// If the uploader object has already been created, reopen the dialog.
70+
if ( this.mediaUploader ) {
71+
this.mediaUploader.open();
72+
return;
73+
}
74+
75+
this.createMediaUploader();
76+
this.bindMediaUploaderEvents();
77+
this.mediaUploader.open();
78+
}
79+
80+
/**
81+
* Create the media uploader.
82+
*/
83+
createMediaUploader() {
84+
this.mediaUploader = wp.media.frames.file_frame = wp.media( {
85+
title: prplSiteIcon?.mediaTitle || 'Choose Site Icon',
86+
button: {
87+
text: prplSiteIcon?.mediaButtonText || 'Use as Site Icon',
88+
},
89+
multiple: false,
90+
library: {
91+
type: 'image',
92+
},
93+
} );
94+
}
95+
96+
/**
97+
* Bind media uploader events.
98+
*/
99+
bindMediaUploaderEvents() {
100+
// Hide popover when media library opens.
101+
this.mediaUploader.on( 'open', () => {
102+
if ( this.elements.popover ) {
103+
this.elements.popover.hidePopover();
104+
}
105+
} );
106+
107+
// Show popover when media library closes.
108+
this.mediaUploader.on( 'close', () => {
109+
if ( this.elements.popover ) {
110+
this.elements.popover.showPopover();
111+
}
112+
} );
113+
114+
// Handle image selection.
115+
this.mediaUploader.on( 'select', () => {
116+
this.handleImageSelection();
117+
} );
118+
}
119+
120+
/**
121+
* Handle image selection.
122+
*/
123+
handleImageSelection() {
124+
const attachment = this.mediaUploader
125+
.state()
126+
.get( 'selection' )
127+
.first()
128+
.toJSON();
129+
130+
this.updateHiddenField( attachment );
131+
this.updatePreview( attachment );
132+
this.enableSubmitButton();
133+
}
134+
135+
/**
136+
* Update the hidden field with attachment ID.
137+
*
138+
* @param {Object} attachment The selected attachment.
139+
*/
140+
updateHiddenField( attachment ) {
141+
if ( this.elements.hiddenField ) {
142+
this.elements.hiddenField.value = attachment.id;
143+
}
144+
}
145+
146+
/**
147+
* Update the preview with the selected image.
148+
*
149+
* @param {Object} attachment The selected attachment.
150+
*/
151+
updatePreview( attachment ) {
152+
if ( ! this.elements.preview ) {
153+
return;
154+
}
155+
156+
// Use thumbnail size if available, otherwise use full size.
157+
const imageUrl =
158+
attachment.sizes && attachment.sizes.thumbnail
159+
? attachment.sizes.thumbnail.url
160+
: attachment.url;
161+
162+
this.elements.preview.innerHTML =
163+
'<img src="' +
164+
imageUrl +
165+
'" alt="' +
166+
( attachment.alt || 'Site icon preview' ) +
167+
'" style="max-width: 150px; height: auto; border-radius: 4px; border: 1px solid #ddd;">';
168+
}
169+
170+
/**
171+
* Enable the submit button.
172+
*/
173+
enableSubmitButton() {
174+
if ( this.elements.submitButton ) {
175+
this.elements.submitButton.disabled = false;
176+
}
177+
}
178+
179+
/**
180+
* Initialize the form listener.
181+
*/
182+
initFormListener() {
183+
prplInteractiveTaskFormListener.siteSettings( {
184+
settingAPIKey: 'site_icon',
185+
setting: 'site_icon',
186+
taskId: 'core-siteicon',
187+
popoverId: 'prpl-popover-core-siteicon',
188+
settingCallbackValue: ( value ) => parseInt( value, 10 ),
189+
} );
190+
}
191+
}
192+
193+
// Initialize the component.
194+
new CoreSiteIcon();
195+
} )();

assets/js/recommendations/interactive-task.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ const prplInteractiveTaskFormListener = {
7373
return;
7474
}
7575

76-
// Add a form listener to the form.
77-
formElement.addEventListener( 'submit', ( event ) => {
76+
const formSubmitHandler = ( event ) => {
7877
event.preventDefault();
7978

8079
callback();
@@ -93,7 +92,13 @@ const prplInteractiveTaskFormListener = {
9392
// Close popover.
9493
document.getElementById( popoverId ).hidePopover();
9594
} );
96-
} );
95+
96+
// Remove the form listener once the callback is executed.
97+
formElement.removeEventListener( 'submit', formSubmitHandler );
98+
};
99+
100+
// Add a form listener to the form.
101+
formElement.addEventListener( 'submit', formSubmitHandler );
97102
},
98103

99104
settings: ( {

0 commit comments

Comments
 (0)