PluginProbe ʕ •ᴥ•ʔ
Strong Testimonials / 3.3.2
Strong Testimonials v3.3.2
3.3.2 3.3.1 trunk 1.0.1 2.30.9 2.31.10 2.32 2.32.1 2.32.2 2.32.3 2.32.4 2.33 2.34 2.35 2.36 2.37 2.38 2.38.1 2.39 2.39.1 2.39.2 2.39.3 2.40.0 2.40.1 2.40.2 2.40.3 2.40.4 2.40.5 2.40.6 2.40.7 2.41.0 2.41.1 2.50.0 2.50.1 2.50.2 2.50.3 2.50.4 2.51.0 2.51.1 2.51.2 2.51.3 2.51.4 2.51.5 2.51.6 2.51.7 2.51.8 2.51.9 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0
strong-testimonials / admin / js / views.js
strong-testimonials / admin / js Last commit date
lib 1 year ago admin-fields.js 1 year ago admin-form.js 1 year ago admin-global.js 1 year ago admin-order.js 1 year ago custom-spinner.js 1 year ago help.js 1 year ago rating-edit.js 1 year ago selectize.js 1 year ago st-uninstall.js 1 year ago strong-testimonials-elementor-editor.js 1 year ago view-category-filter.js 1 year ago views.js 1 month ago
views.js
1474 lines
1 /**
2 * Strong Testimonials - Views
3 */
4
5 // Function to get the Max value in Array
6 Array.max = function (array) {
7 return Math.max.apply(Math, array);
8 };
9
10 (function ($) {
11 $.fn.showInlineBlock = function () {
12 return this.css('display', 'inline-block');
13 };
14 })(jQuery);
15
16 /**
17 * jQuery alterClass plugin
18 *
19 * Remove element classes with wildcard matching. Optionally add classes:
20 * $( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
21 *
22 * https://gist.github.com/peteboere/1517285
23 *
24 * Copyright (c) 2011 Pete Boere (the-echoplex.net)
25 * Free under terms of the MIT license: http://www.opensource.org/licenses/mit-license.php
26 */
27 (function ($) {
28 $.fn.alterClass = function (removals, additions) {
29
30 var self = this;
31
32 if (removals.indexOf('*') === -1) {
33 // Use native jQuery methods if there is no wildcard matching
34 self.removeClass(removals);
35 return !additions ? self : self.addClass(additions);
36 }
37
38 var patt = new RegExp('\\s' +
39 removals.replace(/\*/g, '[A-Za-z0-9-_]+').split(' ').join('\\s|\\s') +
40 '\\s', 'g');
41
42 self.each(function (i, it) {
43 var cn = ' ' + it.className + ' ';
44 while (patt.test(cn)) {
45 cn = cn.replace(patt, ' ');
46 }
47 it.className = cn.trim();
48 });
49
50 return !additions ? self : self.addClass(additions);
51 };
52 })(jQuery);
53
54 /**
55 * Special handling after toggling certain options.
56 */
57 (function ($) {
58 // custom handling
59 $.fn.afterToggle = function () {
60
61 // Category selector
62 var $categoryDivs = $('.view-category-list-panel');
63 // Set initial width to compensate for narrowed box due to checkbox being hidden first
64 // and to prevent horizontal jumpiness as filter is applied.
65 if (!$categoryDivs.hasClass('fixed')) {
66 $categoryDivs.width($categoryDivs.outerWidth(true)).addClass('fixed');
67 }
68
69 // Slideshow controls
70 var $controls = $('#view-slideshow_controls_type');
71 var $pager = $('#view-slideshow_pager_type');
72 var controlsValue = $controls.val();
73 var pagerValue = $pager.val();
74
75 if ('full' === controlsValue) {
76 $('.then_has-pager').fadeOut();
77 $pager.val('none');
78 $('option[value="text"]', '#view-slideshow_controls_style').prop('disabled', false);
79 }
80 else if ('sides' === controlsValue) {
81 $('.then_has-pager').fadeIn();
82 var $style = $('#view-slideshow_controls_style');
83 if ('text' === $style.val()) {
84 $('option:first', $style).prop('selected', true);
85 }
86 $('option[value="text"]', $style).prop('disabled', true);
87 }
88 else {
89 $('.then_has-pager').fadeIn();
90 $('option[value="text"]', '#view-slideshow_controls_style').prop('disabled', false);
91 }
92
93 if ('none' === pagerValue && ('none' === controlsValue || 'sides' === controlsValue)) {
94 $('.then_has-position').fadeOut();
95 }
96 else {
97 $('.then_has-position').fadeIn();
98 }
99
100 // If no navigation, must start automatically.
101 if ('none' === pagerValue && 'none' === controlsValue) {
102 $('#view-auto_start').val('1').prop('checked', true);
103 }
104
105 return this;
106 };
107 }(jQuery));
108
109 /**
110 * Remove 'result' query argument.
111 */
112 removeResultArg = function () {
113 var urlParams = new URLSearchParams(window.location.search);
114 if (urlParams.has('result')) {
115 urlParams.delete('result');
116 var newURL = window.location.pathname;
117 if (urlParams.toString()) {
118 newURL = newURL + '?' + urlParams.toString();
119 }
120 window.history.replaceState({}, document.title, newURL);
121 }
122 };
123
124 /**
125 * Initial actions on document.ready
126 */
127 jQuery(document).ready(function ($) {
128
129 // Masonry in the Layout section
130 $('.view-layout-masonry .example-container')
131 .find('.box')
132 .width(jQuery('.grid-sizer').width())
133 .end()
134 .masonry();
135
136 // Category select width
137 $.fn.afterToggle();
138
139 removeResultArg();
140 });
141
142 (function ($) {
143 'use strict';
144
145 // the shortcode code
146 $('#view-shortcode').on('focus', function () {
147 $(this).trigger('select');
148 });
149
150 $('.expand-cats').on('click', function () {
151 // TODO i18n
152 var $categoryDivs = $('.view-category-list-panel');
153 if ($categoryDivs.hasClass('tall-panel')) {
154 $categoryDivs.addClass('short-panel').removeClass('tall-panel');
155 $(this).val('expand list');
156 } else {
157 $categoryDivs.removeClass('short-panel').addClass('tall-panel');
158 $(this).val('collapse list');
159 }
160 $(this).trigger('blur');
161 });
162
163 // Masonry example
164 var masonryExample = $('.view-layout-masonry .example-container');
165 masonryExample.find('.box').width($('.grid-sizer').width()).end().masonry({
166 columnWidth: '.grid-sizer',
167 gutter: 10,
168 itemSelector: '.box',
169 percentPosition: true
170 });
171
172 // Column count selector
173 var columnCount = $('#view-column-count');
174 var columnCountChange = function () {
175 var col = columnCount.val();
176 $('.example-container').alterClass('col-*', 'col-' + col);
177 masonryExample.find('.box').width($('.grid-sizer').width()).end().masonry();
178 };
179
180 columnCountChange();
181 columnCount.on('change', columnCountChange);
182 $('input[name=\'view[data][layout]\']').on('change', function () {
183 if ('masonry' === $(this).val()) {
184 setTimeout(columnCountChange, 200);
185 }
186 });
187
188 // Color pickers
189 var myOptions = {
190 // you can declare a default color here, or in the data-default-color attribute on the input
191 //defaultColor: '#FFFFFF',
192 // a callback to fire whenever the color changes to a valid color
193 change: function (event, ui) {
194 setTimeout(function () {
195 updateBackgroundPreview();
196 }, 250);
197 },
198 // a callback to fire when the input is emptied or an invalid color
199 clear: function (event, ui) {
200 setTimeout(function () {
201 updateBackgroundPreview();
202 }, 250);
203 },
204 // hide the color picker controls on load
205 //hide: true,
206 // show a group of common colors beneath the square
207 // or, supply an array of colors to customize further
208 palettes: true
209 };
210 $('.wp-color-picker-field').wpColorPicker(myOptions);
211
212 /**
213 * Restore defaults
214 */
215 // TODO i18n
216 $('#restore-defaults').on('click', function () {
217 return confirm('Restore the default settings?');
218 });
219
220 /**
221 * -----------------
222 * Dependent options
223 * -----------------
224 */
225
226 /**
227 * Special handling
228 * TODO Use a technique similar to if-then for adding/removing classes
229 */
230
231 /*
232 var viewContent = $('#view-content');
233 var viewContentChange = function () {
234 var thisValue = viewContent.val();
235 viewContent.closest('td').find('.highlight2').each(function (index, el) {
236 if ('excerpt' === thisValue) {
237 $(el).addClass('highlight-on');
238 } else {
239 $(el).removeClass('highlight-on');
240 }
241 });
242 };
243 viewContentChange();
244 viewContent.on('change', viewContentChange);
245 */
246
247 /**
248 * Update option for [adding read-more to excerpts] based on setting
249 * for [read-more type] (link to post or expand in place).
250 */
251 var viewHybrid = $('#view-more_post_in_place');
252
253 var viewHybridChange = function () {
254
255 var thisValue = viewHybrid.val();
256
257 // var viewMoreFullPost = $('#view-more_full_post');
258 // if ('1' === thisValue) {
259 // viewMoreFullPost.prop('disabled', true).find('option[value=\'1\']').prop('selected', true);
260 // } else {
261 // viewMoreFullPost.removeProp('disabled');
262 // }
263
264 var viewDefaultMore = $('#view-use_default_more');
265 if ('1' === thisValue) {
266 viewDefaultMore.prop('disabled', true).find('option[value=\'0\']').prop('selected', true);
267 } else {
268 viewDefaultMore.removeProp('disabled');
269 }
270 viewDefaultMore.trigger( 'change' );
271
272 };
273
274 viewHybridChange();
275
276 viewHybrid.on('change', viewHybridChange);
277
278 /**
279 * Plugin: Show/Hide parts based on current Mode
280 */
281 $.fn.updateScreen = function (mode, speed) {
282 speed = (speed !== undefined) ? speed : 400;
283 if (!mode)
284 return;
285
286 var modeDesc = $('.mode-description');
287 modeDesc.html('');
288 if (speed === 0) {
289 $('.then_' + mode).show();
290 $('.then_not_' + mode).hide();
291 } else {
292 $('.then_' + mode).fadeIn(speed);
293 $('.then_not_' + mode).fadeOut(speed);
294 }
295
296 /**
297 * Special handling
298 */
299 switch (mode) {
300 case 'form':
301 // hack
302 setTimeout(formTemplateDescriptions, 500);
303 break;
304 case 'slideshow':
305 break;
306 case 'display':
307 // update single/multiple selector ONLY
308 $.fn.selectPerOption($('#view-single_or_multiple'));
309 break;
310 case 'single_template':
311 break;
312 default:
313 }
314
315 /**
316 * Update description
317 *
318 * @since 2.22.0
319 */
320 var data = {
321 'action': 'wpmtst_view_get_mode_description',
322 'mode': mode,
323 'nonce' : wpmtst_admin_views_script_nonce
324 };
325 $.post(ajaxurl, data, function (response) {
326 if (response) {
327 modeDesc.html(response);
328 }
329 });
330
331 return this;
332 };
333
334 /**
335 * Plugin: Toggle dependent options for checkboxes.
336 *
337 * Show/hide other option groups when checkbox is "on".
338 * Single value
339 */
340 $.fn.toggleOption = function (el, speed) {
341 speed = (speed !== undefined) ? speed : 400;
342 var option = $(el).attr('id').split('-').pop();
343 var checked = $(el).prop('checked');
344 var deps = '.then_' + option;
345 var indeps = '.then_not_' + option;
346 if (checked) {
347 if (speed === 0) { $(deps).show(); $(indeps).hide(); }
348 else { $(deps).fadeIn(speed); $(indeps).fadeOut(speed); }
349 }
350 else {
351 if (speed === 0) { $(deps).hide(); $(indeps).show(); }
352 else { $(deps).fadeOut(speed); $(indeps).fadeIn(speed); }
353 }
354 return this;
355 };
356
357 /**
358 * Plugin: Toggle dependent options for checkboxes.
359 *
360 * Show/hide other option groups when checkbox is "on".
361 * Multiple values
362 *
363 * @since 1.20.0
364 */
365 $.fn.selectPerOption = function (el, speed) {
366 speed = speed || 400;
367 var fast = 0;
368 //var option = $(el).attr("id").split("-").pop();
369 var currentValue = $(el).val();
370 var deps = '.then_' + currentValue;
371 var depsFast = deps + '.fast';
372 var indeps = '.then_not_' + currentValue;
373 var indepsFast = indeps + '.fast';
374 if (currentValue) {
375
376 $(depsFast).not('.then_not_' + currentMode).fadeIn(fast);
377 $(deps).not('.fast, .then_not_' + currentMode).fadeIn(speed);
378
379 $(indepsFast).fadeOut(fast);
380 $(indeps).not('.fast').fadeOut(speed);
381
382 } else {
383
384 $(indepsFast).fadeIn(fast);
385 $(indeps).not('.fast').fadeIn(speed);
386
387 $(depsFast).fadeOut(fast);
388 $(deps).not('.fast').fadeOut(speed);
389
390 }
391 return this;
392 };
393
394 /**
395 * Plugin: Toggle dependent options for selects.
396 *
397 * Show/hide other option groups when one and only one *specific* option is selected.
398 * class="if select"
399 * ~TRIP~
400 */
401 $.fn.selectOption = function (el, speed) {
402 speed = speed || 400;
403 var currentValue = $(el).val();
404 var tripValue = $(el).find('.trip').val();
405 var option = $(el).attr('id').split('-').pop();
406 var deps = '.then_' + option;
407 if (currentValue === tripValue) {
408 $(deps).fadeIn(speed);
409 }
410 else {
411 $(deps).fadeOut(speed);
412 }
413 return this;
414 };
415
416 /**
417 * Plugin: Toggle dependent options for selects.
418 *
419 * Show/hide other option groups when one and only one *specific* option is selected.
420 * class="if selectnot"
421 * ~TRIP~
422 */
423 $.fn.selectNotOption = function (el, speed) {
424 speed = speed || 400;
425 var currentValue = $(el).val();
426 var tripValue = $(el).find('.trip').val();
427 var option = $(el).attr('id').split('-').pop();
428 var deps = '.then_' + option;
429 if (currentValue === tripValue) {
430 $(deps).fadeOut(speed);
431 }
432 else {
433 $(deps).fadeIn(speed);
434 }
435 return this;
436 };
437
438 /**
439 * Plugin: Toggle dependent options for selects.
440 *
441 * Show/hide other option groups when any *non-empty (initial)* option is selected.
442 * class="if selectany"
443 */
444 $.fn.selectAnyOption = function (el, speed) {
445 speed = speed || 400;
446 var currentValue = $(el).val();
447 var option = $(el).attr('id').split('-').pop();
448 var deps = '.then_' + option + '.then_' + currentValue;
449 var indeps = '.then_not_' + option + '.then_' + currentValue;
450 if (currentValue) {
451 $(deps).fadeIn(speed);
452 $(indeps).fadeOut(speed);
453 }
454 else {
455 $(deps).fadeOut(speed);
456 $(indeps).fadeIn(speed);
457 }
458 return this;
459 };
460
461 /**
462 * Plugin: Toggle dependent options.
463 *
464 * Show/hide other option groups depending on value (1:1 relationshsip).
465 * Using both option and value, which is different method than other functions.
466 * class="if selectgroup"
467 *
468 * @since 1.20.0
469 */
470 $.fn.selectGroupOption = function (el) {
471 var speed = 400,
472 fastOut = 0,
473 fastIn = 100;
474 var option = $(el).attr('id').split('-').pop();
475 var currentValue = $(el).val();
476 var deps = '.then_' + option + '.then_' + currentValue;
477 var depsFast = deps + '.fast';
478 var indeps = '.then_' + option + '.then_not_' + currentValue;
479 var indepsFast = indeps + '.fast';
480 if (currentValue) {
481 $(depsFast).fadeIn(fastIn);
482 $(deps).not('.fast').fadeIn(speed);
483 $(indepsFast).fadeOut(fastOut);
484 $(indeps).not('.fast').fadeOut(speed);
485 }
486 else {
487 $(indepsFast).fadeIn(fastIn);
488 $(indeps).not('.fast').fadeIn(speed);
489 $(depsFast).fadeOut(fastOut);
490 $(deps).not('.fast').fadeOut(speed);
491 }
492 return this;
493 };
494
495 /**
496 * Initial state
497 */
498 var $mode = $('#view-mode');
499 var currentMode = $mode.find('input:checked').val();
500 $mode.find('input:checked').closest('label').addClass('checked');
501 $.fn.updateScreen(currentMode, 0);
502
503 /**
504 * Mode listener
505 */
506 $mode.find('input').on('change', function () {
507 currentMode = $(this).val();
508 $mode.find('input').not(':checked').closest('label').removeClass('checked');
509 $mode.find('input:checked').closest('label').addClass('checked');
510 $.fn.updateScreen(currentMode);
511
512 // Force default template since we have more than one group of templates.
513 $('input[type=radio][name=\'view[data][template]\'][value=\'default\']').prop('checked', true);
514 templateRadios.trigger( 'change' );
515 $('input[type=radio][name=\'view[data][form-template]\'][value=\'default-form\']').prop('checked', true);
516 // formTemplateRadios.trigger( 'change' );
517 layoutRadios.trigger( 'change' );
518 backgroundRadios.trigger( 'change' );
519 });
520
521 /**
522 * Initial state & Change listeners
523 */
524 function initialize () {
525 $('.if.toggle').each(function (index, el) {
526 $.fn.toggleOption(this, 0);
527 $(this).on('change', function () {
528 $.fn.toggleOption(this);
529 });
530 });
531
532 $('.if.select').each(function (index, el) {
533 $.fn.selectOption(this);
534 $(this).on('change', function () {
535 $.fn.selectOption(this);
536 });
537 });
538
539 $('.if.selectnot').each(function (index, el) {
540 $.fn.selectNotOption(this);
541 $(this).on('change', function () {
542 $.fn.selectNotOption(this).afterToggle();
543 });
544 });
545
546 $('.if.selectany').each(function (index, el) {
547 $.fn.selectAnyOption(this);
548 $(this).on('change', function () {
549 $.fn.selectAnyOption(this);
550 });
551 });
552
553 $('.if.selectper').each(function (index, el) {
554 $.fn.selectPerOption(this);
555 $(this).on('change', function () {
556 $.fn.selectPerOption(this).afterToggle();
557 });
558 });
559
560 $('.if.selectgroup').each(function (index, el) {
561 $.fn.selectGroupOption(this);
562 $(this).on('change', function () {
563 $.fn.selectGroupOption(this);
564 });
565 });
566
567 $('.field-name select').each(function () {
568 var $el = $(this);
569 var $elParent = $el.closest('.field3');
570 var fieldValue = $el.val();
571 var fieldType = $el.find('option:selected').data('type');
572 var key = $elParent.data('key');
573 var typeSelectParent = $elParent.find('td.field-type');
574 var typeSelect = typeSelectParent.find('select');
575
576 if (fieldValue === 'post_date') {
577 typeSelect.prop('disabled', true);
578 typeSelect.parent().append('<input type="hidden" class="save-type" name="view[data][client_section][' + key + '][save-type]" value="date">');
579 }
580 else if (fieldValue === 'submit_date') {
581 typeSelect.prop('disabled', true);
582 typeSelect.parent().append('<input type="hidden" class="save-type" name="view[data][client_section][' + key + '][save-type]" value="date">');
583 }
584 else if (fieldValue === 'category') {
585 typeSelect.prop('disabled', true);
586 typeSelect.parent().append('<input type="hidden" class="save-type" name="view[data][client_section][' + key + '][save-type]" value="category">');
587 }
588 else if (fieldType === 'rating') { /* --- type! --- */
589 typeSelect.prop('disabled', true);
590 typeSelectParent.append('<input type="hidden" class="save-type" name="view[data][client_section][' + key + '][save-type]" value="rating">');
591 }
592 else {
593 $(typeSelect).prop('disabled', false);
594 $(typeSelect).parent().find('input.save-type').remove();
595 }
596 });
597
598 }
599
600 initialize();
601
602 /**
603 * Link field text change listener
604 */
605 function textChangeListener () {
606 $('select[id^="view-fieldtext"]').on('change', function () {
607 if ($(this).val() === 'custom') {
608 var key = $(this).closest('.field3').data('key');
609 $('#view-fieldtext' + key + '-custom').trigger('focus');
610 }
611 });
612 }
613
614 textChangeListener();
615
616 /**
617 * Template change listener
618 */
619 // TODO Use ID
620 var templateRadios = $('.template-list input[type=radio]');
621
622 function templateDescriptions () {
623 var templateRadioOff, templateRadioOn, template;
624
625 templateRadioOff = templateRadios.filter(':not(:checked)');
626 templateRadioOff.closest('li').removeClass('current-selection').find('.template-description').children(':not(:first-child)').hide();
627
628 templateRadioOn = templateRadios.filter(':checked');
629 template = templateRadioOn.val();
630 templateRadioOn.closest('li').addClass('current-selection').find('.template-description').children(':not(:first-child)').show();
631
632 // Check for forced options
633 if (template) {
634 $('input.forced').removeProp('disabled').removeClass('forced');
635 var data = {
636 'action': 'wpmtst_force_check',
637 'template': template,
638 'nonce' : wpmtst_admin_views_script_nonce
639 };
640 $.post(ajaxurl, data, function (response) {
641 if (response.success) {
642 var arrayLength, $el, inputName;
643 arrayLength = response.data.length;
644 for (var i = 0; i < arrayLength; i++) {
645 $el = $('#' + response.data[i]);
646 $el.prop('checked', true).trigger( 'change' );
647 inputName = $el.prop('name');
648 $('input[name=\'' + inputName + '\']').prop('disabled', true).addClass('forced');
649 }
650 }
651 });
652
653 // Special handling
654 if ('unstyled' === template) {
655 $('input[name=\'view[data][background][type]\']').prop('disabled', true);
656 $('input[name=\'view[data][font-color][type]\']').prop('disabled', true);
657 $('input[name=\'wpmtst_style_options[background][type]\']').prop('disabled', true);
658 $('input[name=\'wpmtst_style_options[font-color][type]\']').prop('disabled', true);
659 } else {
660 $('input[name=\'view[data][background][type]\']').prop('disabled', false);
661 $('input[name=\'view[data][font-color][type]\']').prop('disabled', false);
662 $('input[name=\'wpmtst_style_options[background][type]\']').prop('disabled', false);
663 $('input[name=\'wpmtst_style_options[font-color][type]\']').prop('disabled', false);
664 }
665
666 // Special handling for Lucid add-on until I can incorporate a template group config file
667 if ('lucid' === template.substr(0, 5) || 'single_template' === currentMode) {
668 $('.then_lucid').show();
669 } else {
670 $('.then_lucid').hide();
671 }
672 }
673 }
674
675 templateDescriptions();
676
677 templateRadios.on('change', templateDescriptions);
678
679 /**
680 * Form template change listener
681 */
682 var formTemplateRadios = $('input[type=radio][name=\'view[data][form-template]\']');
683
684 function formTemplateDescriptions () {
685 var formTemplateRadioOff, formTemplateRadioOn, formTemplate;
686
687 formTemplateRadioOff = formTemplateRadios.filter(':not(:checked)');
688 formTemplateRadioOff.closest('li').removeClass('current-selection').find('.options').hide();
689
690 formTemplateRadioOn = formTemplateRadios.filter(':checked');
691 formTemplate = formTemplateRadioOn.val();
692 formTemplateRadioOn.closest('li').addClass('current-selection').find('.options').show();
693 }
694
695 formTemplateDescriptions();
696
697 formTemplateRadios.on('change', formTemplateDescriptions);
698
699 /**
700 * Layout change listener
701 */
702 // TODO Use ID instead.
703 var layoutRadios = $('input[type=radio][name=\'view[data][layout]\']');
704
705 function layoutDescriptions () {
706 var layoutRadioOff, layoutRadioOn, layout;
707
708 layoutRadioOff = layoutRadios.filter(':not(:checked)');
709 layoutRadioOff.closest('li').removeClass('current-selection').find('.options').hide();
710
711 layoutRadioOn = layoutRadios.filter(':checked');
712 layout = layoutRadioOn.attr('id');
713 layoutRadioOn.closest('li').addClass('current-selection').find('.options').show();
714
715 $('.layout-description, .layout-example').hide();
716 $('.' + layout).show();
717
718 // Special handling
719
720 if ('view-layout-normal' === layout)
721 $('#column-count-wrapper').fadeOut();
722 else
723 $('#column-count-wrapper').fadeIn();
724
725 if ('view-layout-masonry' === layout) {
726 if ($('#view-pagination').is(':checked')) {
727 alert('Masonry is incompatible with pagination. Please disable pagination first.');
728 $('#view-layout-normal').prop('checked', true).trigger( 'change' );
729 }
730 }
731 }
732
733 layoutDescriptions();
734
735 layoutRadios.on('change', layoutDescriptions);
736
737 /**
738 * Pagination change listener
739 */
740 function paginationChangeListener () {
741 // Pagination is incompatible with Masonry
742 // TODO DRY
743 if ($(this).is(':checked') && 'masonry' === layoutRadios.filter(':checked').val()) {
744 alert('Pagination is incompatible with Masonry. Please select another layout first.');
745 $(this).prop('checked', false).trigger( 'change' );
746 }
747 }
748
749 $('#view-pagination').on('change', paginationChangeListener);
750
751 /**
752 * Disallow standard pagination with query limit.
753 */
754 var $viewQuantity = $('#view-all'),
755 $viewPaginationType = $('#view-pagination_type');
756
757 function paginationTypeChangeListener () {
758 if (this.value === 'standard' && $viewQuantity.val() === '0' && $('#view-pagination').is(':checked')) {
759 alert('Standard pagination is incompatible with Count.');
760 $(this).val('simple').trigger( 'change' );
761 }
762 }
763
764 function quantityChangeListener () {
765 if (this.value === '0' && $viewPaginationType.val() === 'standard' && $('#view-pagination').is(':checked')) {
766 alert('Count is incompatible with Standard pagination.');
767 $(this).val(1).trigger( 'change' );
768 }
769 }
770
771 $viewPaginationType.on('change', paginationTypeChangeListener);
772 $viewQuantity.on('change', quantityChangeListener);
773
774 /**
775 * ----------------------------------------------------------------------
776 * Background and Font colors
777 * ----------------------------------------------------------------------
778 */
779 function updateBackgroundPreview () {
780 var c1,
781 c2,
782 c3,
783 background = backgroundRadios.filter(':checked').val(),
784 fontColor = fontColorRadios.filter(':checked').val();
785
786 if ('custom' === fontColor) {
787 c3 = document.getElementById('fc-color').value;
788 backgroundPreview.css('color', c3);
789 } else {
790 backgroundPreview.css('color', 'inherit');
791 }
792 switch (background) {
793 case '':
794 backgroundPreview.css('background', 'transparent');
795 break;
796 case 'single':
797 c1 = document.getElementById('bg-color').value;
798 backgroundPreview.css('background', c1);
799 break;
800 case 'gradient':
801 c1 = document.getElementById('bg-gradient1').value;
802 c2 = document.getElementById('bg-gradient2').value;
803 backgroundPreview.css(constructGradientCSS(c1, c2));
804 break;
805 case 'preset':
806 backgroundPreset(backgroundPresetSelector.val());
807 break;
808 default:
809 }
810
811 }
812
813 var backgroundRadios = $('input[type=radio][name=\'view[data][background][type]\'], input[type=radio][name=\'wpmtst_style_options[background][type]\']'),
814 backgroundPreview = $('#background-preview'),
815 backgroundPresetSelector = $('#view-background-preset');
816
817 /**
818 * Font-color change listener
819 */
820 // TODO Use ID instead.
821 var fontColorRadios = $('input[type=radio][name=\'view[data][font-color][type]\'], input[type=radio][name=\'wpmtst_style_options[font-color][type]\']');
822
823 function fontColorDescriptions () {
824 var fontColorRadioOff, fontColorRadioOn, fontColorID;
825
826 fontColorRadioOff = fontColorRadios.filter(':not(:checked)');
827 fontColorRadioOff.closest('li').removeClass('current-selection');
828
829 fontColorRadioOn = fontColorRadios.filter(':checked');
830 fontColorID = fontColorRadioOn.filter(':checked').attr('id');
831 fontColorRadioOn.closest('li').addClass('current-selection');
832
833 $('#view-font-color-info')
834 .find('.font-color-description:visible')
835 .hide()
836 .end()
837 .find('.' + fontColorID)
838 .show();
839
840 updateBackgroundPreview();
841 }
842
843 fontColorDescriptions();
844
845 fontColorRadios.on('change', fontColorDescriptions);
846
847 /**
848 * Background change listener
849 */
850 function backgroundDescriptions () {
851 var backgroundRadioOff, backgroundRadioOn, backgroundID;
852
853 backgroundRadioOff = backgroundRadios.filter(':not(:checked)');
854 backgroundRadioOff.closest('li').removeClass('current-selection').find('.options').hide();
855
856 backgroundRadioOn = backgroundRadios.filter(':checked');
857 backgroundID = backgroundRadioOn.filter(':checked').attr('id');
858 backgroundRadioOn.closest('li').addClass('current-selection').find('.options').show();
859
860 $('#view-background-info')
861 .find('.background-description:visible')
862 .hide()
863 .end()
864 .find('.' + backgroundID)
865 .show();
866
867 updateBackgroundPreview();
868 }
869
870 backgroundDescriptions();
871
872 backgroundRadios.on('change', backgroundDescriptions);
873
874 backgroundPresetSelector.on('change', function () {
875 backgroundPreset($(this).val());
876 });
877
878 function backgroundPreset (preset) {
879 if (!preset) {
880 backgroundPreview.css('background', 'transparent');
881 return;
882 }
883
884 var data = {
885 'action': 'wpmtst_get_background_preset_colors',
886 'key': preset,
887 'nonce' : wpmtst_admin_views_script_nonce
888 };
889 $.post(ajaxurl, data, function (response) {
890 var presetObj = JSON.parse(response);
891 if (presetObj.color && presetObj.color2) {
892 backgroundPreview.css(constructGradientCSS(presetObj.color, presetObj.color2));
893 }
894 else if (presetObj.color) {
895 backgroundPreview.css('background', presetObj.color);
896 }
897 else {
898 backgroundPreview.css('background', 'transparent');
899 }
900 });
901 }
902
903 function constructGradientCSS (c1, c2) {
904 return {
905 'background': 'linear-gradient(to bottom, ' + c1 + ' 0%, ' + c2 + ' 100%)'
906 };
907 }
908
909 //$.fn.updateScreen(currentMode);
910
911 /**
912 * -------------
913 * Client fields
914 * -------------
915 */
916
917 /**
918 * Make client fields sortable
919 */
920
921 var customFieldList = $('#custom-field-list2');
922
923 // Prevent single click on handle from opening accordion
924 customFieldList.on('click', 'span.handle', function (e) {
925 e.stopImmediatePropagation();
926 e.preventDefault();
927 });
928
929 // customFieldList.find(".field-properties").hide();
930
931 customFieldList.sortable({
932 placeholder: 'sortable-placeholder',
933 // forcePlaceholderSize: true,
934 handle: '.handle',
935 cursor: 'move',
936 helper: 'clone',
937 start: function (e, ui) {
938 ui.placeholder.height(ui.item.height());
939 }
940 });
941 //}).disableSelection(); // <-- this breaks Firefox
942
943 /**
944 * Add client field
945 */
946 $('#add-field').on('click', function (e) {
947 var keys = $('.field3').map(function () {
948 return $(this).data('key');
949 }).get();
950 var nextKey = Array.max(keys) + 1;
951 var data = {
952 'action': 'wpmtst_view_add_field',
953 'key': nextKey,
954 'source': $(this).attr('source'),
955 'nonce' : wpmtst_admin_views_script_nonce
956 };
957 $.post(ajaxurl, data, function (response) {
958 $.when(customFieldList.append(response)).then(function () {
959 var $newField = customFieldList.find('#field-' + nextKey);
960 $newField
961 .find('div.link').trigger('click').end()
962 .find('.field-dep').hide().end()
963 .find('.first-field').trigger('focus');
964 });
965 });
966 });
967 /**
968 * Field type change listener
969 */
970 customFieldList.on('change', '.field-type select', function () {
971 var $el = $(this);
972 var $elParent = $el.closest('.field3');
973 var fieldType = $el.val();
974 var fieldName = $elParent.find('.field-name').find('select').val();
975 // var key = $elParent.attr("id").split('-').slice(-1)[0];
976 var key = $elParent.data('key');
977 var data;
978
979 switch (fieldType) {
980 case 'link2':
981 case 'link':
982 // if changing to [link], add link fields
983 data = {
984 'action': 'wpmtst_view_add_field_link',
985 'fieldName': fieldName,
986 'fieldType': fieldType,
987 'key': key,
988 'source': $('#add-field').attr('source'),
989 'nonce' : wpmtst_admin_views_script_nonce
990 };
991 $.post(ajaxurl, data, function (response) {
992 // insert into placeholder div
993 $elParent.find('.field-property-box').html(response);
994
995 // Trigger conditional select
996 var $newFieldSelect = $elParent.find('.if.selectgroup');
997 $.fn.selectGroupOption($newFieldSelect);
998 $newFieldSelect.on('change', function () {
999 $.fn.selectGroupOption($newFieldSelect);
1000 });
1001 textChangeListener();
1002 // Get field name --> Get field label --> Populate link_text label
1003 var fieldName = $elParent.find('.field-name').find('select').val();
1004 var data2 = {
1005 'action': 'wpmtst_view_get_label',
1006 'name': fieldName,
1007 'nonce' : wpmtst_admin_views_script_nonce
1008 };
1009 $.post(ajaxurl, data2, function (response) {
1010 // var key = $elParent.attr("id").split('-').slice(-1)[0];
1011 $('#view-fieldtext' + key + '-label').val(response);
1012 });
1013
1014 });
1015 break;
1016
1017 case 'date':
1018 // if changing to [date], add date fields
1019 data = {
1020 'action': 'wpmtst_view_add_field_date',
1021 'key': key,
1022 'source': $('#add-field').attr('source'),
1023 'nonce' : wpmtst_admin_views_script_nonce
1024 };
1025 $.post(ajaxurl, data, function (response) {
1026 // insert into placeholder div
1027 $elParent.find('.field-property-box').html(response);
1028 });
1029 break;
1030
1031 case 'checkbox':
1032 // if changing to [checkbox_value]
1033 data = {
1034 'action': 'wpmtst_view_add_field_checkbox',
1035 'fieldName': fieldName,
1036 'fieldType': fieldType,
1037 'key': key,
1038 'source': $('#add-field').attr('source'),
1039 'nonce' : wpmtst_admin_views_script_nonce
1040 };
1041 $.post(ajaxurl, data, function (response) {
1042 // insert into placeholder div
1043 $elParent.find('.field-property-box').html(response);
1044 });
1045 break;
1046
1047 case 'category':
1048 data = {
1049 'action' : 'wpmtst_view_add_field_category_type_select',
1050 'fieldName': fieldName,
1051 'fieldType': fieldType,
1052 'key' : key,
1053 'source' : $('#add-field').attr('source'),
1054 'nonce' : wpmtst_admin_views_script_nonce
1055 };
1056 $.post(ajaxurl, data, function (response) {
1057 // insert into placeholder div
1058 $elParent.find('.field-property-box').html(response);
1059 });
1060 break;
1061
1062 default:
1063 $elParent.find('.field-property-box').html('');
1064 }
1065 });
1066
1067 /**
1068 * Field name change listener.
1069 */
1070 customFieldList.on('change', '.field-name select', function () {
1071 var $el = $(this);
1072 var $elParent = $el.closest('.field3');
1073 var fieldType = $el.find('option:selected').data('type');
1074 var fieldValue = $el.val();
1075 var key = $elParent.data('key');
1076 var typeSelectParent = $elParent.find('.field-type');
1077 var typeSelect = typeSelectParent.find('select');
1078 var source = $('#add-field').attr('source');
1079 var data;
1080
1081 $elParent.not('.open').addClass('open').find('.field-properties').addClass('open').slideDown();
1082
1083 if ('' === fieldValue) {
1084 $elParent.find('.field-description').html('');
1085 // Hide dependent inputs if nothing has been selected
1086 $elParent.find('.field-dep').hide();
1087 }
1088 else {
1089 // Update field label
1090 data = {
1091 'action': 'wpmtst_view_get_label',
1092 'name': fieldValue,
1093 'key': key,
1094 'nonce' : wpmtst_admin_views_script_nonce
1095 };
1096 $.post(ajaxurl, data, function (response) {
1097 if (response) {
1098 $elParent.find('.field-description').html(response);
1099
1100 //trigger custom event
1101 var event = document.createEvent('Event');
1102 event.initEvent('wpmtst_custom_field_changed', true, true);
1103 document.dispatchEvent(event);
1104 }
1105 });
1106
1107 // Show dependent inputs
1108 $elParent.find('.field-dep').show();
1109 }
1110 switch (fieldValue) {
1111 // First, the immutables
1112 case 'post_date':
1113 case 'submit_date':
1114 // Disable type selector
1115 typeSelect.val('date').prop('disabled', true);
1116 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="date">');
1117
1118 // add format field
1119 data = {
1120 'action': 'wpmtst_view_add_field_date',
1121 'key': key,
1122 'nonce': wpmtst_admin_views_script_nonce
1123 };
1124 $.post(ajaxurl, data, function (response) {
1125 // Insert into placeholder div. Add hidden field because we are
1126 // disabling the <select> so its value will not be submitted.
1127 $elParent.find('.field-property-box').html(response); // .find("input").trigger('focus');
1128 $el.parent().append('<input type="hidden" class="save-type" name="view[data][client_section][' + key + '][type]" value="date">');
1129 });
1130 break;
1131
1132 case 'link2':
1133 case 'link':
1134 // Get field name --> Get field label --> Populate link_text label
1135 var fieldName = $elParent.find('.field-name').find('select').val();
1136 var data2 = {
1137 'action': 'wpmtst_view_get_label',
1138 'name': fieldName,
1139 'nonce' : wpmtst_admin_views_script_nonce,
1140 };
1141 $.post(ajaxurl, data2, function (response) {
1142 var key = $elParent.attr('id').split('-').slice(-1)[0];
1143 $('#view-fieldtext' + key + '-label').val(response);
1144 });
1145 break;
1146
1147 case 'category':
1148 $(typeSelect).val('category').prop('disabled', true);
1149 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="category">');
1150 var fieldName = $elParent.find('.field-name').find('select').val();
1151 var data3 = {
1152 'action' : 'wpmtst_view_add_field_category_type_select',
1153 'fieldName': fieldName,
1154 'fieldType': fieldType,
1155 'key' : key,
1156 'source' : $('#add-field').attr('source'),
1157 'nonce' : wpmtst_admin_views_script_nonce
1158 };
1159 $.post(ajaxurl, data3, function (response) {
1160 // insert into placeholder div
1161 $elParent.find('.field-property-box').html(response);
1162 });
1163
1164 break;
1165
1166 default:
1167
1168 // Special handling
1169 if ('rating' === fieldType) {
1170 typeSelect.val('rating').prop('disabled', true);
1171 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="rating">');
1172 $elParent.find('.field-property-box').empty();
1173 break;
1174 }
1175
1176 if ('checkbox' === fieldType) {
1177 typeSelect.val('checkbox').prop('disabled', true);
1178 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="checkbox">');
1179 typeSelect.parent().hide();
1180 var fieldName = $elParent.find('.field-name').find('select').val();
1181 data = {
1182 'action': 'wpmtst_view_add_field_checkbox',
1183 'fieldName': fieldName,
1184 'fieldType': fieldType,
1185 'key': key,
1186 'source': source,
1187 'nonce' : wpmtst_admin_views_script_nonce
1188 };
1189 $.post(ajaxurl, data, function (response) {
1190 // insert into placeholder div
1191 $elParent.find('.field-property-box').html(response);
1192 });
1193 break;
1194 }
1195
1196 if ('video' === fieldType) {
1197 typeSelect.val('video').prop('disabled', true);
1198 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="video">');
1199 typeSelect.parent().hide();
1200 break;
1201 }
1202
1203 if ('video_record' === fieldType || fieldValue == 'video_file') {
1204 typeSelect.val('video_record').prop('disabled', true);
1205 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="video_record">');
1206 typeSelect.parent().hide();
1207 break;
1208 }
1209
1210 if ('platform' === fieldType) {
1211 typeSelect.val('platform').prop('disabled', true);
1212 typeSelectParent.append('<input type="hidden" class="save-type" name="' + source + '[client_section][' + key + '][save-type]" value="platform">');
1213 $elParent.find('.field-property-box').empty();
1214 break;
1215 }
1216
1217 $(typeSelect).val('text').prop('disabled', false);
1218 // remove meta field
1219 $elParent.find('.field-property-box').empty();
1220 // remove the saved type that's only necessary when we disable the input (above)
1221 $el.parent().find('input.save-type').remove();
1222 }
1223 });
1224
1225 /**
1226 * Custom field checkbox label
1227 */
1228 customFieldList.on('change', '.field-label-select', function () {
1229 var fieldValue = $(this).val();
1230 var elParent = $(this).closest('.field3');
1231 var fieldLabel = elParent.find('.client_section_field_label');
1232 var defaultValue = fieldLabel.attr('attr-defaultValue');
1233 if (fieldValue == 'custom') {
1234 fieldLabel.prop("readonly", false);
1235 } else {
1236 fieldLabel.prop("readonly", true);
1237 fieldLabel.val(defaultValue);
1238 }
1239 });
1240
1241 /**
1242 * Custom field checkbox value
1243 */
1244 customFieldList.on('change', '.field-checked-select', function () {
1245 var fieldValue = $(this).val();
1246 var elParent = $(this).closest('.field3');
1247 var fieldLabel = elParent.find('.client_section_field_checked_value');
1248 var defaultValue = fieldLabel.attr('attr-defaultValue');
1249 if (fieldValue == 'custom') {
1250 fieldLabel.prop("readonly", false);
1251 } else {
1252 fieldLabel.prop("readonly", true);
1253 fieldLabel.val(defaultValue);
1254 }
1255 });
1256
1257
1258 /**
1259 * Delete a client field
1260 */
1261 customFieldList.on('click', 'span.delete', function (e) {
1262 var thisField = $(this).closest('.field2');
1263 var yesno = confirm('Remove this field?');
1264 if (yesno) {
1265 thisField.fadeOut(function () {
1266 $(this).remove();
1267
1268 //trigger custom event
1269 var event = document.createEvent('Event');
1270 event.initEvent('wpmtst_custom_field_deleted', true, true);
1271 document.dispatchEvent(event);
1272 });
1273 }
1274 // Prevent click from expanding accordion
1275 e.stopImmediatePropagation();
1276 e.preventDefault();
1277 });
1278
1279 customFieldList.on('click', 'div.link', function (e) {
1280 $(this)
1281 .closest('.field2')
1282 .toggleClass('open')
1283 .find('.field-properties')
1284 .slideToggle(100);
1285 return false;
1286 });
1287
1288 /**
1289 * Slider|Carousel change listener
1290 */
1291 var $sliderType = $('#view-slider_type');
1292 var $effect = $('#view-effect');
1293 var $position = $('view-slideshow_nav_position');
1294
1295 var sliderTypeUpdate = function () {
1296 if ($sliderType.val() === 'show_multiple') {
1297 $effect.find('option[value=\'horizontal\']').prop('selected', true);
1298 $position.find('option[value=\'outside\']').prop('selected', true);
1299
1300 $sliderType.parent().siblings('.option-desc.singular').hide();
1301 $sliderType.parent().siblings('.option-desc.plural').showInlineBlock();
1302 } else {
1303 $sliderType.parent().siblings('.option-desc.singular').showInlineBlock();
1304 $sliderType.parent().siblings('.option-desc.plural').hide();
1305 }
1306
1307 $effect.trigger( 'change' );
1308 $position.trigger( 'change' );
1309 };
1310
1311 sliderTypeUpdate();
1312
1313 $sliderType.on('change', sliderTypeUpdate);
1314
1315 /**
1316 * MaxSlides change listener
1317 */
1318 var $maxSlides = $('[id^=\'view-max_slides\']');
1319
1320 // Update display
1321 var maxSlidesUpdateValue = function (el) {
1322 var $el = $(el);
1323 var maxSlidesValue = parseInt($el.val());
1324 if (maxSlidesValue > 1) {
1325 $el.parent().siblings('.option-desc.singular').hide();
1326 $el.parent().siblings('.option-desc.plural').showInlineBlock();
1327 } else {
1328 $el.parent().siblings('.option-desc.singular').showInlineBlock();
1329 $el.parent().siblings('.option-desc.plural').hide();
1330 }
1331 };
1332
1333 // Initial display
1334 $maxSlides.each( function (index, el) {
1335 maxSlidesUpdateValue(el);
1336 });
1337
1338 // Update on change
1339 var maxSlidesUpdate = function (e) {
1340 maxSlidesUpdateValue( $(e.target) );
1341 };
1342
1343 // Event listener
1344 $maxSlides.each( function (index, el) {
1345 $(el).on('change', maxSlidesUpdate);
1346 });
1347
1348 /**
1349 * MoveSlides change listener
1350 */
1351 var $moveSlides = $('[id^=\'view-move_slides\']');
1352
1353 // Update display
1354 var moveSlidesUpdateValue = function (el) {
1355 var $el = $(el);
1356 var moveSlidesValue = parseInt($el.val());
1357 if (moveSlidesValue > 1) {
1358 $el.parent().siblings('.option-desc.singular').hide();
1359 $el.parent().siblings('.option-desc.plural').showInlineBlock();
1360 } else {
1361 $el.parent().siblings('.option-desc.singular').showInlineBlock();
1362 $el.parent().siblings('.option-desc.plural').hide();
1363 }
1364 };
1365
1366 // Initial display
1367 $moveSlides.each( function (index, el) {
1368 moveSlidesUpdateValue(el);
1369 });
1370
1371 // Update on change
1372 var moveSlidesUpdate = function (e) {
1373 moveSlidesUpdateValue( $(e.target) );
1374 };
1375
1376 // Event listener
1377 $moveSlides.each( function (index, el) {
1378 $(el).on('change', moveSlidesUpdate);
1379 });
1380
1381 /**
1382 * Restore default breakpoints
1383 */
1384 $('#restore-default-breakpoints').on('click', function (e) {
1385 var data = {
1386 'action': 'wpmtst_restore_default_breakpoints',
1387 'nonce' : wpmtst_admin_views_script_nonce
1388 };
1389
1390 $.post(ajaxurl, data, function (response) {
1391
1392 var object = JSON.parse(response);
1393 var targetId;
1394 var el;
1395
1396 for (var key in object) {
1397
1398 if (object.hasOwnProperty(key)) {
1399
1400 // width
1401 targetId = 'view-breakpoint_' + key;
1402 el = $('[id="' + targetId + '"]');
1403 el.val(parseInt(object[key].width));
1404
1405 // max_slides
1406 targetId = 'view-max_slides_' + key;
1407 el = $('[id="' + targetId + '"]');
1408 el.val(parseInt(object[key].max_slides));
1409
1410 // margin
1411 targetId = 'view-margin_' + key;
1412 el = $('[id="' + targetId + '"]');
1413 el.val(parseInt(object[key].margin));
1414
1415 // move_slides
1416 targetId = 'view-move_slides_' + key;
1417 el = $('[id="' + targetId + '"]');
1418 el.val(parseInt(object[key].move_slides));
1419
1420 }
1421
1422 }
1423
1424 document.getElementById('restored-message').classList.add('copied');
1425 setTimeout(function () {
1426 document.getElementById('restored-message').classList.remove('copied');
1427 }, 2000);
1428
1429 });
1430 });
1431
1432 })(jQuery);
1433
1434 /**
1435 * Click to copy to keyboard
1436 * Thanks https://www.sitepoint.com/javascript-copy-to-clipboard/
1437 */
1438 (function () {
1439
1440 'use strict';
1441
1442 // click events
1443 document.body.addEventListener('click', copy, true);
1444
1445 // event handler
1446 function copy (e) {
1447
1448 // find target element
1449 var
1450 t = e.target,
1451 c = t.dataset.copytarget,
1452 inp = (c ? document.querySelector(c) : null);
1453
1454 // is element selectable?
1455 if (inp && inp.select) {
1456
1457 // select text
1458 inp.focus();
1459 inp.select();
1460
1461 // copy text
1462 document.execCommand('copy');
1463 document.getElementById('copy-message').classList.add('copied');
1464
1465 setTimeout(function () {
1466 document.getElementById('copy-message').classList.remove('copied');
1467 }, 2000);
1468
1469 }
1470
1471 }
1472
1473 })();
1474