PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.4
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.4
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 7.8.8 All 47 releases
gamipress / assets / js / gamipress-admin-badge-builder.js

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

1,575 lines 52.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var gamipress_badge_builder;
2 var gamipress_badge_builder_canvas;
3 var gamipress_badge_builder_canvas_backup;
4 var gamipress_badge_builder_multiple_canvas = [];
5 var gamipress_badge_builder_multiple_details = [];
6 var gamipress_badge_builder_active_obj;
7 var gamipress_badge_builder_active_obj_index;
8 var gamipress_badge_builder_history = [];
9 var gamipress_badge_builder_history_redo = [];
10 var gamipress_badge_builder_history_timer = null;
11 var gamipress_badge_builder_history_applying = false;
12 var gamipress_badge_builder_history_suspended = 0;
13
14 ( function( $ ) {
15
16 gamipress_badge_builder = $('.gamipress-badge-builder');
17
18 gamipress_badge_builder_canvas = new fabric.Canvas('gamipress-badge-builder-canvas', {
19 preserveObjectStacking: true,
20 });
21
22 gamipress_badge_builder_canvas_backup = new fabric.Canvas('gamipress-badge-builder-canvas-backup', {
23 preserveObjectStacking: true,
24 });
25
26 // Generate the initial badge
27 gamipress_badge_builder_generate_badge();
28
29 // Update selection
30 gamipress_badge_builder_canvas.on('selection:created', gamipress_badge_builder_update_selection);
31 gamipress_badge_builder_canvas.on('selection:updated', gamipress_badge_builder_update_selection);
32 gamipress_badge_builder_canvas.on('selection:cleared', gamipress_badge_builder_update_selection);
33 gamipress_badge_builder_canvas.on('mouse:down', function() {
34 var active_el = ( typeof document !== 'undefined' && document.activeElement ) ? document.activeElement : null;
35 var tag = ( active_el && active_el.tagName ) ? String( active_el.tagName ).toLowerCase() : '';
36
37 if ( ! active_el ) return;
38
39 if ( active_el.isContentEditable || [ 'input', 'textarea', 'select' ].includes( tag ) ) {
40 if ( typeof active_el.blur === 'function' ) {
41 active_el.blur();
42 }
43 }
44 });
45
46 setTimeout( gamipress_badge_builder_update_selection, 100 );
47
48 // History
49 gamipress_badge_builder_canvas.on('after:render', gamipress_badge_builder_history_schedule);
50
51 gamipress_badge_builder_history_save();
52
53 // Click icon field
54 $('.gamipress-badge-builder-selection-options').on('click', '.cmb2-id-icon .gamipress-badge-builder-icon', function(e) {
55 var selector = $('.gamipress-badge-builder-icon-selector');
56 var sidebar = $('.gamipress-badge-builder-sidebar');
57
58 if ( selector.is(':visible') ) {
59 selector.hide().scrollTop( 0 );
60 sidebar.removeClass('gamipress-badge-builder-icon-selector-open');
61 } else {
62 selector.show().scrollTop( 0 );
63 sidebar.addClass('gamipress-badge-builder-icon-selector-open');
64 }
65 });
66
67 // Click icon from icon selector
68 $('.gamipress-badge-builder-icon-selector').on('click', '.gamipress-badge-builder-icon', function(e) {
69 var icon_id = $(this).data('id');
70
71 gamipress_badge_builder_update_icon_field( icon_id );
72
73 $('.gamipress-badge-builder-selection-options .cmb2-id-icon input').val( icon_id ).trigger('change');
74
75 $('.gamipress-badge-builder-icon-selector').hide().scrollTop( 0 );
76 $('.gamipress-badge-builder-sidebar').removeClass('gamipress-badge-builder-icon-selector-open');
77 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-selector-filter input').val('').change();
78
79 });
80
81 // Click close on icon selector
82 $('.gamipress-badge-builder-icon-selector').on('click', '.gamipress-badge-builder-icon-selector-filter .dashicons', function(e) {
83 $('.gamipress-badge-builder-icon-selector').hide().scrollTop( 0 );
84 $('.gamipress-badge-builder-sidebar').removeClass('gamipress-badge-builder-icon-selector-open');
85
86 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-selector-filter input').val('').change();
87 });
88
89 // Icon selector filter
90 $('.gamipress-badge-builder-icon-selector').on('change input', '.gamipress-badge-builder-icon-selector-filter input', function(e) {
91 var search = $(this).val().toLowerCase();
92
93 if( search === '' ) {
94 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon').show();
95 $('.gamipress-badge-builder-icon-selector strong').show();
96 return;
97 }
98
99 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon').hide();
100 $('.gamipress-badge-builder-icon-selector strong').hide();
101
102 var found = $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon[data-id*="' + search + '"],'
103 + '.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon[data-id^="' + search + '"],'
104 + '.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon[data-id*="' + search + '"],'
105 + '.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon[data-id="' + search + '"]');
106
107 found.show();
108
109 found.parent().prev('strong').show();
110 });
111
112 // Range inputs synchronization
113 $('.gamipress-badge-builder-selection-options').on('change input', '.gamipress-badge-builder-range-input', function(e) {
114 var $this = $(this);
115 $this.parent().find('input[type="range"]').val( $this.val() ).trigger('change');
116 });
117
118 $('.gamipress-badge-builder-selection-options').on('change input', 'input[type="range"]', function(e) {
119 var $this = $(this);
120 $this.parent().find('.gamipress-badge-builder-range-input').val( $this.val() );
121 });
122
123 // Selection form change
124 $('.gamipress-badge-builder-selection-options').on('change input', 'input, select', function(e) {
125 gamipress_badge_builder_selection_form_change( $(this) );
126 });
127
128 // Color Pickers
129 gamipress_badge_builder_handle_colorpicker_changes();
130
131 // Toolbar actions
132 $('.gamipress-badge-builder-toolbar').on('click', '.gamipress-badge-builder-toolbar-control', function(e) {
133 gamipress_badge_builder_process_action( $(this).data('action'), $(this) );
134 });
135
136 // Sidebar actions
137 $('.gamipress-badge-builder-sidebar').on('click', '.gamipress-badge-builder-sidebar-control', function(e) {
138 gamipress_badge_builder_process_action( $(this).data('action'), $(this) );
139 });
140
141 // Generate multiple actions
142 $('.gamipress-badge-builder-generate-multiple-view').on('click', '.gamipress-badge-builder-preview-action', function(e) {
143 gamipress_badge_builder_process_action( $(this).data('action'), $(this) );
144 });
145
146
147 // Object tools
148 $('.gamipress-badge-builder-tools').on('click', '.gamipress-badge-builder-tool', function(e) {
149 gamipress_badge_builder_process_tool( $(this).data('tool') );
150 });
151
152 // Object shortcuts
153 $('body').on('click', '.gamipress-badge-builder-shortcuts-toggle', function(e) {
154 e.preventDefault();
155 var $this = $(this);
156
157 $('.gamipress-badge-builder-shortcuts-wrapper').slideToggle('fast');
158
159 if( $this.text() === gamipress_admin_badge_builder.show_text ) {
160 $this.text(gamipress_admin_badge_builder.hide_text);
161 } else {
162 $this.text(gamipress_admin_badge_builder.show_text);
163 }
164 });
165
166 // Upload
167 // GPB
168 $('body').on('click', '.gamipress-badge-builder-upload-gpb', function(e) {
169 $('input#gamipress-badge-builder-upload-gpb-input')[0].click();
170 });
171
172 $('body').on('change', '.gamipress-badge-builder-upload-gpb input', function(e) {
173 gamipress_badge_builder_import_gpb( this );
174 });
175
176 // Save as
177 $('body').on('click', '.gamipress-badge-builder-action-save-dropdown li', function(e) {
178 var format = $(this).attr('class').replace('gamipress-badge-builder-save-', '');
179 gamipress_badge_builder_process_save( format );
180 });
181
182 // Generate Multiple > Save as
183 $('body').on('click', '.gamipress-badge-builder-preview-action-download-dropdown li', function(e) {
184 var format = $(this).attr('class').replace('gamipress-badge-builder-preview-save-', '');
185
186 var i = parseInt( $(this).closest('.gamipress-badge-builder-preview').data('index') );
187 var details = gamipress_badge_builder_multiple_details[i];
188
189 details.canvas = gamipress_badge_builder_canvas_backup;
190
191 gamipress_badge_builder_canvas_backup.clear();
192 gamipress_badge_builder_generate_badge( details );
193
194 setTimeout( function() {
195 gamipress_badge_builder_process_save( format, gamipress_badge_builder_canvas_backup );
196 }, 100 );
197 });
198
199
200 } )( jQuery );
201
202 /**
203 * Get colors pairs
204 *
205 * @since 7.0.0
206 *
207 * @return {Array}
208 */
209 function gamipress_badge_builder_colors_pairs() {
210 return {
211 material: [
212 ['#e3574d', '#822c28', '#f59191', '#822c28'],
213 ['#e3574d', '#822c28', '#ffeeee', '#822c28'],
214 ['#822c28', '#e3574d', '#f59191', '#e3574d'],
215 ['#71b243', '#276d36', '#bad970', '#276d36'],
216 ['#71b243', '#276d36', '#eeffee', '#276d36'],
217 ['#276d36', '#71b243', '#bad970', '#71b243'],
218 ['#6cc8bd', '#2f7b76', '#b3e0dd', '#2f7b76'],
219 ['#6cc8bd', '#2f7b76', '#eeffff', '#2f7b76'],
220 ['#2f7b76', '#6cc8bd', '#b3e0dd', '#6cc8bd'],
221 ['#f27da2', '#bc374b', '#ebc5bf', '#bc374b'],
222 ['#f27da2', '#bc374b', '#FFFFFF', '#bc374b'],
223 ['#bc374b', '#f27da2', '#ebc5bf', '#f27da2'],
224 ['#e6c539', '#d18529', '#fcf6d9', '#d18529'],
225 ['#e6c539', '#d18529', '#FFFFFF', '#d18529'],
226 ['#d18529', '#e6c539', '#fcf6d9', '#e6c539'],
227 ['#3ea5d0', '#265771', '#9adbf4', '#265771'],
228 ['#3ea5d0', '#265771', '#FFFFFF', '#265771'],
229 ['#265771', '#3ea5d0', '#9adbf4', '#3ea5d0'],
230 ['#937cb9', '#513d78', '#ddd5e9', '#513d78'],
231 ['#937cb9', '#513d78', '#FFFFFF', '#513d78'],
232 ['#513d78', '#937cb9', '#ddd5e9', '#937cb9'],
233 ['#f69625', '#a74824', '#ead0bf', '#a74824'],
234 ['#f69625', '#a74824', '#FFFFFF', '#a74824'],
235 ['#a74824', '#f69625', '#ead0bf', '#f69625'],
236 ],
237 pastel: [
238 ['#fbdfe4', '#f7a3b2', '#f9f9f9', '#f7a3b2'],
239 ['#f7a3b2', '#fbdfe4', '#f9f9f9', '#fbdfe4'],
240 ['#cbb0d7', '#bd89c6', '#f0def7', '#bd89c6'],
241 ['#bd89c6', '#cbb0d7', '#f0def7', '#cbb0d7'],
242 ['#fda384', '#f28583', '#fcddd4', '#f28583'],
243 ['#f28583', '#fda384', '#fcddd4', '#fda384'],
244 ['#98c2ea', '#7aacdb', '#dbe6ff', '#7aacdb'],
245 ['#7aacdb', '#98c2ea', '#dbe6ff', '#98c2ea'],
246 ['#a1dacb', '#88bdab', '#e3f9f8', '#88bdab'],
247 ['#88bdab', '#a1dacb', '#e3f9f8', '#a1dacb'],
248 ['#baedb6', '#9ddb8a', '#d9f4db', '#9ddb8a'],
249 ['#9ddb8a', '#baedb6', '#d9f4db', '#baedb6'],
250 ['#e6ee92', '#d8e54e', '#f2fcd6', '#d8e54e'],
251 ['#d8e54e', '#e6ee92', '#f2fcd6', '#e6ee92'],
252 ['#bdcab3', '#9fb492', '#cfe2c9', '#9fb492'],
253 ['#9fb492', '#bdcab3', '#cfe2c9', '#bdcab3'],
254 ['#f9f4ad', '#f2e774', '#f9f9de', '#f2e774'],
255 ['#f2e774', '#f9f4ad', '#f9f9de', '#f9f4ad'],
256 ],
257 vintage: [
258 ['#233D4D', '#215E61', '#E5D9B0', '#FE7F2D'],
259 ['#233D4D', '#215E61', '#FE7F2D', '#E5D9B0'],
260 ['#E5D9B0', '#DE802B', '#5C6F2B', '#EEEEEE'],
261 ['#3b4f00', '#5C6F2B', '#DE802B', '#E5D9B0'],
262 ['#656D3F', '#84934A', '#492828', '#E5D9B0'],
263 ['#79C9C5', '#3F9AAE', '#FFE2AF', '#F96E5B'],
264 ['#FFE2AF', '#F96E5B', '#79C9C5', '#3F9AAE'],
265 ['#FDB5CE', '#3B9797', '#3B9797', '#FFFFFF'],
266 ['#213C51', '#6594B1', '#DDAED3', '#EEEEEE'],
267 ['#213C51', '#6594B1', '#EEEEEE', '#DDAED3'],
268 ['#DDAED3', '#6594B1', '#EEEEEE', '#6594B1'],
269 ['#84994F', '#FFE797', '#FFE797', '#FCB53B'],
270 ['#37353E', '#44444E', '#715A5A', '#D3DAD9'],
271 ['#44444E', '#37353E', '#D3DAD9', '#715A5A'],
272 ],
273 };
274 }
275
276 /**
277 * Get shapes
278 *
279 * @since 7.0.0
280 *
281 * @return {Array}
282 */
283 function gamipress_badge_builder_get_shapes() {
284 return gamipress_admin_badge_builder.shapes;
285 }
286
287 /**
288 * Get icons
289 *
290 * @since 7.0.0
291 *
292 * @return {Array}
293 */
294 function gamipress_badge_builder_get_icons() {
295 return gamipress_admin_badge_builder.icons;
296 }
297
298 /**
299 * Generate badge
300 *
301 * @since 7.0.0
302 *
303 * @param {Object} options
304 */
305 function gamipress_badge_builder_generate_badge( options ) {
306
307 if( options === undefined ) {
308 options = {};
309 }
310
311 if( options.canvas === undefined ) {
312 options.canvas = gamipress_badge_builder_canvas;
313 }
314
315 if( options.is_preview === undefined ) {
316 options.is_preview = false;
317 }
318
319 var colors = gamipress_badge_builder_colors_pairs();
320
321 if( options.palette === undefined || options.palette === '' ) {
322 var palette = Object.keys(colors);
323 options.palette = palette[Math.floor(Math.random() * palette.length)];
324 }
325
326 if( options.colors === undefined ) {
327 colors = colors[options.palette];
328 colors = colors[Math.floor(Math.random() * colors.length)];
329
330 if( colors[3] === undefined )
331 colors[3] = colors[1];
332
333 options.colors = colors;
334 }
335
336 if( options.shape === undefined || options.shape === '' ) {
337 var shape = gamipress_badge_builder_get_shapes();
338 options.shape = shape[Math.floor(Math.random() * shape.length)];
339 }
340
341 if( options.icon === undefined || options.icon === '' ) {
342 var icon = gamipress_badge_builder_get_icons();
343 options.icon = icon[Math.floor(Math.random() * icon.length)];
344 }
345
346 // Load Shape
347 fabric.loadSVGFromString( gamipress_badge_builder_get_icon_svg( options.shape ) ).then(({ objects }) => {
348 var obj = fabric.util.groupSVGElements(objects);
349
350 // load the shape
351 obj.clone().then(clone => {
352 clone.set({
353 id: options.shape.split('/').pop().replace('.svg', ''),
354 fill: options.colors[0],
355 strokeWidth: options.canvas.width/20,
356 strokeUniform: true,
357 strokeLineJoin: 'round',
358 stroke: options.colors[1],
359 selectable: ! options.is_preview,
360 });
361
362 gamipress_badge_builder_default_object_properties( clone );
363
364 if( clone.height > clone.width ) {
365 clone.scaleToHeight( options.canvas.height - 30 );
366 } else {
367 clone.scaleToWidth( options.canvas.width - 30 );
368 }
369
370 options.canvas.add( clone );
371
372 options.canvas.centerObject( clone );
373
374 if( ! options.is_preview )
375 options.canvas.setActiveObject( clone );
376 });
377 });
378
379 // Load Icon
380 fabric.loadSVGFromString( gamipress_badge_builder_get_icon_svg( options.icon ) ).then(({ objects }) => {
381 var obj = fabric.util.groupSVGElements(objects);
382
383 // load the icon
384 obj.clone().then(clone => {
385 clone.set({
386 id: options.icon.split('/').pop().replace('.svg', ''),
387 fill: options.colors[2],
388 strokeWidth: options.canvas.width/60,
389 strokeUniform: true,
390 strokeLineJoin: 'round',
391 stroke: options.colors[3],
392 selectable: ! options.is_preview,
393 });
394
395 gamipress_badge_builder_default_object_properties( clone );
396
397 if( clone.height > clone.width ) {
398 clone.scaleToHeight( ( options.canvas.height / 2 ) - 10 );
399 } else {
400 clone.scaleToWidth( ( options.canvas.width / 2 ) - 10 );
401 }
402
403 options.canvas.add( clone );
404
405 options.canvas.centerObject( clone );
406
407 // Icon adjustments based on shape
408 if( options.shape === 'triangle-shape' ) {
409 gamipress_badge_builder_scale( clone, 0.8 );
410 gamipress_badge_builder_move_object( clone, 0, options.canvas.height/6 );
411
412 if( options.is_preview ) {
413 gamipress_badge_builder_move_object( clone, 0, -6 );
414 }
415 } else if( options.shape === 'pentagon-shape' ) {
416 gamipress_badge_builder_move_object( clone, 0, options.canvas.height/12 );
417
418 if( options.is_preview ) {
419 gamipress_badge_builder_move_object( clone, 0, -4 );
420 }
421 } else if( options.shape === 'shield-shape' ) {
422 gamipress_badge_builder_move_object( clone, 0, -(options.canvas.height/15) );
423
424 if( options.is_preview ) {
425 gamipress_badge_builder_move_object( clone, 0, +5 );
426 }
427 }
428
429 });
430 });
431
432 options.canvas.renderAll();
433
434 return options;
435
436 }
437
438 /**
439 * Check colorpicker changes
440 *
441 * @since 7.0.0
442 */
443 function gamipress_badge_builder_handle_colorpicker_changes() {
444
445 var $ = $ || jQuery;
446 var colorpickers = $('.gamipress-badge-builder-selection-options .wp-color-picker');
447
448 // Timeout is to wait to wpColorPicker initialization
449 if( colorpickers.length === 0 ) {
450 setTimeout( gamipress_badge_builder_handle_colorpicker_changes, 500 );
451 return;
452 }
453
454 colorpickers.wpColorPicker('option', 'change', function(e, ui) {
455 // Requires a small delay when a color is selected from presets
456 setTimeout(function() {
457 gamipress_badge_builder_selection_form_change( $(e.target) );
458 }, 1 );
459
460 } );
461
462 }
463
464 /**
465 * Get icon SVG
466 *
467 * @since 7.0.0
468 *
469 * @param {String} icon_id
470 *
471 * @return {String}
472 */
473 function gamipress_badge_builder_get_icon_svg( icon_id ) {
474
475 return jQuery('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-' + icon_id + ' .gamipress-badge-builder-icon-svg').html();
476
477 }
478
479 /**
480 * Update icon field
481 *
482 * @since 7.0.0
483 *
484 * @param {String} icon_id
485 */
486 function gamipress_badge_builder_update_icon_field( icon_id ) {
487
488 var $ = $ || jQuery;
489 var form = $('.gamipress-badge-builder-selection-options');
490
491 var icon = $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-' + icon_id);
492
493 if( icon.length ) {
494 // update selected icon
495 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-selected').toggleClass('gamipress-badge-builder-icon-selected')
496 icon.toggleClass('gamipress-badge-builder-icon-selected')
497
498 var svg = gamipress_badge_builder_get_icon_svg( icon_id );
499 var name = icon.find('span.cmb-tooltip-desc').html();
500
501 // Update the form field
502 form.find('#icon').val( icon_id );
503 form.find('.cmb2-id-icon .gamipress-badge-builder-icon .gamipress-badge-builder-icon-svg').html( svg );
504 form.find('.cmb2-id-icon .gamipress-badge-builder-icon .cmb-tooltip-desc').html( name );
505 }
506
507 }
508
509 /**
510 * Update selection
511 *
512 * @since 7.0.0
513 */
514 function gamipress_badge_builder_update_selection() {
515
516 gamipress_badge_builder_active_obj = gamipress_badge_builder_canvas.getActiveObject();
517 gamipress_badge_builder_active_obj_index = gamipress_badge_builder_canvas.getObjects().indexOf( gamipress_badge_builder_active_obj );
518
519 gamipress_badge_builder_update_selection_form();
520
521 }
522
523 /**
524 * Update selection form
525 *
526 * @since 7.0.0
527 */
528 function gamipress_badge_builder_update_selection_form() {
529
530 var $ = $ || jQuery;
531 var form = $('.gamipress-badge-builder-selection-options');
532 var sidebar = $('.gamipress-badge-builder-sidebar');
533
534 if ( ! gamipress_badge_builder_active_obj ) {
535 // Hide the form
536 sidebar.css( 'right', '-24%' );
537 return;
538 }
539
540 var obj = gamipress_badge_builder_active_obj;
541
542 // Show the form
543 sidebar.css('right', '0%');
544
545 // Icon
546 form.find('.cmb2-id-icon').show();
547 gamipress_badge_builder_update_icon_field( obj.id );
548
549 // Fill
550 if( typeof obj.fill == 'object' ) {
551 form.find('#fill').val( gamipress_badge_builder_parse_color( obj.fill.colorStops[0].color ) );
552 } else {
553 form.find('#fill').val( gamipress_badge_builder_parse_color( obj.fill ) );
554 }
555
556 // Stroke
557 if( typeof obj.stroke == 'object' ) {
558 form.find('#stroke').val( gamipress_badge_builder_parse_color( obj.stroke.colorStops[0].color ) );
559 } else {
560 form.find('#stroke').val( gamipress_badge_builder_parse_color( obj.stroke ) );
561 }
562
563 form.find('#stroke_width').val( obj.strokeWidth );
564 form.find('#stroke_type').val( obj.strokeLineJoin );
565
566 /**
567 * Allow external functions to add their own logic
568 *
569 * @since 7.0.0
570 *
571 * @selector .gamipress-badge-builder
572 * @event gamipress_badge_builder_process_action
573 */
574 gamipress_badge_builder.trigger( 'gamipress_badge_builder_update_selection_form', [ form ] );
575
576 // Trigger changes
577 form.find('#fill').trigger('change');
578 form.find('#stroke_width').trigger('change');
579 form.find('#stroke').trigger('change');
580
581 }
582
583 /**
584 * Selection form field change
585 *
586 * @since 7.0.0
587 *
588 * @param {Object} field
589 */
590 function gamipress_badge_builder_selection_form_change( field ) {
591
592 var $ = $ || jQuery;
593
594 if ( ! gamipress_badge_builder_active_obj ) return;
595
596 var obj = gamipress_badge_builder_active_obj;
597
598 var form = $('.gamipress-badge-builder-selection-options');
599 var field_id = field.attr('id');
600 var value = field.val();
601
602 switch( field_id ) {
603 case 'icon':
604 var index = gamipress_badge_builder_active_obj_index;
605 var swap_obj = gamipress_badge_builder_active_obj;
606
607 gamipress_badge_builder_history_suspended++;
608
609 fabric.loadSVGFromString( gamipress_badge_builder_get_icon_svg( value ) ).then(({ objects }) => {
610 var new_obj = fabric.util.groupSVGElements(objects);
611
612 // load the shape
613 return new_obj.clone().then(clone => {
614 clone.set({
615 id: value,
616 left: swap_obj.left,
617 top: swap_obj.top,
618 fill: swap_obj.fill,
619 strokeWidth: swap_obj.strokeWidth,
620 strokeUniform: true,
621 strokeLineJoin: swap_obj.strokeLineJoin,
622 stroke: swap_obj.stroke,
623 });
624
625 gamipress_badge_builder_duplicate_object_properties( clone, swap_obj );
626
627 if( new_obj.height > new_obj.width ) {
628 clone.scaleToHeight( swap_obj.getScaledHeight() - swap_obj.strokeWidth );
629 } else {
630 clone.scaleToWidth( swap_obj.getScaledWidth() - swap_obj.strokeWidth );
631 }
632
633 gamipress_badge_builder_canvas.insertAt( index, clone );
634
635 gamipress_badge_builder_canvas.setActiveObject( clone );
636 gamipress_badge_builder_canvas.requestRenderAll();
637 });
638 }).catch(function() {
639 }).then(function() {
640 if ( gamipress_badge_builder_history_suspended > 0 ) {
641 gamipress_badge_builder_history_suspended--;
642 }
643
644 if ( typeof gamipress_badge_builder_history_schedule === 'function' ) {
645 setTimeout( function() {
646 gamipress_badge_builder_history_schedule();
647 }, 0 );
648 }
649 });
650
651 gamipress_badge_builder_delete( swap_obj );
652 break;
653 case 'fill':
654 obj.set( 'fill', gamipress_badge_builder_parse_color( value ) );
655 break;
656 case 'stroke_width':
657 value = parseInt( value );
658 if( isNaN( value ) ) value = 0;
659 obj.set('strokeWidth', value );
660 break;
661 case 'stroke':
662 obj.set( 'stroke', gamipress_badge_builder_parse_color( value ) );
663 break;
664 case 'stroke_type':
665 obj.set('strokeLineJoin', value );
666 break;
667 }
668
669 /**
670 * Allow external functions to add their own logic
671 *
672 * @since 7.0.0
673 *
674 * @selector .gamipress-badge-builder
675 * @event gamipress_badge_builder_selection_form_change
676 */
677 gamipress_badge_builder.trigger( 'gamipress_badge_builder_selection_form_change', [ form, field, field_id, value ] );
678
679 gamipress_badge_builder_canvas.renderAll();
680
681 }
682
683 /**
684 * Process action
685 *
686 * @since 7.0.0
687 *
688 * @param {String} action
689 * @param {Object} element
690 */
691 function gamipress_badge_builder_process_action( action, element ) {
692
693 var $ = $ || jQuery;
694
695 switch ( action ) {
696 case 'add-icon':
697 gamipress_badge_builder_show_options_form( 'selection' );
698
699 fabric.loadSVGFromString( gamipress_badge_builder_get_icon_svg( 'circle-shape' ) ).then(({ objects }) => {
700 var new_obj = fabric.util.groupSVGElements( objects );
701
702 // load the shape
703 new_obj.clone().then(clone => {
704 clone.set({
705 id: 'circle-shape',
706 left: gamipress_badge_builder_canvas.width / 2,
707 top: gamipress_badge_builder_canvas.height / 2,
708 fill: '#000000',
709 strokeWidth: 0,
710 strokeUniform: true,
711 strokeLineJoin: 'round',
712 stroke: '#ff0000',
713 });
714
715 gamipress_badge_builder_default_object_properties( clone );
716
717 if( clone.height > clone.width ) {
718 clone.scaleToHeight( ( gamipress_badge_builder_canvas.height / 2 ) );
719 } else {
720 clone.scaleToWidth( ( gamipress_badge_builder_canvas.width / 2 ) );
721 }
722
723 gamipress_badge_builder_canvas.add( clone );
724
725 gamipress_badge_builder_canvas.setActiveObject( clone );
726
727 });
728 });
729
730 gamipress_badge_builder_canvas.renderAll();
731
732 $('.gamipress-badge-builder-selection-options .cmb2-id-icon .gamipress-badge-builder-icon').trigger('click');
733 break;
734 case 'open-generate-badge':
735 gamipress_badge_builder_show_options_form( 'generate-badge' );
736 break;
737 case 'close-generate-badge':
738 gamipress_badge_builder_close_options_form( 'generate-badge' );
739 break;
740 case 'generate-badge':
741 var palette = $('.gamipress-badge-builder-generate-badge-options input[name="badge_palette"]:checked').val();
742
743 gamipress_badge_builder_canvas.clear();
744 gamipress_badge_builder_generate_badge( { palette: palette } );
745 break;
746 case 'open-generate-multiple':
747 var palette = $('.gamipress-badge-builder-generate-multiple-options input[name="multiple_palette"]:checked').val();
748
749 $('.gamipress-badge-builder-generate-multiple-view .gamipress-badge-builder-preview').each(function() {
750 var i = parseInt( $(this).data('index') );
751
752 if( gamipress_badge_builder_multiple_canvas[i] === undefined ) {
753 gamipress_badge_builder_multiple_canvas[i] = new fabric.Canvas($(this).attr('class') + '-canvas-' + i, {
754 preserveObjectStacking: true,
755 });
756
757 gamipress_badge_builder_multiple_canvas[i].clear();
758
759 var details = gamipress_badge_builder_generate_badge( {
760 canvas: gamipress_badge_builder_multiple_canvas[i],
761 palette: palette,
762 is_preview: true,
763 } );
764 gamipress_badge_builder_multiple_details[i] = details;
765
766 $(this).find('.gamipress-badge-builder-preview-palette-name').text(
767 gamipress_admin_badge_builder.color_palettes[details.palette].name
768 );
769 }
770 });
771
772 gamipress_badge_builder_show_options_form( 'generate-multiple' );
773 $('.gamipress-badge-builder-generate-multiple-view').css( 'left', '-2%' );
774 break;
775 case 'close-generate-multiple':
776 gamipress_badge_builder_close_options_form( 'generate-multiple' );
777 $('.gamipress-badge-builder-generate-multiple-view').css( 'left', '-84%' );
778 break;
779 case 'generate-multiple':
780 var palette = $('.gamipress-badge-builder-generate-multiple-options input[name="multiple_palette"]:checked').val();
781
782 $('.gamipress-badge-builder-generate-multiple-view .gamipress-badge-builder-preview').each(function() {
783 var i = parseInt( $(this).data('index') );
784
785 gamipress_badge_builder_multiple_canvas[i].clear();
786
787 var details = gamipress_badge_builder_generate_badge( {
788 canvas: gamipress_badge_builder_multiple_canvas[i],
789 palette: palette,
790 is_preview: true,
791 } );
792 gamipress_badge_builder_multiple_details[i] = details;
793
794 $(this).find('.gamipress-badge-builder-preview-palette-name').text(
795 gamipress_admin_badge_builder.color_palettes[details.palette].name
796 );
797 });
798 break;
799 case 'generate-multiple-edit':
800 var i = parseInt( element.closest('.gamipress-badge-builder-preview').data('index') );
801 var details = gamipress_badge_builder_multiple_details[i];
802
803 details.canvas = gamipress_badge_builder_canvas;
804 details.is_preview = false;
805
806 gamipress_badge_builder_canvas.clear();
807
808 gamipress_badge_builder_generate_badge( details );
809
810 gamipress_badge_builder_close_options_form( 'generate-multiple' );
811 $('.gamipress-badge-builder-generate-multiple-view').css( 'left', '-84%' );
812 break;
813 default:
814 /**
815 * Allow external functions to add their own process action
816 *
817 * @since 7.0.0
818 *
819 * @selector .gamipress-badge-builder
820 * @event gamipress_badge_builder_process_action
821 */
822 gamipress_badge_builder.trigger( 'gamipress_badge_builder_process_action', [ action, element ] );
823 break;
824 }
825
826 }
827
828 function gamipress_badge_builder_show_options_form( options ) {
829
830 var $ = $ || jQuery;
831
832 // Show options form
833 $('.gamipress-badge-builder-sidebar > div').hide();
834 $('.gamipress-badge-builder-' + options + '-options').show();
835
836 // Switch sidebars
837 $('.gamipress-badge-builder-sidebar').css( 'right', '0%' );
838 $('.gamipress-badge-builder-generate-multiple-view').css( 'left', '-84%' );
839
840 // Hide icon selector
841 $('.gamipress-badge-builder-icon-selector').hide().scrollTop( 0 );
842 $('.gamipress-badge-builder-sidebar').removeClass('gamipress-badge-builder-icon-selector-open');
843 $('.gamipress-badge-builder-icon-selector .gamipress-badge-builder-icon-selector-filter input').val('').change();
844
845 }
846
847 function gamipress_badge_builder_close_options_form( options ) {
848
849 var $ = $ || jQuery;
850
851 $('.gamipress-badge-builder-sidebar > div').hide();
852 $('.gamipress-badge-builder-selection-options').show();
853
854 if ( ! gamipress_badge_builder_active_obj ) {
855 $('.gamipress-badge-builder-sidebar').css( 'right', '-24%' );
856
857 }
858
859 }
860
861 /**
862 * Process tool
863 *
864 * @since 7.0.0
865 *
866 * @param {String} tool
867 */
868 function gamipress_badge_builder_process_tool( tool ) {
869
870 var $ = $ || jQuery;
871
872 if ( ! gamipress_badge_builder_active_obj ) return;
873
874 var obj = gamipress_badge_builder_active_obj;
875
876 var scale_step = 0.1;
877
878 switch ( tool ) {
879 case 'scale-up':
880 gamipress_badge_builder_scale( obj, 1.0 + scale_step );
881 break;
882 case 'scale-down':
883 gamipress_badge_builder_scale( obj, 1.0 - scale_step );
884 break;
885 case 'fit':
886 var fit_padding = parseFloat( obj.strokeWidth || 0 );
887 var fit_max_w = Math.max( 0, gamipress_badge_builder_canvas.width - fit_padding );
888 var fit_max_h = Math.max( 0, gamipress_badge_builder_canvas.height - fit_padding );
889 var fit_obj_w = obj.getScaledWidth();
890 var fit_obj_h = obj.getScaledHeight();
891 var fit_factor = 1;
892
893 if ( fit_obj_w > 0 && fit_obj_h > 0 ) {
894 fit_factor = Math.min( fit_max_w / fit_obj_w, fit_max_h / fit_obj_h );
895 }
896
897 if ( isFinite( fit_factor ) && fit_factor > 0 ) {
898 obj.scaleX *= fit_factor;
899 obj.scaleY *= fit_factor;
900 }
901
902 gamipress_badge_builder_canvas.centerObject( obj );
903 obj.setCoords();
904 break;
905 case 'rotate-left':
906 gamipress_badge_builder_rotate( obj, -5 )
907 break;
908 case 'rotate-right':
909 gamipress_badge_builder_rotate( obj, 5 );
910 break;
911 case 'flip-horizontal':
912 obj.toggle('flipX');
913 break;
914 case 'flip-vertical':
915 obj.toggle('flipY');
916 break;
917 case 'align-horizontal-left':
918 obj.left = obj.getScaledWidth()/2;
919 obj.setCoords();
920 break;
921 case 'align-horizontal-center':
922 obj.left = gamipress_badge_builder_canvas.width/2;
923 obj.setCoords();
924 break;
925 case 'align-horizontal-right':
926 obj.left = gamipress_badge_builder_canvas.width - obj.getScaledWidth()/2;
927 obj.setCoords();
928 break;
929 case 'align-vertical-top':
930 obj.top = obj.getScaledHeight()/2;
931 obj.setCoords();
932 break;
933 case 'align-vertical-center':
934 obj.top = gamipress_badge_builder_canvas.height/2;
935 obj.setCoords();
936 break;
937 case 'align-vertical-bottom':
938 obj.top = gamipress_badge_builder_canvas.height - obj.getScaledHeight()/2;
939 obj.setCoords();
940 break;
941 case 'group':
942 // Only group when multiple objects are selected
943 if (obj.type !== "activeselection") return;
944 if (!obj._objects || obj._objects.length < 2) return;
945
946 // Filter out artboard objects from selection
947 var objects = obj._objects.filter(clone => clone.data !== "artboard" );
948 if (objects.length < 2) return;
949
950 // Create fabric group with centered origin
951 const group = new fabric.Group(objects, {
952 originX: "center",
953 originY: "center"
954 });
955
956 // Discard active selection and remove individual objects
957 gamipress_badge_builder_canvas.discardActiveObject();
958 objects.forEach(obj => gamipress_badge_builder_canvas.remove( obj ) );
959
960 // Add group to canvas and set as active
961 gamipress_badge_builder_canvas.add( group );
962 gamipress_badge_builder_canvas.setActiveObject( group );
963 break;
964 case 'ungroup':
965 console.log('ungroup');
966 // Only ungroup if active object is a fabric group
967 if (obj.type !== "group") return;
968
969 // Extract child objects from group
970 const items = obj._objects ? obj.getObjects() : [];
971 if (!items.length) return;
972
973 // Discard selection and remove group wrapper
974 gamipress_badge_builder_canvas.discardActiveObject();
975 gamipress_badge_builder_canvas.remove(obj);
976
977 // Add individual objects back to canvas
978 items.forEach(clone => {
979 // Calculate global position accounting for group transform
980 var point = fabric.util.transformPoint(
981 { x: clone.left, y: clone.top },
982 obj.calcTransformMatrix()
983 );
984
985 clone.set({
986 left: point.x,
987 top: point.y,
988 scaleX: clone.scaleX * obj.scaleX,
989 scaleY: clone.scaleY * obj.scaleY,
990 angle: clone.angle + obj.angle
991 });
992
993 clone.setCoords();
994 gamipress_badge_builder_canvas.add(clone);
995 });
996
997 // Create active selection from ungrouped items
998 const selection = new fabric.ActiveSelection(items, {
999 canvas: gamipress_badge_builder_canvas
1000 });
1001 gamipress_badge_builder_canvas.setActiveObject(selection);
1002 break;
1003 case 'send-front':
1004 gamipress_badge_builder_canvas.bringObjectForward( obj );
1005 break;
1006 case 'send-back':
1007 gamipress_badge_builder_canvas.sendObjectBackwards( obj );
1008 break;
1009 case 'duplicate':
1010 obj.clone().then((clone) => {
1011
1012 clone.set({
1013 id: obj.id,
1014 });
1015
1016 gamipress_badge_builder_duplicate_object_properties( clone, obj );
1017
1018 clone.left += 20;
1019 clone.top += 20;
1020
1021 gamipress_badge_builder_canvas.add( clone );
1022
1023 gamipress_badge_builder_canvas.setActiveObject( clone );
1024 });
1025 break;
1026 case 'undo':
1027 gamipress_badge_builder_undo();
1028 break;
1029 case 'redo':
1030 gamipress_badge_builder_redo();
1031 break;
1032 case 'delete':
1033 gamipress_badge_builder_delete( obj );
1034 break;
1035 default:
1036 /**
1037 * Allow external functions to add their own process tool
1038 *
1039 * @since 7.0.0
1040 *
1041 * @selector .gamipress-badge-builder
1042 * @event gamipress_badge_builder_process_tool
1043 */
1044 gamipress_badge_builder.trigger( 'gamipress_badge_builder_process_tool', [ tool ] );
1045 break;
1046 }
1047
1048 gamipress_badge_builder_canvas.renderAll();
1049
1050 }
1051
1052 /**
1053 * Set the object center coordinates
1054 *
1055 * @since 7.0.0
1056 *
1057 * @param {Object} obj
1058 * @param {Number} x
1059 * @param {Number} y
1060 */
1061 function gamipress_badge_builder_set_object_center(obj, x, y) {
1062 obj.set({
1063 originX: 'center',
1064 originY: 'center',
1065 left: x,
1066 top: y
1067 });
1068
1069 obj.setCoords();
1070 }
1071
1072 /**
1073 * Scale object
1074 *
1075 * @since 7.0.0
1076 *
1077 * @param {Object} obj
1078 * @param {Number} factor
1079 */
1080 function gamipress_badge_builder_scale( obj, factor ) {
1081 var c = obj.getCenterPoint();
1082
1083 obj.scaleX *= factor;
1084 obj.scaleY *= factor;
1085
1086 gamipress_badge_builder_set_object_center( obj, c.x, c.y );
1087 }
1088
1089 /**
1090 * Rotate object
1091 *
1092 * @since 7.0.0
1093 *
1094 * @param {Object} obj
1095 * @param {Number} delta
1096 */
1097 function gamipress_badge_builder_rotate( obj, delta ) {
1098 obj.rotate( ( obj.angle || 0 ) + delta );
1099 obj.setCoords();
1100 }
1101
1102 /**
1103 * Delete object
1104 *
1105 * @since 7.0.0
1106 *
1107 * @param {Object} obj
1108 */
1109 function gamipress_badge_builder_delete( obj ) {
1110 gamipress_badge_builder_canvas.remove( obj );
1111 gamipress_badge_builder_canvas.requestRenderAll();
1112
1113 gamipress_badge_builder_active_obj = undefined;
1114 gamipress_badge_builder_active_obj_index = -1;
1115 }
1116
1117 /**
1118 * Parse color
1119 *
1120 * @since 7.0.0
1121 *
1122 * @param {String} color
1123 */
1124 function gamipress_badge_builder_parse_color( color ) {
1125 return '#' + new fabric.Color( color ).toHex();
1126 }
1127
1128 /**
1129 * Check if valid file
1130 *
1131 * @since 7.0.0
1132 *
1133 * @param {Object} field
1134 * @param {String} format
1135 */
1136 function gamipress_badge_builder_is_valid_file( field, format ) {
1137
1138 if( field.files.length === 0 ) {
1139 return false;
1140 }
1141
1142 var file = field.files[0];
1143 var ext = file.name.split('.').pop();
1144
1145 if( ext !== format ) {
1146 return false;
1147 }
1148
1149 return true;
1150 }
1151
1152 /**
1153 * Import GamiPress Badge (GPB)
1154 *
1155 * @since 7.0.0
1156 *
1157 * @param {Object} field
1158 */
1159 function gamipress_badge_builder_import_gpb( field ) {
1160
1161 if( ! gamipress_badge_builder_is_valid_file( field, 'gpb' ) ) {
1162 console.log( 'not valid file' );
1163 return;
1164 }
1165
1166 var file = field.files[0];
1167
1168 const reader = new FileReader();
1169 reader.onload = (e) => {
1170 if( e.target.result.length > 0 ) {
1171 gamipress_badge_builder_canvas.loadFromJSON( e.target.result );
1172
1173 setTimeout( function() {
1174 gamipress_badge_builder_canvas.renderAll();
1175 }, 1 );
1176 }
1177 };
1178 reader.readAsText(file);
1179
1180
1181 }
1182
1183 /**
1184 * Process save
1185 *
1186 * @since 7.0.0
1187 *
1188 * @param {String} format
1189 * @param {Object} canvas
1190 */
1191 function gamipress_badge_builder_process_save( format, canvas ) {
1192
1193 if( canvas === undefined ) {
1194 canvas = gamipress_badge_builder_canvas;
1195 }
1196
1197 switch( format ) {
1198 case 'gpb':
1199 var gpb = JSON.stringify( canvas.toJSON() );
1200 gamipress_badge_builder_download( "data:text/plain," + encodeURIComponent( gpb ), 'gpb' );
1201 break;
1202 case 'png':
1203 gamipress_badge_builder_download( canvas.toDataURL( 'png' ), 'png' );
1204 break;
1205 default:
1206 /**
1207 * Allow external functions to add their own process save
1208 *
1209 * @since 7.0.0
1210 *
1211 * @selector .gamipress-badge-builder
1212 * @event gamipress_badge_builder_process_save
1213 */
1214 gamipress_badge_builder.trigger( 'gamipress_badge_builder_process_save', [ format, canvas ] );
1215 break;
1216 }
1217
1218 }
1219
1220 /**
1221 * Download file
1222 *
1223 * @since 7.0.0
1224 *
1225 * @param {String} url
1226 * @param {String} ext
1227 */
1228 function gamipress_badge_builder_download( url, ext ) {
1229
1230 var $ = $ || jQuery;
1231
1232 var filename = $('#filename').val();
1233
1234 if( filename === '' ) {
1235 filename = 'gamipress-badge';
1236 }
1237
1238 filename = filename.replace(/[\/|\\:*?"<>]/g, " ");
1239 filename += '.' + ext;
1240
1241 var a = document.createElement('a');
1242 a.href = url;
1243 a.download = filename;
1244 document.body.appendChild(a);
1245 a.click();
1246 document.body.removeChild(a);
1247
1248 }
1249
1250 /**
1251 * Move object
1252 *
1253 * @since 7.0.0
1254 *
1255 * @param {Object} obj
1256 * @param {Number} dx
1257 * @param {Number} dy
1258 */
1259 function gamipress_badge_builder_move_object( obj, dx, dy ) {
1260 obj.left += dx;
1261 obj.top += dy;
1262 obj.setCoords();
1263 gamipress_badge_builder_canvas.renderAll();
1264 }
1265
1266 /**
1267 * Default object properties
1268 *
1269 * @since 7.0.0
1270 *
1271 * @param {Object} clone
1272 */
1273 function gamipress_badge_builder_default_object_properties( clone ) {
1274
1275 /**
1276 * Allow external functions to default object properties
1277 *
1278 * @since 7.0.0
1279 *
1280 * @selector .gamipress-badge-builder
1281 * @event gamipress_badge_builder_default_object_properties
1282 */
1283 gamipress_badge_builder.trigger( 'gamipress_badge_builder_default_object_properties', [ clone ] );
1284
1285 }
1286
1287 /**
1288 * Duplicate object properties
1289 *
1290 * @since 7.0.0
1291 *
1292 * @param {Object} clone
1293 * @param {Object} obj
1294 */
1295 function gamipress_badge_builder_duplicate_object_properties( clone, obj ) {
1296
1297 /**
1298 * Allow external functions to extend cloned object properties
1299 *
1300 * @since 7.0.0
1301 *
1302 * @selector .gamipress-badge-builder
1303 * @event gamipress_badge_builder_duplicate_object_properties
1304 */
1305 gamipress_badge_builder.trigger( 'gamipress_badge_builder_duplicate_object_properties', [ clone, obj ] );
1306
1307 }
1308
1309 /**
1310 * Schedule history save
1311 *
1312 * @since 7.0.0
1313 */
1314 function gamipress_badge_builder_history_schedule() {
1315 if( gamipress_badge_builder_history_applying || gamipress_badge_builder_history_suspended > 0 ) return;
1316
1317 clearTimeout( gamipress_badge_builder_history_timer );
1318 gamipress_badge_builder_history_timer = setTimeout( gamipress_badge_builder_history_save, 300 );
1319
1320 }
1321
1322 /**
1323 * History save
1324 *
1325 * @since 7.0.0
1326 */
1327 function gamipress_badge_builder_history_save() {
1328 if ( gamipress_badge_builder_history_applying || gamipress_badge_builder_history_suspended > 0 ) return;
1329
1330 gamipress_badge_builder_history.push( gamipress_badge_builder_canvas.toJSON(["data"]) );
1331 gamipress_badge_builder_history_redo = [];
1332 }
1333
1334 /**
1335 * History reset
1336 *
1337 * @since 7.0.0
1338 */
1339 function gamipress_badge_builder_history_reset() {
1340 gamipress_badge_builder_history = [];
1341 gamipress_badge_builder_history_redo = [];
1342 gamipress_badge_builder_history_save();
1343 }
1344
1345 /**
1346 * Undo
1347 *
1348 * @since 7.0.0
1349 */
1350 function gamipress_badge_builder_undo() {
1351 if( ! gamipress_badge_builder_history.length > 0 ) return;
1352
1353 gamipress_badge_builder_history_applying = true;
1354
1355 var preferred_active_id = ( gamipress_badge_builder_active_obj && gamipress_badge_builder_active_obj.id ) ? gamipress_badge_builder_active_obj.id : null;
1356 var current = gamipress_badge_builder_history.pop();
1357 gamipress_badge_builder_history_redo.push( current );
1358
1359 const prev = gamipress_badge_builder_history[gamipress_badge_builder_history.length - 1];
1360 gamipress_badge_builder_history_apply( prev, preferred_active_id );
1361
1362 }
1363
1364 /**
1365 * Redo
1366 *
1367 * @since 7.0.0
1368 */
1369 function gamipress_badge_builder_redo() {
1370 if( ! gamipress_badge_builder_history_redo.length > 0 ) return;
1371
1372 gamipress_badge_builder_history_applying = true;
1373
1374 var preferred_active_id = ( gamipress_badge_builder_active_obj && gamipress_badge_builder_active_obj.id ) ? gamipress_badge_builder_active_obj.id : null;
1375 const next = gamipress_badge_builder_history_redo.pop();
1376 gamipress_badge_builder_history.push( next );
1377
1378 gamipress_badge_builder_history_apply( next, preferred_active_id );
1379
1380 }
1381
1382 /**
1383 * Apply history
1384 *
1385 * @since 7.0.0
1386 */
1387 function gamipress_badge_builder_history_apply( json, preferred_active_id ) {
1388 if( json === undefined ) return;
1389
1390 gamipress_badge_builder_history_applying = true;
1391 var finalized = false;
1392 var finalize_apply = function() {
1393 if ( finalized ) {
1394 return;
1395 }
1396
1397 finalized = true;
1398
1399 var list = ( typeof gamipress_badge_builder_canvas.getObjects === 'function' ) ? gamipress_badge_builder_canvas.getObjects() : [];
1400 var target = null;
1401
1402 if ( preferred_active_id ) {
1403 for ( var i = 0; i < list.length; i++ ) {
1404 if ( list[i] && String( list[i].id || '' ) === String( preferred_active_id ) ) {
1405 target = list[i];
1406 break;
1407 }
1408 }
1409 }
1410
1411 if ( ! target ) {
1412 var non_artboard = list.filter( function( entry ) {
1413 return entry && ! ( entry.data === 'artboard' || ( entry.data && entry.data.role === 'artboard' ) );
1414 } );
1415
1416 if ( non_artboard.length === 1 ) {
1417 target = non_artboard[0];
1418 }
1419 }
1420
1421 if ( target && typeof gamipress_badge_builder_canvas.setActiveObject === 'function' ) {
1422 gamipress_badge_builder_canvas.setActiveObject( target );
1423 if ( typeof target.setCoords === 'function' ) {
1424 target.setCoords();
1425 }
1426 } else if ( typeof gamipress_badge_builder_canvas.discardActiveObject === 'function' ) {
1427 gamipress_badge_builder_canvas.discardActiveObject();
1428 }
1429
1430 gamipress_badge_builder_canvas.renderAll();
1431 gamipress_badge_builder_update_selection();
1432 gamipress_badge_builder_history_applying = false;
1433 };
1434
1435 var loaded = gamipress_badge_builder_canvas.loadFromJSON( json, finalize_apply );
1436
1437 if ( loaded && typeof loaded.then === 'function' ) {
1438 loaded.then( finalize_apply ).catch( finalize_apply );
1439 }
1440
1441 setTimeout( function() {
1442 finalize_apply();
1443 }, 320 );
1444
1445 }
1446
1447
1448 /**
1449 * Keyboard shortcuts
1450 *
1451 * @since 7.0.0
1452 */
1453 document.addEventListener('keydown', e => {
1454 var obj = gamipress_badge_builder_active_obj;
1455 var has_cmd_mod = !! ( e.ctrlKey || e.metaKey );
1456 if ( ! obj ) return;
1457
1458 // Prevent to process it while editing an input
1459 if( [ 'INPUT', 'SELECT', 'TEXTAREA' ].includes( e.target.tagName ) ) return;
1460
1461 switch ( e.key ) {
1462 // Delete = Delete
1463 case 'Delete': e.preventDefault(); gamipress_badge_builder_process_tool( 'delete' );
1464 break;
1465 // + = Scale Up
1466 case '+': e.preventDefault(); gamipress_badge_builder_process_tool( 'scale-up' );
1467 break;
1468 // - = Scale Down
1469 case '-': e.preventDefault(); gamipress_badge_builder_process_tool( 'scale-down' );
1470 break;
1471 }
1472
1473 if( ! e.shiftKey && ! e.altKey && ! has_cmd_mod ) {
1474
1475 var move_step = 2;
1476
1477 switch ( e.key ) {
1478 // Arrows = Move
1479 case 'ArrowUp': e.preventDefault(); gamipress_badge_builder_move_object( obj, 0, -move_step );
1480 break;
1481 case 'ArrowDown': e.preventDefault(); gamipress_badge_builder_move_object( obj, 0, move_step );
1482 break;
1483 case 'ArrowLeft': e.preventDefault(); gamipress_badge_builder_move_object( obj, -move_step, 0 );
1484 break;
1485 case 'ArrowRight': e.preventDefault(); gamipress_badge_builder_move_object( obj, move_step, 0 );
1486 break;
1487 }
1488
1489 } else if( e.shiftKey ) {
1490 switch ( e.key ) {
1491 // Shift + Arrow Key = Align
1492 case 'ArrowUp': e.preventDefault(); gamipress_badge_builder_process_tool( 'align-vertical-top' );
1493 break;
1494 case 'ArrowDown': e.preventDefault(); gamipress_badge_builder_process_tool( 'align-vertical-bottom' );
1495 break;
1496 case 'ArrowLeft': e.preventDefault(); gamipress_badge_builder_process_tool( 'align-horizontal-left' );
1497 break;
1498 case 'ArrowRight': e.preventDefault(); gamipress_badge_builder_process_tool( 'align-horizontal-right' );
1499 break;
1500 // Shift + C = Center
1501 case 'C':
1502 case 'c':
1503 e.preventDefault();
1504 gamipress_badge_builder_process_tool( 'align-horizontal-center' );
1505 gamipress_badge_builder_process_tool( 'align-vertical-center' );
1506 break;
1507 // Shift + D = Duplicate
1508 case 'D':
1509 case 'd':
1510 e.preventDefault(); gamipress_badge_builder_process_tool( 'duplicate' );
1511 break;
1512 // Shift + F = Fit to canvas
1513 case 'F':
1514 case 'f':
1515 e.preventDefault(); gamipress_badge_builder_process_tool( 'fit' );
1516 break;
1517 }
1518 } else if( e.altKey ) {
1519 switch ( e.key ) {
1520 // Alt + Left or Right = Flip Horizontal
1521 case 'ArrowLeft': e.preventDefault(); gamipress_badge_builder_process_tool( 'flip-horizontal' );
1522 break;
1523 case 'ArrowRight': e.preventDefault(); gamipress_badge_builder_process_tool( 'flip-horizontal' );
1524 break;
1525 // Alt + Up or Down = Flip Vertical
1526 case 'ArrowUp': e.preventDefault(); gamipress_badge_builder_process_tool( 'flip-vertical' );
1527 break;
1528 case 'ArrowDown': e.preventDefault(); gamipress_badge_builder_process_tool( 'flip-vertical' );
1529 break;
1530 }
1531 } else if( has_cmd_mod ) {
1532 switch ( e.key ) {
1533 // Ctrl + Left or Right = Rotate
1534 case 'ArrowLeft': e.preventDefault(); gamipress_badge_builder_process_tool( 'rotate-left' );
1535 break;
1536 case 'ArrowRight': e.preventDefault(); gamipress_badge_builder_process_tool( 'rotate-right' );
1537 break;
1538 // Ctrl + Up or Down = Send to Front/Back
1539 case 'ArrowUp': e.preventDefault(); gamipress_badge_builder_process_tool( 'send-front' );
1540 break;
1541 case 'ArrowDown': e.preventDefault(); gamipress_badge_builder_process_tool( 'send-back' );
1542 break;
1543 }
1544 }
1545 });
1546
1547 /**
1548 * Keyboard shortcuts that not require an active object
1549 *
1550 * @since 7.0.0
1551 */
1552 document.addEventListener('keydown', e => {
1553
1554 var has_cmd_mod = !! ( e.ctrlKey || e.metaKey );
1555
1556 if( e.shiftKey && has_cmd_mod ) {
1557 switch ( e.key ) {
1558 // Shift + Ctrl + Z: Redo
1559 case 'Z':
1560 case 'z':
1561 e.preventDefault(); gamipress_badge_builder_process_tool( 'redo' );
1562 break;
1563 }
1564 } else if( has_cmd_mod ) {
1565 switch ( e.key ) {
1566 // Ctrl + Z: Undo
1567 case 'Z':
1568 case 'z':
1569 e.preventDefault(); gamipress_badge_builder_process_tool( 'undo' );
1570 break;
1571 }
1572 }
1573
1574 });
1575