PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 7.9.8
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v7.9.8
8.0.4 8.0.3 8.0.1 8.0.2 8.0.0 7.9.9.7 7.9.9.6 7.9.9.5 7.9.9.4 7.9.9.3 7.9.9.2 7.9.9.1 7.9.9 7.9.8 7.9.7 7.9.6 7.9.5 7.9.4 7.9.3 7.9.2 7.9.1 7.9.0 7.8.9 7.8.8 7.8.7 All 46 releases
gamipress / assets / js / gamipress-admin-functions.js

gamipress-admin-functions.js in GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI 7.9.8, at assets/js/gamipress-admin-functions.js

645 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Helper function to initialize select2 on fields
3 *
4 * @since 1.6.6
5 *
6 * @param {Object} $this
7 */
8 function gamipress_selector( $this ) {
9
10 // Prevent load select2 on widgets lists
11 if( $this.closest('#available-widgets').length )
12 return;
13
14 var select2_args = {
15 theme: 'default gamipress-select2',
16 placeholder: ( $this.data('placeholder') ? $this.data('placeholder') : gamipress_admin_functions.selector_placeholder ),
17 allowClear: true,
18 multiple: ( $this[0].hasAttribute('multiple') ),
19 matcher: gamipress_select2_words_matcher,
20 };
21
22 $this.gamipress_select2( select2_args );
23
24 }
25
26 /**
27 * Helper function to initialize select2 post selector on fields
28 *
29 * @since 1.6.6
30 *
31 * @param {Object} $this
32 */
33 function gamipress_post_selector( $this ) {
34
35 // Prevent load select2 on widgets lists
36 if( $this.closest('#available-widgets').length )
37 return;
38
39 var select2_args = {
40 ajax: {
41 url: ajaxurl,
42 dataType: 'json',
43 delay: 250,
44 type: 'POST',
45 data: function( params ) {
46 return {
47 q: params.term,
48 page: params.page || 1,
49 action: ( $this.data('action') ? $this.data('action') : 'gamipress_get_posts' ),
50 nonce: gamipress_admin_functions.nonce,
51 post_type: $this.data('post-type').split(','),
52 };
53 },
54 processResults: gamipress_select2_posts_process_results
55 },
56 escapeMarkup: function ( markup ) { return markup; },
57 templateResult: gamipress_select2_posts_template_result,
58 theme: 'default gamipress-select2',
59 placeholder: ( $this.data('placeholder') ? $this.data('placeholder') : gamipress_admin_functions.post_selector_placeholder ),
60 allowClear: true,
61 multiple: ( $this[0].hasAttribute('multiple') ),
62 matcher: gamipress_select2_words_matcher,
63 };
64
65 $this.gamipress_select2( select2_args );
66
67 }
68
69 /**
70 * Helper function to initialize select2 user selector on fields
71 *
72 * @since 1.6.6
73 *
74 * @param {Object} $this
75 */
76 function gamipress_user_selector( $this ) {
77
78 // Prevent load select2 on widgets lists
79 if( $this.closest('#available-widgets').length )
80 return;
81
82 var select2_args = {
83 ajax: {
84 url: ajaxurl,
85 dataType: 'json',
86 delay: 250,
87 type: 'POST',
88 data: function( params ) {
89 return {
90 q: params.term,
91 page: params.page || 1,
92 action: 'gamipress_get_users',
93 nonce: gamipress_admin_functions.nonce,
94 };
95 },
96 processResults: gamipress_select2_users_process_results
97 },
98 escapeMarkup: function ( markup ) { return markup; },
99 templateResult: gamipress_select2_users_template_result,
100 theme: 'default gamipress-select2',
101 placeholder: ( $this.data('placeholder') ? $this.data('placeholder') : gamipress_admin_functions.user_selector_placeholder ),
102 allowClear: true,
103 multiple: ( $this[0].hasAttribute('multiple') ),
104 matcher: gamipress_select2_words_matcher,
105 };
106
107 $this.gamipress_select2( select2_args );
108
109 }
110
111 /**
112 * Helper function to destroy a select2 element when the method destroy does not works
113 *
114 * @since 1.6.6
115 *
116 * @param {Object} $this
117 */
118 function gamipress_select2_destroy( $this, clear_options = false ) {
119 $this.removeAttr('data-select2-id');
120 $this.removeData('data-hash');
121 $this.next('.select2').remove();
122
123 if( clear_options ) {
124 $this.find('option').remove();
125 }
126 }
127
128 /**
129 * Custom formatting for posts on select2
130 *
131 * @since 1.4.1
132 *
133 * @param {Object} item
134 *
135 * @return {string}
136 */
137 function gamipress_select2_posts_template_result( item ) {
138
139 if( item.post_parent_title !== undefined ) {
140 return gamipress_select2_post_parent_template_result( item );
141 }
142
143 if( item.post_type !== undefined ) {
144
145 var post_type_label = item.post_type;
146
147 if( gamipress_post_type_exists( item.post_type ) ) {
148 post_type_label = gamipress_get_post_type_label( item.post_type );
149 }
150
151 return '<strong>' + item.post_title + '</strong>'
152 + '<span class="result-description">'
153 + 'ID: ' + item.ID + '<span class="align-right">' + post_type_label + '</span>'
154 + ( item.site_name !== undefined ? ' (' + item.site_name + ')' : '' )
155 + '</span>';
156 }
157
158 return item.text;
159
160 }
161
162 /**
163 * Custom formatting for post with parent information on select2
164 *
165 * @since 1.4.1
166 *
167 * @param {Object} item
168 *
169 * @return {string}
170 */
171 function gamipress_select2_post_parent_template_result( item ) {
172
173 if( item.post_parent_type !== undefined ) {
174
175 var post_type_label = item.post_parent_type;
176
177 if( item.post_parent_type === 'points-type' ) {
178 post_type_label = '';
179 } else if( gamipress_post_type_exists( item.post_parent_type ) ) {
180 post_type_label = gamipress_get_post_type_label( item.post_parent_type );
181
182 post_type_label += ':';
183 }
184
185
186
187 return '<strong>' + item.post_title + '</strong>'
188 + '<span class="result-description">'
189 + 'ID: ' + item.ID + '<span class="align-right">' + post_type_label + ' ' + item.post_parent_title + '</span>'
190 + ( item.site_name !== undefined ? ' (' + item.site_name + ')' : '' )
191 + '</span>';
192 }
193
194 return item.text;
195
196 }
197
198 /**
199 * Custom results processing for posts on select2
200 *
201 * @since 1.4.1
202 *
203 * @param {Object} response
204 * @param {Object} params
205 *
206 * @return {string}
207 */
208 function gamipress_select2_posts_process_results( response, params ) {
209
210 if( response === null ) {
211 return { results: [] };
212 }
213
214 var formatted_results = [];
215
216 // Paginated responses will come with results and more_results keys
217 var results = ( response.data.results !== undefined ? response.data.results : response.data );
218
219 results.forEach( function( item ) {
220
221 // Extend select2 keys (id and text) with given keys (ID, post_title and optionally post_type, site_id and site_name)
222 formatted_results.push( jQuery.extend({
223 id: item.ID,
224 text: item.post_title + ' (#' + item.ID + ')',
225 }, item ) );
226
227 } );
228
229 return {
230 results: formatted_results,
231 pagination: {
232 more: ( response.data.more_results !== undefined ? response.data.more_results : false )
233 }
234 };
235
236 }
237
238 /**
239 * Custom formatting for users on select2
240 *
241 * @since 1.4.1
242 *
243 * @param {Object} item
244 *
245 * @return {string}
246 */
247 function gamipress_select2_users_template_result( item ) {
248
249 if( item.display_name !== undefined ) {
250
251 return '<strong>' + item.display_name + '</strong>'
252 + '<span class="result-description">'
253 + 'ID: ' + item.ID + ' - ' + item.user_email + ' (' + item.user_login + ')'
254 + '</span>';
255 }
256
257 return item.text;
258
259 }
260
261 /**
262 * Custom results processing for users on select2
263 *
264 * @since 1.4.1
265 *
266 * @param {Object} response
267 * @param {Object} params
268 *
269 * @return {string}
270 */
271 function gamipress_select2_users_process_results( response, params ) {
272
273 if( response === null ) {
274 return { results: [] };
275 }
276
277 var formatted_results = [];
278
279 // Paginated responses will come with results and more_results keys
280 var results = ( response.data.results !== undefined ? response.data.results : response.data );
281
282 results.forEach( function( item ) {
283
284 // Extend select2 keys (id and text) with given keys (ID, post_title and optionally post_type)
285 formatted_results.push( jQuery.extend({
286 id: item.ID,
287 text: item.user_login + ' (#' + item.ID + ')',
288 }, item ) );
289
290 } );
291
292 return {
293 results: formatted_results,
294 pagination: {
295 more: ( response.data.more_results !== undefined ? response.data.more_results : false )
296 }
297 };
298
299 }
300
301 /**
302 * Helper function to check if text has any word of a term
303 *
304 * @since 1.0.0
305 *
306 * @param {String} text
307 * @param {String} term
308 *
309 * @return {boolean}
310 */
311 function gamipress_matches_by_word( text, term ) {
312
313 text = text.toUpperCase();
314 var words = term.toUpperCase().split(" ");
315 var found = true;
316
317 // Check if the text contains the term (separated in words)
318 for (var i =0; i < words.length; i++)
319 found = ( found && text.indexOf( words[i] ) >= 0 );
320
321 return found;
322
323 }
324
325 /**
326 * Select2 search matcher by word
327 *
328 * @since 1.0.0
329 *
330 * @param {Object} params
331 * @param {Object} data
332 *
333 * @return {mixed}
334 */
335 function gamipress_select2_words_matcher( params, data ) {
336
337 // Always return the object if there is nothing to compare
338 if ( params.term === undefined || params.term.trim() === '' ) return data;
339
340 // Return the object if any word matches
341 if ( gamipress_matches_by_word( data.text, params.term ) ) return data;
342
343 // If it doesn't contain the term, don't return anything
344 return null;
345
346 }
347
348 /**
349 * Custom search matcher for selects with groups on select2
350 *
351 * @since 1.6.3
352 *
353 * @param {Object} params
354 * @param {Object} data
355 *
356 * @return {mixed}
357 */
358 function gamipress_select2_optgroup_matcher( params, data ) {
359
360 // Initialize required vars
361 data.parentText = data.parentText || '';
362
363 // Always return the object if there is nothing to compare
364 if ( params.term === undefined || params.term.trim() === '' ) return data;
365
366 // Do a recursive check for options with children
367 if ( data.children && data.children.length > 0 ) {
368
369 // Clone the data object if there are children
370 // This is required as we modify the object to remove any non-matches
371 var match = jQuery.extend( true, {}, data );
372
373 // Check each child of the option
374 for ( var c = data.children.length - 1; c >= 0; c-- ) {
375
376 var child = data.children[c];
377 child.parentText += data.parentText + " " + data.text;
378
379 var matches = gamipress_select2_optgroup_matcher( params, child );
380
381 // If there wasn't a match, remove the object in the array
382 if (matches == null) {
383 match.children.splice( c, 1 );
384 }
385
386 }
387
388 // If any children matched, return the new object
389 if ( match.children.length > 0 ) {
390 return match;
391 }
392
393 // If there were no matching children, check just the plain object
394 return gamipress_select2_optgroup_matcher( params, match );
395
396 }
397
398 // Check if term matches with this text or text from parent
399 if ( gamipress_matches_by_word( ( data.parentText + ' ' + data.text ), params.term ) ) return data;
400
401 // If it doesn't contain the term, don't return anything
402 return null;
403 }
404
405 /**
406 * Check if post type has been registered
407 *
408 * @since 1.6.5
409 *
410 * @param {string} post_type
411 *
412 * @return {boolean}
413 */
414 function gamipress_post_type_exists( post_type ) {
415 return ( gamipress_admin_functions.post_type_labels[post_type] !== undefined )
416 }
417
418 /**
419 * Get the post type label (singular name)
420 *
421 * @since 1.6.5
422 *
423 * @param {string} post_type
424 *
425 * @return {string}
426 */
427 function gamipress_get_post_type_label( post_type ) {
428
429 var label = '';
430
431 if( gamipress_post_type_exists( post_type ) ) {
432 label = gamipress_admin_functions.post_type_labels[post_type];
433 }
434
435 return label;
436 }
437
438 /**
439 * Check if given term is on reserved terms
440 *
441 * @since 1.7.4
442 *
443 * @param {string} term
444 *
445 * @return {boolean}
446 */
447 function gamipress_is_reserved_term( term ) {
448 return ( gamipress_admin_functions.reserved_terms.indexOf( term ) !== -1 )
449 }
450
451 /**
452 * Check if given slug has any error (like invalid chars, exceeds lenght, etc)
453 *
454 * @since 1.7.4
455 *
456 * @param {string} slug
457 * @param {string} current_slug
458 *
459 * @return {string}
460 */
461 function gamipress_get_slug_error( slug, current_slug ) {
462
463 // Only allow alphanumeric characters, "-" adn "_"
464 if( /[^a-zA-Z0-9\-_]/.test( slug ) )
465 return gamipress_admin_functions.slug_error_special_char;
466
467 // Check if slug is greater than 20 characters (maximum allowed for a post type)
468 if ( slug.length > 20 )
469 return gamipress_admin_functions.slug_error_max_length;
470
471 // Check if slug has been already registered
472 if( gamipress_post_type_exists( slug ) && slug !== current_slug )
473 return gamipress_admin_functions.slug_error_post_type.replace( '%s', gamipress_get_post_type_label( slug ) );
474
475 // Check if slug matches a reserved term
476 if ( gamipress_is_reserved_term( slug ) )
477 return gamipress_admin_functions.slug_error_reserved_term;
478
479 // No errors
480 return '';
481 }
482
483 /**
484 * Function to turn an object or a JSON object to a CSV file and force the download (Used on import/export tools)
485 *
486 * @since 1.6.4
487 *
488 * @param {Object} data
489 * @param {string} filename
490 */
491 function gamipress_download_csv( data, filename ) {
492
493 // Convert JSON to CSV
494 var csv = gamipress_object_to_csv( data );
495
496 gamipress_download_file( csv, filename, 'csv' );
497
498 }
499
500 /**
501 * Function to force the download of the given content (Used on import/export tools)
502 *
503 * @since 1.7.0
504 *
505 * @param {string} content
506 * @param {string} filename
507 * @param {string} extension
508 * @param {string} mime_type
509 * @param {string} charset
510 */
511 function gamipress_download_file( content, filename, extension, mime_type = '', charset = '' ) {
512
513 if( mime_type === undefined || mime_type === '' )
514 mime_type = 'text/' + extension;
515
516 if( charset === undefined || charset === '' )
517 charset = 'utf-8';
518
519 // Setup the file name
520 var file = ( filename.length ? filename + '.' + extension : 'file.' + extension );
521
522 var blob = new Blob( [content], { type: mime_type + ';charset=' + charset + ';' } );
523
524 if (navigator.msSaveBlob) {
525
526 // IE 10+
527 navigator.msSaveBlob( blob, file );
528
529 } else {
530
531 var link = document.createElement("a");
532
533 // Hide the link element
534 link.style.visibility = 'hidden';
535
536 // Check if browser supports HTML5 download attribute
537 if ( link.download !== undefined ) {
538
539 // Build the URL object
540 var url = URL.createObjectURL( blob );
541
542 // Update link attributes
543 link.setAttribute( "href", url );
544 link.setAttribute( "download", file );
545
546 // Append the link element and trigger the click event
547 document.body.appendChild( link );
548
549 link.click(); // NOTE: Is not a jQuery element, so is safe to use click()
550
551 // Finally remove the link element
552 document.body.removeChild( link );
553
554 }
555 }
556
557 }
558
559 /**
560 * Format an object into a CSV line
561 *
562 * @since 1.6.4
563 *
564 * @param {Object} obj
565 *
566 * @return {string}
567 */
568 function gamipress_object_to_csv( obj ) {
569
570 // Convert JSON to Object
571 var array = typeof obj !== 'object' ? JSON.parse( obj ) : obj;
572 var str = '';
573
574 for ( var i = 0; i < array.length; i++ ) {
575
576 var line = '';
577
578 for ( var index in array[i] ) {
579
580 // Separator
581 if ( line !== '' ) {
582 line += ',';
583 }
584
585 // Build a new line
586 line += '"' + array[i][index] + '"';
587 }
588
589 // Append the line break
590 str += line + '\r\n';
591
592 }
593
594 return str;
595
596 }
597
598 /**
599 * Helper function to get a parameter from an URL
600 *
601 * @since 1.0.0
602 *
603 * @param {String} url
604 * @param {String} param
605 * @param default_value
606 *
607 * @return {String}
608 */
609 function gamipress_get_url_param( url, param, default_value = false ) {
610
611 var results = new RegExp('[\?&]' + param + '=([^&#]*)').exec( url );
612
613 return results[1] || default_value;
614
615 }
616
617 /**
618 * Helper function to check if given URL is a valid one
619 *
620 * @since 1.0.0
621 *
622 * @param {String} url
623 *
624 * @return {boolean}
625 */
626 function gamipress_is_valid_url( url ) {
627 var result = url.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
628 return ( result !== null )
629 }
630
631 /**
632 * Helper function to remove script tags in a string
633 * @param String s
634 * @returns {string}
635 */
636 function gamipress_strip_scripts(s) {
637 var div = document.createElement('div');
638 div.innerHTML = s;
639 var scripts = div.getElementsByTagName('script');
640 var i = scripts.length;
641 while (i--) {
642 scripts[i].parentNode.removeChild(scripts[i]);
643 }
644 return div.innerHTML;
645 }