PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.9
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / assets / src / js / frontend / course-builder / builder-settings.js

builder-settings.js in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.9, at assets/src/js/frontend/course-builder/builder-settings.js

375 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Settings tab JS handler for Course Builder.
3 *
4 * @since 4.3.x
5 * @version 1.2.0
6 */
7 import * as lpToastify from 'lpAssetsJsPath/lpToastify.js';
8
9 export class BuilderSettings {
10 constructor() {
11 this.form = null;
12 this.debounceTimer = null;
13 this.debounceDelay = 600;
14 this.isSaving = false;
15 this.isDirty = false;
16 this.shouldRetryOnCompleted = false;
17 this.lastSavedState = '';
18 this.mediaUploader = null;
19
20 this.init();
21 }
22
23 static selectors = {
24 elForm: '#lp-cb-settings-form',
25 elCheckbox: 'input[name="hide_instructor_access_admin_screen"]',
26 elBadge: '[data-setting-badge]',
27 elHeaderLogoLink: '.lp-cb-top-header__logo a',
28 elLogoSetting: '[data-cb-logo-setting]',
29 elDefaultLogoTemplate: '#lp-cb-default-logo-template',
30 elLogoPreviewDefault: '[data-cb-logo-preview-default]',
31 elLogoPreviewImage: '[data-cb-logo-preview-image]',
32 elLogoChooseBtn: '[data-cb-logo-choose]',
33 elLogoRemoveBtn: '[data-cb-logo-remove]',
34 elLogoIdInput: 'input[name="course_builder_logo_id"]',
35 elLogoRemoveInput: 'input[name="course_builder_logo_remove"]',
36 };
37
38 init() {
39 this.form = document.querySelector( BuilderSettings.selectors.elForm );
40 if ( ! this.form ) {
41 return;
42 }
43
44 this.cacheElements();
45 this.updateBadge( this.getCurrentValue() );
46 this.hydrateDefaultLogoPreview();
47 this.setLogoVisibility( this.getLogoId() > 0 );
48 this.lastSavedState = this.getStateFingerprint();
49 this.events();
50 }
51
52 cacheElements() {
53 this.headerLogoLink = document.querySelector( BuilderSettings.selectors.elHeaderLogoLink );
54 this.logoSetting = this.form?.querySelector( BuilderSettings.selectors.elLogoSetting );
55 this.logoPreviewDefault = this.form?.querySelector(
56 BuilderSettings.selectors.elLogoPreviewDefault
57 );
58 this.logoPreviewImage = this.form?.querySelector(
59 BuilderSettings.selectors.elLogoPreviewImage
60 );
61 this.logoChooseBtn = this.form?.querySelector( BuilderSettings.selectors.elLogoChooseBtn );
62 this.logoRemoveBtn = this.form?.querySelector( BuilderSettings.selectors.elLogoRemoveBtn );
63 this.logoIdInput = this.form?.querySelector( BuilderSettings.selectors.elLogoIdInput );
64 this.logoRemoveInput = this.form?.querySelector( BuilderSettings.selectors.elLogoRemoveInput );
65 this.defaultLogoURL = this.logoSetting?.dataset?.cbDefaultLogoUrl || '';
66 }
67
68 events() {
69 if ( BuilderSettings._loadedEvents ) {
70 return;
71 }
72 BuilderSettings._loadedEvents = true;
73
74 if ( ! this.form ) {
75 return;
76 }
77
78 this.form.addEventListener( 'change', ( e ) => {
79 if ( e.target.matches( BuilderSettings.selectors.elCheckbox ) ) {
80 this.handleSettingChange();
81 }
82 } );
83
84 if ( this.logoChooseBtn ) {
85 this.logoChooseBtn.addEventListener( 'click', ( e ) => {
86 e.preventDefault();
87 this.openLogoMediaUploader();
88 } );
89 }
90
91 if ( this.logoRemoveBtn ) {
92 this.logoRemoveBtn.addEventListener( 'click', ( e ) => {
93 e.preventDefault();
94 this.removeLogo();
95 } );
96 }
97 }
98
99 handleSettingChange() {
100 this.isDirty = true;
101 if ( this.isSaving ) {
102 this.shouldRetryOnCompleted = true;
103 }
104 this.updateBadge( this.getCurrentValue() );
105 this.queueSave();
106 }
107
108 queueSave() {
109 window.clearTimeout( this.debounceTimer );
110 this.debounceTimer = window.setTimeout( () => {
111 this.flushSave();
112 }, this.debounceDelay );
113 }
114
115 flushSave() {
116 if ( ! this.isDirty ) {
117 return;
118 }
119
120 const currentState = this.getStateFingerprint();
121 if ( currentState === this.lastSavedState ) {
122 this.isDirty = false;
123 return;
124 }
125
126 if ( this.isSaving ) {
127 return;
128 }
129
130 this.isSaving = true;
131 this.shouldRetryOnCompleted = false;
132 lpToastify.show( 'Updating settings...', 'info', { duration: 1800 } );
133
134 window.lpAJAXG.fetchAJAX( this.getPayloadForSave(), {
135 success: ( response ) => {
136 if ( response?.status !== 'success' ) {
137 this.handleSaveError( response?.message || 'Could not save changes.' );
138 return;
139 }
140
141 this.applySaveResponse( response );
142 this.isDirty = false;
143 this.lastSavedState = this.getStateFingerprint();
144 this.updateBadge( this.getCurrentValue() );
145 lpToastify.show( response?.message || 'Saved', 'success' );
146 },
147 error: ( error ) => {
148 this.handleSaveError( error?.message || error || 'An error occurred.' );
149 },
150 completed: () => {
151 this.isSaving = false;
152 if ( this.shouldRetryOnCompleted ) {
153 this.queueSave();
154 }
155 },
156 } );
157 }
158
159 getPayloadForSave() {
160 return {
161 action: 'save_global_settings',
162 args: { id_url: 'save-global-settings' },
163 hide_instructor_access_admin_screen: this.getCurrentValue(),
164 course_builder_logo_id: this.getLogoId(),
165 course_builder_logo_remove: this.getLogoRemoveValue(),
166 };
167 }
168
169 applySaveResponse( response ) {
170 const data = response?.data || {};
171 const savedLogoID = parseInt( data.course_builder_logo_id ?? this.getLogoId(), 10 ) || 0;
172 const savedLogoSrc = data.course_builder_logo_url || '';
173
174 if ( this.logoIdInput ) {
175 this.logoIdInput.value = savedLogoID;
176 }
177
178 if ( this.logoRemoveInput ) {
179 this.logoRemoveInput.value = 'no';
180 }
181
182 if ( savedLogoID > 0 && savedLogoSrc ) {
183 this.setLogoImageSource( savedLogoSrc );
184 this.setLogoVisibility( true );
185 } else if ( savedLogoID === 0 ) {
186 this.clearLogoUI();
187 }
188
189 this.syncHeaderLogo( savedLogoID > 0 ? savedLogoSrc : '' );
190 }
191
192 handleSaveError( message ) {
193 lpToastify.show( message, 'error' );
194 }
195
196 getCurrentValue() {
197 const checkbox = this.form?.querySelector( BuilderSettings.selectors.elCheckbox );
198 return checkbox && checkbox.checked ? 'yes' : 'no';
199 }
200
201 updateBadge( value ) {
202 const badgeEl = this.form?.querySelector( BuilderSettings.selectors.elBadge );
203 if ( ! badgeEl ) {
204 return;
205 }
206
207 const isEnabled = value === 'yes';
208 badgeEl.dataset.state = isEnabled ? 'enabled' : 'disabled';
209 badgeEl.textContent = isEnabled ? 'Enabled' : 'Disabled';
210 }
211
212 getStateFingerprint() {
213 return JSON.stringify( {
214 hide_instructor_access_admin_screen: this.getCurrentValue(),
215 course_builder_logo_id: this.getLogoId(),
216 course_builder_logo_remove: this.getLogoRemoveValue(),
217 } );
218 }
219
220 getLogoId() {
221 return parseInt( this.logoIdInput?.value || '0', 10 ) || 0;
222 }
223
224 getLogoRemoveValue() {
225 return this.logoRemoveInput?.value === 'yes' ? 'yes' : 'no';
226 }
227
228 openLogoMediaUploader() {
229 if ( typeof wp === 'undefined' || typeof wp.media === 'undefined' ) {
230 lpToastify.show( 'Media library is unavailable.', 'error' );
231 return;
232 }
233
234 if ( this.mediaUploader ) {
235 this.mediaUploader.open();
236 return;
237 }
238
239 this.mediaUploader = wp.media( {
240 title: 'Select logo image',
241 button: { text: 'Use this image' },
242 multiple: false,
243 library: { type: 'image' },
244 } );
245
246 this.mediaUploader.on( 'select', () => {
247 const attachment = this.mediaUploader.state().get( 'selection' ).first().toJSON();
248 const imageURL = attachment?.sizes?.full?.url || attachment?.url || '';
249 if ( ! imageURL ) {
250 return;
251 }
252
253 if ( this.logoIdInput ) {
254 this.logoIdInput.value = attachment?.id || 0;
255 }
256
257 if ( this.logoRemoveInput ) {
258 this.logoRemoveInput.value = 'no';
259 }
260
261 this.setLogoImageSource( imageURL );
262 this.setLogoVisibility( true );
263 this.handleSettingChange();
264 } );
265
266 this.mediaUploader.open();
267 }
268
269 setLogoImageSource( source ) {
270 if ( this.logoPreviewImage ) {
271 if ( source ) {
272 this.logoPreviewImage.src = source;
273 } else {
274 this.logoPreviewImage.removeAttribute( 'src' );
275 }
276 }
277 }
278
279 setLogoVisibility( visible ) {
280 if ( this.logoPreviewImage ) {
281 this.logoPreviewImage.classList.toggle( 'is-hidden', ! visible );
282 }
283
284 if ( this.logoPreviewDefault ) {
285 this.logoPreviewDefault.classList.toggle( 'is-hidden', visible );
286 }
287
288 if ( this.logoRemoveBtn ) {
289 this.logoRemoveBtn.classList.toggle( 'is-hidden', ! visible );
290 }
291 }
292
293 hydrateDefaultLogoPreview() {
294 if ( ! this.logoPreviewDefault || this.logoPreviewDefault.children.length > 0 ) {
295 return;
296 }
297
298 const defaultLogoTemplate = document.querySelector(
299 BuilderSettings.selectors.elDefaultLogoTemplate
300 );
301 const defaultLogoSVG =
302 defaultLogoTemplate?.content?.querySelector( 'svg' ) ||
303 defaultLogoTemplate?.querySelector( 'svg' ) ||
304 document.querySelector( '.lp-cb-top-header__logo svg' );
305
306 if ( ! defaultLogoSVG && ! this.defaultLogoURL ) {
307 return;
308 }
309
310 const svgPreviewImage = document.createElement( 'img' );
311 svgPreviewImage.classList.add( 'lp-cb-logo-setting__preview-default-image' );
312 svgPreviewImage.setAttribute( 'aria-hidden', 'true' );
313 svgPreviewImage.alt = 'Course Builder default logo';
314 if ( defaultLogoSVG ) {
315 svgPreviewImage.src = `data:image/svg+xml;charset=UTF-8,${ encodeURIComponent(
316 defaultLogoSVG.outerHTML
317 ) }`;
318 } else {
319 svgPreviewImage.src = this.defaultLogoURL;
320 }
321
322 this.logoPreviewDefault.appendChild( svgPreviewImage );
323 }
324
325 removeLogo() {
326 if ( ! this.logoIdInput ) {
327 return;
328 }
329
330 this.clearLogoUI();
331 if ( this.logoRemoveInput ) {
332 this.logoRemoveInput.value = 'yes';
333 }
334 this.handleSettingChange();
335 }
336
337 clearLogoUI() {
338 if ( this.logoPreviewImage ) {
339 this.logoPreviewImage.src = '';
340 }
341
342 if ( this.logoIdInput ) {
343 this.logoIdInput.value = 0;
344 }
345
346 this.setLogoVisibility( false );
347 }
348
349 syncHeaderLogo( source = '' ) {
350 if ( ! this.headerLogoLink ) {
351 return;
352 }
353
354 const logoSource = source || this.defaultLogoURL;
355 if ( ! logoSource ) {
356 return;
357 }
358
359 let logoImage = this.headerLogoLink.querySelector( '.lp-cb-top-header__logo-image' );
360 if ( ! logoImage ) {
361 logoImage = document.createElement( 'img' );
362 logoImage.classList.add( 'lp-cb-top-header__logo-image' );
363 logoImage.alt = 'Course Builder';
364 logoImage.loading = 'eager';
365 logoImage.decoding = 'async';
366 this.headerLogoLink.textContent = '';
367 this.headerLogoLink.appendChild( logoImage );
368 }
369
370 logoImage.removeAttribute( 'srcset' );
371 logoImage.removeAttribute( 'sizes' );
372 logoImage.src = logoSource;
373 }
374 }
375