PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.6
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.6
8.0.6 8.0.5 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 All 48 releases
← All changes | assets/js/gamipress-admin-functions.js +645 -0 7.9.7 → 8.0.6 View file →
@@ -1,0 +1,645 @@
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 +}