PageSourceSearch

https://dailysuperheroes.com/wp-content/plugins/snax/assets/js/front.js?ver=1.53

js dailysuperheroes.com collected 2026-10-02 12:27:00 UTC 74,148 bytes, 2,434 lines download raw bytes

1/* global document */
2/* global jQuery */
3/* global snax */
4/* global alert */
5/* global confirm */
6/* global console */
7/* global grecaptcha */
8
9// globa namespace
10if ( typeof window.snax === 'undefined' ) {
11    window.snax = {};
12}
13
14/********
15 *
16 * Core
17 *
18 *******/
19
20(function ($, ctx) {
21
22    'use strict';
23
24    /** VARS *************************/
25
26    ctx.config = $.parseJSON(window.snax_front_config);
27
28    if (!ctx.config) {
29        throw 'Snax Error: Global config is not defined!';
30    }
31
32    /** FUNCTIONS ********************/
33
34    ctx.log = function(msg) {
35        if (typeof console !== 'undefined') {
36            console.log(msg);
37        }
38    };
39
40    ctx.inDebugMode = function() {
41        return (typeof ctx.config.debug_mode !== 'undefined' && ctx.config.debug_mode);
42    };
43
44    ctx.isTouchDevice = function () {
45        return ('ontouchstart' in window) || navigator.msMaxTouchPoints;
46    };
47
48    ctx.createCookie =  function (name, value, hours) {
49        var expires;
50
51        if (hours) {
52            var date = new Date();
53            date.setTime(date.getTime() + (hours * 60 * 60 * 1000));
54            expires = '; expires=' + date.toUTCString();
55        }
56        else {
57            expires = '';
58        }
59
60        document.cookie = name.concat('=', value, expires, '; path=/');
61    };
62
63    ctx.readCookie = function (name) {
64        var nameEQ = name + '=';
65        var ca = document.cookie.split(';');
66
67        for(var i = 0; i < ca.length; i += 1) {
68            var c = ca[i];
69            while (c.charAt(0) === ' ') {
70                c = c.substring(1,c.length);
71            }
72
73            if (c.indexOf(nameEQ) === 0) {
74                return c.substring(nameEQ.length,c.length);
75            }
76        }
77
78        return null;
79    };
80
81    ctx.deleteCookie = function (name) {
82        ctx.createCookie(name, '', -1);
83    };
84
85    ctx.getUrlParameter = function (param) {
86        var sPageURL = decodeURIComponent(window.location.search.substring(1)),
87            sURLVariables = sPageURL.split('&'),
88            sParameterName,
89            i;
90
91        for (i = 0; i < sURLVariables.length; i++) {
92            sParameterName = sURLVariables[i].split('=');
93
94            if (sParameterName[0] === param) {
95                return sParameterName[1] === undefined ? true : sParameterName[1];
96            }
97    }
98};
99
100})(jQuery, snax);
101
102
103/***********
104 *
105 * Helpers
106 *
107 ***********/
108
109(function ($, ctx) {
110
111    /* Media Item Class (image, audio, video) */
112
113    ctx.MediaItem = function (data) {
114        // Public scope.
115        var instance = {};
116
117        // Constructor.
118        function init() {
119            data = data || {};
120
121            data = $.extend({
122                'type':         'image',
123                'title':        '',
124                'source':       '',
125                'refLink':      '',
126                'description':  '',
127                'mediaId':      '',
128                'postId':       0,
129                'authorId':     '',
130                'status':       '',
131                'parentFormat': 'list',
132                'origin':       'post',
133                'legal':        false,
134                'memeTemplate': ''
135            }, data);
136
137            return instance;
138        }
139
140        instance.save = function(callback) {
141            callback = callback || function() {};
142
143            var ajaxData = {
144                'action':               'snax_add_media_item',
145                'security':             $('input[name=snax-add-media-item-nonce]').val(),
146                'snax_title':           data.title,
147                'snax_source':          data.source,
148                'snax_ref_link':        data.refLink,
149                'snax_description':     data.description,
150                'snax_media_id':        data.mediaId,
151                'snax_post_id':         data.postId,
152                'snax_author_id':       data.authorId,
153                'snax_status':          data.status,
154                'snax_parent_format':   data.parentFormat,
155                'snax_origin':          data.origin,
156                'snax_legal':           data.legal ? 'accepted' : '',
157                'snax_type':            data.type,
158                'snax_meme_template':   data.memeTemplate
159            };
160
161            if (typeof ctx.saveItemImageDataFilter === 'function') {
162                ajaxData = ctx.saveItemImageDataFilter(ajaxData, data);
163            }
164
165            var xhr = $.ajax({
166                'type': 'POST',
167                'url': ctx.config.ajax_url,
168                'dataType': 'json',
169                'data': ajaxData
170            });
171
172            xhr.done(function (res) {
173                 callback(res);
174            });
175        };
176
177        return init();
178    };
179
180    /* Embed Item Class */
181
182    ctx.EmbedItem = function (data) {
183        // Public scope.
184        var instance = {};
185
186        // Constructor.
187        function init() {
188            data = data || {};
189
190            data = $.extend({
191                'type':         'embed',
192                'title':        '',
193                'source':       '',
194                'refLink':      '',
195                'description':  '',
196                'embedCode':    '',
197                'postId':       0,
198                'authorId':     '',
199                'status':       '',
200                'parentFormat': 'list',
201                'origin':       'post',
202                'legal':        false
203            }, data);
204
205            return instance;
206        }
207
208        instance.save = function(callback) {
209            callback = callback || function() {};
210
211            var ajaxData = {
212                'action':               'snax_add_embed_item',
213                'security':             $('input[name=snax-add-embed-item-nonce]').val(),
214                'snax_title':           data.title,
215                'snax_source':          data.source,
216                'snax_ref_link':        data.refLink,
217                'snax_embed_code':      data.embedCode,
218                'snax_description':     data.description,
219                'snax_post_id':         data.postId,
220                'snax_author_id':       data.authorId,
221                'snax_status':          data.status,
222                'snax_parent_format':   data.parentFormat,
223                'snax_origin':          data.origin,
224                'snax_legal':           data.legal ? 'accepted' : ''
225            };
226
227            if (typeof ctx.saveItemEmbedDataFilter === 'function') {
228                ajaxData = ctx.saveItemEmbedDataFilter(ajaxData, data);
229            }
230
231            var xhr = $.ajax({
232                'type': 'POST',
233                'url': ctx.config.ajax_url,
234                'dataType': 'json',
235                'data': ajaxData
236            });
237
238            xhr.done(function (res) {
239                callback(res);
240            });
241        };
242
243        return init();
244    };
245
246    /* Embed Item Class */
247
248    ctx.TextItem = function (data) {
249        // Public scope.
250        var instance = {};
251
252        // Constructor.
253        function init() {
254            data = data || {};
255
256            data = $.extend({
257                'type':         'text',
258                'title':        '',
259                'refLink':      '',
260                'description':  '',
261                'postId':       0,
262                'authorId':     '',
263                'status':       '',
264                'parentFormat': 'list',
265                'origin':       'post',
266                'legal':        false
267            }, data);
268
269            return instance;
270        }
271
272        instance.save = function(callback) {
273            callback = callback || function() {};
274
275            var ajaxData = {
276                'action':               'snax_add_text_item',
277                'security':             $('input[name=snax-add-text-item-nonce]').val(),
278                'snax_title':           data.title,
279                'snax_ref_link':        data.refLink,
280                'snax_description':     data.description,
281                'snax_post_id':         data.postId,
282                'snax_author_id':       data.authorId,
283                'snax_status':          data.status,
284                'snax_parent_format':   data.parentFormat,
285                'snax_origin':          data.origin,
286                'snax_legal':           data.legal ? 'accepted' : ''
287            };
288
289            if (typeof ctx.saveItemTextDataFilter === 'function') {
290                ajaxData = ctx.saveItemTextDataFilter(ajaxData, data);
291            }
292
293            var xhr = $.ajax({
294                'type': 'POST',
295                'url': ctx.config.ajax_url,
296                'dataType': 'json',
297                'data': ajaxData
298            });
299
300            xhr.done(function (res) {
301                callback(res);
302            });
303        };
304
305        return init();
306    };
307
308    ctx.deleteItem = function($link, callback) {
309        callback = callback || function() {};
310
311        var nonce       = $.trim($link.attr('data-snax-nonce'));
312        var itemId      = parseInt($link.attr('data-snax-item-id'), 10);
313        var userId      = snax.currentUserId;
314
315        var xhr = $.ajax({
316            'type': 'POST',
317            'url': ctx.config.ajax_url,
318            'dataType': 'json',
319            'data': {
320                'action':               'snax_delete_item',
321                'security':             nonce,
322                'snax_item_id':         itemId,
323                'snax_user_id':         userId
324            }
325        });
326
327        xhr.done(function (res) {
328            callback(res);
329        });
330    };
331
332    ctx.setItemAsFeatured = function($link, callback) {
333        callback = callback || function() {};
334
335        var nonce       = $.trim($link.attr('data-snax-nonce'));
336        var itemId      = parseInt($link.attr('data-snax-item-id'), 10);
337        var userId      = snax.currentUserId;
338
339        var xhr = $.ajax({
340            'type': 'POST',
341            'url': ctx.config.ajax_url,
342            'dataType': 'json',
343            'data': {
344                'action':               'snax_set_item_as_featured',
345                'security':             nonce,
346                'snax_item_id':         itemId,
347                'snax_user_id':         userId
348            }
349        });
350
351        xhr.done(function (res) {
352            callback(res);
353        });
354    };
355
356    ctx.updateItems = function(items, callback) {
357        callback = callback || function() {};
358
359        var xhr = $.ajax({
360            'type': 'POST',
361            'url': ctx.config.ajax_url,
362            'dataType': 'json',
363            'data': {
364                'action':           'snax_update_items',
365                'security':         $('input[name=snax-frontend-submission-nonce]').val(),
366                'snax_items':       items
367            }
368        });
369
370        xhr.done(function (res) {
371            callback(res);
372        });
373    };
374
375    ctx.deletePost = function($link, callback) {
376        callback = callback || function() {};
377
378        var nonce  = $.trim($link.attr('data-snax-nonce'));
379        var postId = parseInt($link.attr('data-snax-post-id'), 10);
380
381        var xhr = $.ajax({
382            'type': 'POST',
383            'url': ctx.config.ajax_url,
384            'dataType': 'json',
385            'data': {
386                'action':           'snax_delete_post',
387                'security':         nonce,
388                'snax_post_id':     postId
389            }
390        });
391
392        xhr.done(function (res) {
393            callback(res);
394        });
395    };
396
397    ctx.loginRequired = function(blocked) {
398        $('body').trigger('snaxLoginRequired', [blocked]);
399    };
400
401    ctx.getMediaHtmlTag = function(data, callback) {
402        var xhr = $.ajax({
403            'type': 'GET',
404            'url': ctx.config.ajax_url,
405            'dataType': 'json',
406            'data': {
407                'action':           'snax_load_media_tpl',
408                'snax_media_id':    data.mediaId,
409                'snax_post_id':     data.postId,
410                'snax_type':        data.type
411            }
412        });
413
414        xhr.done(function (res) {
415            callback(res);
416        });
417    };
418
419    ctx.deleteMedia = function(data, callback) {
420        callback = callback || function() {};
421
422        var xhr = $.ajax({
423            'type': 'POST',
424            'url': ctx.config.ajax_url,
425            'dataType': 'json',
426            'data': {
427                'action':           'snax_delete_media',
428                'security':         $('input[name=snax-delete-media-nonce]').val(),
429                'snax_media_id':    data.mediaId,
430                'snax_author_id':   data.authorId
431            }
432        });
433
434        xhr.done(function (res) {
435            callback(res);
436        });
437    };
438
439    ctx.updateMediaMetadata = function(data, callback) {
440        callback = callback || function() {};
441
442        var xhr = $.ajax({
443            'type': 'POST',
444            'url': ctx.config.ajax_url,
445            'dataType': 'json',
446            'data': {
447                'action':               'snax_update_media_meta',
448                // @todo - use separate nonce or use generic one.
449                'security':             $('input[name=snax-delete-media-nonce]').val(),
450                'snax_media_id':        data.mediaId,
451                'snax_parent_format':   data.parentFormat
452            }
453        });
454
455        xhr.done(function (res) {
456            callback(res);
457        });
458    };
459
460    ctx.getEmbedPreview = function(embed_code, callback) {
461        var xhr = $.ajax({
462            'type': 'POST',
463            'url': ctx.config.ajax_url,
464            'dataType': 'json',
465            'data': {
466                'action':           'snax_load_embed_tpl',
467                'snax_embed_code':  embed_code
468            }
469        });
470
471        xhr.done(function (res) {
472            callback(res);
473        });
474    };
475
476    ctx.displayFeedback = function(type) {
477        var feedbackTypeClass = 'snax-feedback-' + type;
478
479        // Try to get type specific feedback first.
480        var $feedback = $('.' + feedbackTypeClass);
481
482        if ($feedback.length === 0) {
483            return;
484        }
485
486        ctx.hideFeedback();
487
488        // Activate.
489        $feedback.toggleClass('snax-feedback-off snax-feedback-on');
490
491        // Show.
492        $('body').addClass('snax-show-feedback');
493    };
494
495    ctx.hideFeedback = function() {
496        // Deactivate all.
497        $('.snax-feedback-on').toggleClass('snax-feedback-on snax-feedback-off');
498
499        // Hide all.
500        $('body').removeClass('snax-show-feedback');
501    };
502
503    ctx.isValidUrl = function(url) {
504        return url.match(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;
504:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
505    };
506
507})(jQuery, snax);
508
509
510/*********
511 *
512 * Common
513 *
514 *********/
515
516(function ($, ctx) {
517
518    'use strict';
519
520    var selectors = {
521        'feedbackCloseButton':  '.snax-close-button'
522    };
523
524    // fire
525    $(document).ready(function () {
526
527        /*
528         * Close feedback button.
529         */
530        $(selectors.feedbackCloseButton).on('click', function(e) {
531            e.preventDefault();
532
533            snax.hideFeedback();
534        });
535    });
536
537})(jQuery, snax);
538
539
540/****************
541 *
542 * Facebook SDK
543 *
544 ****************/
545
546(function ($, ctx) {
547
548    'use strict';
549
550    ctx.resetFacebookSDK = function () {
551        $('script#facebook-jssdk').remove();
552        $('#fb-root').remove();
553        if (window.FB) {
554            delete window.FB;
555        }
556    };
557
558    $('body').on( 'snaxBeforeNewContentReady', function ( e, $newContent ) {
559        if ($newContent.find('.fb-video')) {
560            ctx.resetFacebookSDK();
561        }
562    } );
563
564})(jQuery, snax);
565
566/****************************
567 *
568 * Module: Media upload form
569 *
570 ***************************/
571
572(function ($, ctx) {
573
574    'use strict';
575
576    var selectors = {
577        'form':                 '.snax-media-upload-form',
578        'pluploadForm':          '.snax-plupload-upload-ui',
579        'loadFormButton':       '.snax-load-form-button'
580    };
581
582    ctx.mediaUploadForm = function () {
583        if (typeof snaxPlupload === 'undefined') {
584            return;
585        }
586
587        $(selectors.form).each(function() {
588            snaxPlupload.initUploader($(this));
589        });
590
591        $(selectors.loadFormButton).on('click',function() {
592            var $link = $(this);
593            var $form = $link.parents(selectors.form);
594            var formClass = $link.attr('data-snax-rel-class');
595
596            $form.find('.' + formClass).toggle();
597
598            var $pluploadForm = $form.find(selectors.pluploadForm);
599
600            $pluploadForm.toggle();
601
602            if ($pluploadForm.is(':visible')) {
603                $form.removeClass('snax-custom-form');
604            } else {
605                $form.addClass('snax-custom-form');
606            }
607        });
608    };
609
610    // fire
611    $(document).ready(function () {
612        ctx.mediaUploadForm();
613    });
614
615})(jQuery, snax);
616
617
618/*************************
619 *
620 * Module: Date > Time ago
621 *
622 *************************/
623
624(function ($, ctx) {
625
626    'use strict';
627
628    var selectors = {
629        'wrapper':      '.snax-time-left',
630        'dateWrapper':  '> .snax-date-wrapper',
631        'date':         '> .snax-date',
632        'timeWrapper':  '> .snax-time-wrapper',
633        'time':         '> .snax-time'
634    };
635
636    ctx.timeagoSelectors = selectors;
637
638    ctx.dateConstans = {
639        'day_ms':   1000 * 60 * 60 * 24,
640        'month_ms': 1000 * 60 * 60 * 24 * 30,
641        'year_ms':  1000 * 60 * 60 * 24 * 356
642    };
643
644    ctx.dateToTimeago = function () {
645        if (!$.fn.timeago) {
646            return;
647        }
648
649        // store current settings, thanks to $.extend we have a copy without reference to original object
650        var origSettings = $.extend(true, {} , $.timeago.settings);
651
652        // override
653        $.extend($.timeago.settings, {
654            cutoff: ctx.dateConstans.year_ms,
655            allowFuture: true
656        });
657
658        $.extend($.timeago.settings.strings, {
659            suffixFromNow: ''
660        });
661
662        // apply
663        $(selectors.wrapper).each(function () {
664            var $wrapper        = $(this);
665            var $dateWrapper    = $wrapper.find(selectors.dateWrapper);
666            var $date           = $dateWrapper.find(selectors.date);
667            var $timeWrapper    = $wrapper.find(selectors.timeWrapper);
668            var $time           = $timeWrapper.find(selectors.time);
669
670            var timeLeftText = $.timeago($date.text());
671
672            $time.text(timeLeftText);
673
674            $dateWrapper.removeClass( '.snax-date-wrapper-unfriendly' );
675            $timeWrapper.removeClass( 'snax-time-wrapper-unfriendly' );
676        });
677
678        // restore
679        $.timeago.settings = origSettings;
680    };
681
682    // fire
683    $(document).ready(function () {
684        ctx.dateToTimeago();
685    });
686
687})(jQuery, snax);
688
689
690/**************************
691 *
692 * Module: Upvote/Downvote
693 *
694 *************************/
695
696(function ($, ctx) {
697
698    'use strict';
699
700    var locked = false;
701
702    var selectors = {
703        'wrapper':      '.snax-voting',
704        'upvoteLink':   '.snax-voting-upvote',
705        'downvoteLink': '.snax-voting-downvote',
706        'guestVoting':  '.snax-guest-voting',
707        'voted':        '.snax-user-voted',
708        'scoreWrapper': '.snax-voting-score',
709        'scoreValue':   '.snax-voting-score strong'
710    };
711
712    var classes = {
713        'voted':        'snax-user-voted'
714    };
715
716    ctx.votesSelectors  = selectors;
717    ctx.votesClasses    = classes;
718
719    ctx.votes = function () {
720        // Catch event on wrapper to keep it working after box content reloading
721        $('body').on('click', selectors.upvoteLink + ', ' + selectors.downvoteLink, function (e) {
722            e.preventDefault();
723
724            if (locked) {
725                return;
726            }
727
728            locked = true;
729
730            var $link       = $(this);
731
732            var voteType    = $link.is(selectors.upvoteLink) ? 'upvote' : 'downvote';
733            var $wrapper    = $link.parents(selectors.wrapper);
734            var nonce       = $.trim($link.attr('data-snax-nonce'));
735            var itemId      = parseInt($link.attr('data-snax-item-id'), 10);
736            var authorId    = parseInt($link.attr('data-snax-author-id'), 10);
737
738            ctx.vote({
739                'itemId':   itemId,
740                'authorId': authorId,
741                'type':     voteType
742            }, nonce, $wrapper);
743        });
744
745        // Iterate over all voting boxes and update them based on cookie states.
746        $(selectors.wrapper).each(function () {
747            var $this   = $(this);
748            var id      = parseInt($this.attr('data-snax-item-id'), 10);
749
750            if (id <= 0) {
751                return;
752            }
753
754            var typeCookie  = 'snax_vote_type_' + id;
755            var scoreCookie = 'snax_vote_score_' + id;
756
757            var type  = ctx.readCookie(typeCookie);
758            var score = ctx.readCookie(scoreCookie);
759
760            if (!type && !score) {
761                return;
762            }
763
764            if (score) {
765                ctx.updateVoteScore($this.find(selectors.scoreWrapper), score);
766            }
767
768            if (type) {
769                var $upVoteLink     = $this.find(selectors.upvoteLink);
770                var $downVoteLink   = $this.find(selectors.downvoteLink);
771
772                if ('upvote' === type) {
773                    $upVoteLink.addClass(classes.voted);
774                    $downVoteLink.removeClass(classes.voted);
775                } else {
776                    $downVoteLink.addClass(classes.voted);
777                    $upVoteLink.removeClass(classes.voted);
778                }
779            }
780        });
781    };
782
783    ctx.vote = function (data, nonce, $box) {
784        var config = $.parseJSON(window.snax_front_config);
785        if ( $box.find('.snax-login-required').length > 0 ){
786            return;
787        }
788
789        if (!config) {
790            ctx.log('Item voting failed. Global config is not defined!');
791            return;
792        }
793
794        /*
795         * Apply new voting box state before ajax response.
796         */
797        var $userVoted      = $box.find('.snax-user-voted');
798        var userUpvoted     = $userVoted.length > 0 && $userVoted.is('.snax-voting-upvote');
799        var userDownvoted   = $userVoted.length > 0 && $userVoted.is('.snax-voting-downvote');
800        var $score          = $box.find('.snax-voting-score > strong');
801        var score           = parseInt($score.text(), 10);
802        var diff            = 'upvote' === data.type ? 1 : -1;
803
804        // Remove all bubbles.
805        $box.find('.snax-voting-bubble').remove();
806
807        // User reverted his vote.
808        if (userUpvoted && 'upvote' === data.type || userDownvoted && 'downvote' === data.type) {
809            diff *= -1;
810
811            $box.find('.snax-user-voted').removeClass('snax-user-voted');
812
813            if ( 'upvote' === data.type ) {
814                $box.find('.snax-voting-upvote').append('<span class="snax-voting-bubble snax-voting-bubble-minus-back">-1</span>');
815            } else {
816                $box.find('.snax-voting-downvote').append('<span class="snax-voting-bubble snax-voting-bubble-plus-back">+1</span>');
817            }
818
819        // User voted opposite.
820        } else if (userUpvoted && 'downvote' === data.type || userDownvoted && 'upvote' === data.type) {
821            diff *= 2;
822
823            $box.find('.snax-user-voted').removeClass('snax-user-voted');
824            $box.find('.snax-voting-' + data.type).addClass('snax-user-voted');
825
826            if ( 'upvote' === data.type ) {
827                $box.find('.snax-voting-upvote').append('<span class="snax-voting-bubble snax-voting-bubble-plus">+2</span>');
828            } else {
829                $box.find('.snax-voting-downvote').append('<span class="snax-voting-bubble snax-voting-bubble-minus">-2</span>');
830            }
831        // User added new vote.
832        } else {
833            if ( 'upvote' === data.type ) {
834                $box.find('.snax-voting-upvote').addClass('snax-user-voted').append('<span class="snax-voting-bubble snax-voting-bubble-plus">+1</span>');
835            } else {
836                $box.find('.snax-voting-downvote').addClass('snax-user-voted').append('<span class="snax-voting-bubble snax-voting-bubble-minus">-1</span>');
837            }
838        }
839
840        // Update score.
841        ctx.updateVoteScore($box.find(selectors.scoreWrapper), score + diff);
842
843        // Send ajax.
844        var xhr = $.ajax({
845            'type': 'POST',
846            'url': config.ajax_url,
847            'dataType': 'json',
848            'data': {
849                'action':           'snax_vote_item',
850                'security':         nonce,
851                'snax_item_id':     data.itemId,
852                'snax_author_id':   data.authorId,
853                'snax_vote_type':   data.type,
854                'snax_user_voted':  ctx.readCookie( 'snax_vote_type_' + data.itemId )
855            }
856        });
857
858        // Update state immediately after sending ajax. Don't wait for response.
859        ctx.updateVoteState(data.itemId, data.type, $box);
860
861        xhr.done(function (res) {
862            locked = false;
863        });
864    };
865
866    ctx.updateVoteState = function(itemId, type, $box) {
867        var typeCookie  = 'snax_vote_type_' + itemId;
868        var scoreCookie = 'snax_vote_score_' + itemId;
869
870        var currentValue = ctx.readCookie(typeCookie);
871
872        // Cookie can't be read immediately so we need to update CSS classes manually.
873        $box.find(selectors.voted).removeClass(classes.voted);
874
875        // User voted and now he wants to remove the vote.
876        if (currentValue === type) {
877            ctx.deleteCookie(typeCookie);
878        } else {
879            ctx.createCookie(typeCookie, type, 1);
880
881            // Cookie can't be read immediately so we need to update CSS classes manually.
882            $box.find('.snax-voting-' + type).addClass(classes.voted);
883        }
884
885        // Update score.
886        var score = parseInt($box.find(selectors.scoreValue).text(), 10);
887
888        ctx.createCookie(scoreCookie, score, 1);
889    };
890
891    ctx.updateVoteScore = function($wrapper, score) {
892        var scoreHtml = '';
893        var $container = $wrapper.parents('.snax-voting');
894
895        // Singular?
896        if (1 === Math.abs(score)) {
897            scoreHtml = ctx.config.i18n.points_singular_tpl.replace('%d', score);
898        } else {
899            scoreHtml = ctx.config.i18n.points_plural_tpl.replace('%d', score);
900        }
901
902        // Remove all score related classes.
903        $container.removeClass('snax-voting-0 snax-voting-negative snax-voting-positive');
904
905        // Add score related classes.
906        if (0 < score) {
907            $container.addClass( 'snax-voting-positive' );
908        } else if (0 > score) {
909            $container.addClass( 'snax-voting-negative' );
910        } else {
911            $container.addClass( 'snax-voting-0' );
912        }
913
914        $wrapper.html(scoreHtml);
915    };
916
917    // fire
918    $(document).ready(function () {
919        ctx.votes();
920    });
921
922})(jQuery, snax);
923
924/*********************
925 *
926 * Module: Login form
927 *
928 ********************/
929
930(function ($, ctx) {
931
932    'use strict';
933
934    var selectors = {
935        'loginTab':             '.snax-login-tab',
936        'loginFormWrapper':     '.snax-login-form',
937        'loginForm':            '.snax-login-form #loginform-in-popup',
938        'forgotTab':            '.snax-forgot-pass-tab',
939        'forgotFormWrapper':    '.snax-forgot-pass-form',
940        'forgotForm':           '.snax-forgot-pass-form #lostpasswordform',
941        'gdprTab':              '.snax-gdpr-tab',
942        'backToLoginTab':       '.snax-back-to-login-tab',
943        'loginErrorMessage':    '.snax-login-form .snax-login-error-message',
944        'forgotErrorMessage':   '.snax-forgot-pass-form .snax-forgot-pass-error-message',
945        'forgotSuccessMessage': '.snax-forgot-pass-form .snax-forgot-pass-success-message',
946        'user': {
947            'loginInput':       '#user_login',
948            'emailInput':       '#user_email',
949            'passwordInput':    '#user_pass'
950        },
951        'forgotPasswordLink':   '#snax-popup-content .snax-link-forgot-pass',
952        'passwordWrapper':      '#snax-popup-content .login-password',
953        'connectWithLabel':     '#snax-popup-content .wp-social-login-connect-with',
954        'resetTab':             '.snax-reset-tab'
955    };
956
957    ctx.loginFormSelectors = selectors;
958
959    var useReCaptcha;
960    var reCaptchaToken;
961    var urlAction = ctx.getUrlParameter(ctx.config.login_popup_url_var);
962
963    ctx.loginForm = function () {
964        useReCaptcha = ctx.config.use_login_recaptcha;
965
966        // Add input placeholders.
967        $.each(selectors.user, function (id, selector) {
968            var $input = $(selector);
969            var $label = $input.prev('label');
970
971            if ($label.length > 0) {
972                $input.attr('placeholder', $label.text());
973            }
974        });
975
976        // Move forgot link after password field.
977        $(selectors.passwordWrapper + ' input').after( $(selectors.forgotPasswordLink) );
978
979        // Wrap label with <h4> tag.
980        $(selectors.connectWithLabel).wrapInner( '<h4>' );
981
982        $('.wp-social-login-provider').on('click', function(e) {
983            var $that = $(this);
984            if ($('.snax-wpsl-gdpr-consent input').length > 0) {
985                if (!$('.snax-wpsl-gdpr-consent input').is(':checked')) {
986                    e.stopPropagation();
987                    e.stopImmediatePropagation();
988                    e.preventDefault();
989                    handleLoginGDPR($that);
990                }
991            }
992        });
993
994        handleLoginAction();
995        handleForgotPassAction();
996        handleTabsSwitch();
997
998        if (urlAction==='reset_password'){
999            $(selectors.loginTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1000            $(selectors.resetTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1001        }
1002
1003        if (urlAction==='forgot_password'){
1004            $(selectors.loginTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1005            $(selectors.forgotTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1006        }
1007
1008        $('body').on('snaxPopupOpened', function(e, action) {
1009            if (useReCaptcha && 'login' === action) {
1010                loadReCaptcha();
1011            }
1012        });
1013    };
1014
1015    var handleLoginGDPR = function($clickedProvider) {
1016        $(selectors.loginTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1017        $(selectors.gdprTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1018        $('.snax-login-gdpr-accept').on('click', function() {
1019            $('.snax-wpsl-gdpr-consent input').prop('checked', true);
1020            $(selectors.gdprTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1021            $(selectors.loginTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1022            var redirectTo = $clickedProvider.attr('href');
1023            window.location.href = redirectTo;
1024        });
1025    };
1026
1027    var handleLoginAction = function() {
1028        $(selectors.loginForm).on('submit', function(e) {
1029            e.preventDefault();
1030
1031            var $form = $(this);
1032            var $errorMessage = $(selectors.loginErrorMessage);
1033
1034            var requestData = {
1035                'action':   'snax_login'
1036            };
1037
1038            $.each($form.serializeArray(), function(i, field) {
1039                requestData[field.name] = field.value;
1040            });
1041
1042            // Read config directly, DO NOT use any reference. We change the value while auto logging.
1043            if (ctx.config.use_login_recaptcha) {
1044                if (!reCaptchaToken) {
1045                    $errorMessage.html( '<p class="snax-validation-tip">' + ctx.config.i18n.recaptcha_invalid + '</p>');
1046                    return;
1047                }
1048            }
1049
1050            // Clear error message.
1051            $errorMessage.html('<p>' + ctx.config.i18n.user_is_logging + '</p>');
1052
1053            var xhr = $.ajax({
1054                'type':     'POST',
1055                'url':      ctx.config.ajax_url,
1056                'dataType': 'json',
1057                'data':     requestData
1058            });
1059
1060            xhr.done(function (res) {
1061                if ('success' === res.status) {
1062                    var redirectTo = res.args.redirect_url;
1063
1064                    if (!redirectTo) {
1065                        redirectTo = window.location.href;
1066                    }
1067
1068                    if (redirectTo.indexOf('?') > 0){
1069                        redirectTo += '&' + ctx.config.login_success_var + '=true';
1070                    }else{
1071                        redirectTo += '?' + ctx.config.login_success_var + '=true';
1072                    }
1073
1074                    window.location.href = redirectTo;
1075                } else {
1076                    if (res.message) {
1077                        $errorMessage.html( '<p class="snax-validation-tip">' + res.message + '</p>');
1078                    }
1079
1080                    if (useReCaptcha) {
1081                        grecaptcha.reset();
1082                    }
1083                }
1084            });
1085
1086            // Reload page if failed.
1087            xhr.fail(function() {
1088                var reloadUrl = window.location.href;
1089
1090                if (reloadUrl.indexOf('?') > 0){
1091                    reloadUrl += '&' + ctx.config.login_success_var + '=false';
1092                }else{
1093                    reloadUrl += '?' + ctx.config.login_success_var + '=false';
1094                }
1095
1096                window.location.href = reloadUrl;
1097            });
1098        });
1099    };
1100
1101    var handleForgotPassAction = function() {
1102        $(selectors.forgotForm).on('submit', function(e) {
1103            e.preventDefault();
1104
1105            var $form = $(this);
1106            var $errorMessage = $(selectors.forgotErrorMessage);
1107            var $successMessage = $(selectors.forgotSuccessMessage);
1108
1109            var requestData = {
1110                'action':   'snax_forgot_pass'
1111            };
1112
1113            $.each($form.serializeArray(), function(i, field) {
1114                requestData[field.name] = field.value;
1115            });
1116
1117            // Clear messages.
1118            $errorMessage.text('');
1119            $successMessage.text('');
1120
1121            var xhr = $.ajax({
1122                'type':     'POST',
1123                'url':      ctx.config.ajax_url,
1124                'dataType': 'json',
1125                'data':     requestData
1126            });
1127
1128            xhr.done(function (res) {
1129                if ('success' === res.status) {
1130                    if (res.message) {
1131                        $successMessage.html( '<p class="snax-validation-tip">' + res.message + '</p>');
1132                    }
1133                } else {
1134                    if (res.message) {
1135                        $errorMessage.html( '<p class="snax-validation-tip">' + res.message + '</p>');
1136                    }
1137                }
1138            });
1139        });
1140    };
1141
1142    var handleTabsSwitch = function() {
1143        $(selectors.forgotPasswordLink).on('click', function(e) {
1144            e.preventDefault();
1145
1146            $(selectors.loginTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1147            $(selectors.forgotTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1148        });
1149
1150        $(selectors.backToLoginTab).on('click', function(e) {
1151            e.preventDefault();
1152
1153            $(selectors.resetTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1154            $(selectors.forgotTab).removeClass('snax-tab-active').addClass('snax-tab-inactive');
1155            $(selectors.loginTab).removeClass('snax-tab-inactive').addClass('snax-tab-active');
1156        });
1157    };
1158
1159    var loadReCaptcha = function() {
1160        var apiUrl  = ctx.config.recaptcha_api_url;
1161        var ver     = ctx.config.recaptcha_version;
1162        var siteKey = ctx.config.recaptcha_site_key;
1163
1164        if (!siteKey || !apiUrl) {
1165            return;
1166        }
1167
1168        var renderLoginReCaptcha = function() {
1169            if ('30' === ver) {
1170                grecaptcha.execute(
1171                    siteKey,
1172                    { action: 'login' }
1173                ).then( function( token ) {
1174                    $('#snax-login-recaptcha').html('<input type="hidden" name="g-recaptcha-response" value="'+ token +'">');
1175                    reCaptchaEnteredCorrectly(token);
1176                } );
1177            } else {
1178                grecaptcha.render('snax-login-recaptcha', {
1179                    'sitekey' : siteKey,
1180                    'callback': reCaptchaEnteredCorrectly
1181                });
1182            }
1183        };
1184
1185        // Google reCaptcha API loaded.
1186        if (typeof grecaptcha !== 'undefined') {
1187            renderLoginReCaptcha();
1188        } else {
1189            // API not loaded. Register callback and load script.
1190            window.snaxReCaptchaOnloadCallback = function() {
1191                renderLoginReCaptcha();
1192            };
1193
1194            if ('30' === ver) {
1195                $('head').append('<script src="' + apiUrl + '?onload=snaxReCaptchaOnloadCallback&render='+siteKey+'" async defer>');
1196            } else {
1197                $('head').append('<script src="' + apiUrl + '?onload=snaxReCaptchaOnloadCallback&render=explicit" async defer>');
1198            }
1199        }
1200    };
1201
1202    var reCaptchaEnteredCorrectly = function(response) {
1203        reCaptchaToken = response;
1204    };
1205
1206    // Fire.
1207    $(document).ready(function () {
1208        ctx.loginForm();
1209    });
1210
1211})(jQuery, snax);
1212
1213/****************
1214 *
1215 * Module: Popup
1216 *
1217 ****************/
1218
1219(function ($, ctx) {
1220
1221    'use strict';
1222
1223    var selectors = {
1224        'popupContent':     '#snax-popup-content',
1225        'loginRequired':    '.snax-login-required',
1226        'usernameField':    '#user_login'
1227    };
1228
1229    ctx.popupSelectors = selectors;
1230
1231    ctx.popup = function () {
1232        if (!$.fn.magnificPopup) {
1233            return;
1234        }
1235
1236        $(selectors.loginRequired).click(function (e) {
1237            e.preventDefault();
1238
1239            var $content = $(selectors.popupContent);
1240
1241            ctx.openPopup($content, {}, 'login');
1242
1243            // Delay till popup opens.
1244            setTimeout(function() {
1245                $content.find(selectors.usernameField).focus();
1246            }, 100);
1247        });
1248
1249        $('body').on('snaxLoginRequired', function(e, blocked) {
1250            blocked = blocked || false;
1251
1252            var $content = $(selectors.popupContent);
1253
1254            ctx.openPopup($content, {
1255                'closeOnBgClick': blocked
1256            }, 'login');
1257
1258            // Delay till popup opens.
1259            setTimeout(function() {
1260                $content.find(selectors.usernameField).focus();
1261            }, 100);
1262
1263            // Prevent default close action to not show page under the overlay when redirecting.
1264            if (blocked) {
1265                $.magnificPopup.instance.close = function() {
1266                    window.location.href = ctx.config.site_url;
1267                };
1268            }
1269        });
1270    };
1271
1272    ctx.openPopup = function ($content, args, action) {
1273        if (!$.fn.magnificPopup) {
1274            return;
1275        }
1276
1277        args = args || {};
1278
1279        args.items = {
1280            src: $content,
1281            type: 'inline'
1282        };
1283
1284        args.callbacks = {
1285            'open': function () {
1286                $('body').trigger('snaxPopupOpened', [ action ]);
1287            }
1288        };
1289
1290        $.magnificPopup.open(args);
1291    };
1292
1293    ctx.closePopup = function () {
1294        if (!$.fn.magnificPopup) {
1295            return;
1296        }
1297
1298        $.magnificPopup.close();
1299    };
1300
1301    ctx.redirectToLogin = function () {
1302        $(selectors.loginRequired).click(function (e) {
1303            window.location.href = ctx.config.login_url;
1304        });
1305
1306        if (ctx.forceLoginPopup) {
1307            window.location.href = ctx.config.login_url;
1308        }
1309
1310        $('body').on('snaxLoginRequired', function(e) {
1311            window.location.href = ctx.config.login_url;
1312        });
1313
1314        if (ctx.getUrlParameter(ctx.config.login_popup_url_var)){
1315            window.location.href = ctx.config.login_url;
1316        }
1317    };
1318
1319    // fire
1320    $(document).ready(function () {
1321        if (ctx.config.enable_login_popup) {
1322            ctx.popup();
1323
1324            if (ctx.getUrlParameter(ctx.config.login_popup_url_var) && !ctx.config.logged_in){
1325                ctx.loginRequired();
1326            }
1327
1328            if (ctx.forceLoginPopup) {
1329                ctx.loginRequired(ctx.forceLoginPopup.blocked);
1330            }
1331        } else {
1332            ctx.redirectToLogin();
1333        }
1334    });
1335
1336})(jQuery, snax);
1337
1338
1339/*************************
1340 *
1341 * Module: Actions Menu
1342 *
1343 ************************/
1344
1345(function ($, ctx) {
1346
1347    'use strict';
1348
1349    var selectors = {
1350        'actions' :         '.snax-actions',
1351        'actionsToggle':    '.snax-actions-toggle',
1352        'actionsExpanded':  '.snax-actions-expanded'
1353    };
1354
1355    var classes = {
1356        'expanded': 'snax-actions-expanded'
1357    };
1358
1359    ctx.actionsMenuSelectors = selectors;
1360    ctx.actionsMenuClasses = classes;
1361
1362    ctx.actionsMenu = function () {
1363        var $body = $('body');
1364
1365        $('body').on('click', selectors.actionsToggle, function(e) {
1366            e.preventDefault();
1367
1368            var $toggle = $(e.target);
1369
1370            $toggle.parents(selectors.actions).toggleClass(classe
1370s.expanded);
1371        });
1372
1373        // Hide on focus out.
1374        $body.on('click touchstart', function (e) {
1375            var $activeMenu = $(e.target).parents(selectors.actions);
1376
1377            // Collapse all expanded menus except active one.
1378            $(selectors.actionsExpanded).not($activeMenu).removeClass(classes.expanded);
1379        });
1380    };
1381
1382    // Fire.
1383    $(document).ready(function () {
1384        ctx.actionsMenu();
1385    });
1386
1387})(jQuery, snax);
1388
1389
1390/*************************
1391 *
1392 * Module: Item Share
1393 *
1394 ************************/
1395
1396(function ($, ctx) {
1397
1398    'use strict';
1399
1400    var selectors = {
1401        'wrapper' :         '.snax-item-share',
1402        'toggle':           '.snax-item-share-toggle',
1403        'expandedState':    '.snax-item-share-expanded'
1404    };
1405
1406    var classes = {
1407        'expanded': 'snax-item-share-expanded'
1408    };
1409
1410    ctx.itemShareSelectors = selectors;
1411    ctx.itemShareClasses   = classes;
1412
1413    ctx.itemShare = function () {
1414        // On none touchable devices, shares visibility is handled via css :hover.
1415        // On touch devices there is no "hover", so we emulate hover via CSS class toggle on click.
1416        $(selectors.toggle).on('click  touchstart', function (e) {
1417            e.preventDefault();
1418
1419            $(this).parents(selectors.wrapper).addClass(classes.expanded);
1420        });
1421
1422        // Hide shares on focus out.
1423        $('body').on('click touchstart', function (e) {
1424            var $activeElem = $(e.target).parents(selectors.expandedState);
1425
1426            // Collapse all expanded micro shares except active one.
1427            $(selectors.expandedState).not($activeElem).removeClass(classes.expanded);
1428        });
1429
1430        $('.snax-share-twitter').on('click', function (e) {
1431            e.preventDefault();
1432            window.open($(this).attr('href'), 'Google', 'width=500,height=300');
1433        });
1434        $('.snax-share-pinterest').on('click', function (e) {
1435            e.preventDefault();
1436            window.open($(this).attr('href'), 'Google', 'width=700,height=670');
1437        });
1438    };
1439
1440    // Fire.
1441    $(document).ready(function () {
1442        if (ctx.isTouchDevice()) {
1443            $('body').removeClass('snax-hoverable');
1444
1445        }
1446
1447        ctx.itemShare();
1448    });
1449
1450})(jQuery, snax);
1451
1452
1453/*************************
1454 *
1455 * Module: Delete Item
1456 *
1457 ************************/
1458
1459(function ($, ctx) {
1460
1461    'use strict';
1462
1463    /** CONFIG *******************************************/
1464
1465        // Register new component.
1466    ctx.deleteItemModule = {};
1467
1468    // Component namespace shortcut.
1469    var c = ctx.deleteItemModule;
1470
1471    // CSS selectors.
1472    var selectors = {
1473        'deleteLink':   '.snax-delete-item'
1474    };
1475
1476    var i18n = {
1477        'confirm':      'Are you sure?'
1478    };
1479
1480    // Allow accessing
1481    c.selectors = selectors;
1482    c.i18n      = i18n;
1483
1484    /** INIT *******************************************/
1485
1486    c.init = function () {
1487        c.attachEventHandlers();
1488    };
1489
1490    /** EVENTS *****************************************/
1491
1492    c.attachEventHandlers = function() {
1493
1494        /* Delete item */
1495
1496        $(selectors.deleteLink).on('click', function (e) {
1497            e.preventDefault();
1498
1499            if (!confirm(i18n.confirm)) {
1500                return;
1501            }
1502
1503            ctx.deleteItem($(this), function(res) {
1504                if (res.status === 'success') {
1505                    location.href = res.args.redirect_url;
1506                } else {
1507                    alert(res.message);
1508                }
1509            });
1510        });
1511    };
1512
1513    // Fire.
1514    $(document).ready(function () {
1515        c.init();
1516    });
1517
1518})(jQuery, snax);
1519
1520
1521/*******************************
1522 *
1523 * Module: Set Item as Featured
1524 *
1525 ******************************/
1526
1527(function ($, ctx) {
1528
1529    'use strict';
1530
1531    /** CONFIG *******************************************/
1532
1533    // Register new component.
1534    ctx.setItemAsFeaturedModule = {};
1535
1536    // Component namespace shortcut.
1537    var c = ctx.setItemAsFeaturedModule;
1538
1539    // CSS selectors.
1540    var selectors = {
1541        'link':   '.snax-set-item-as-featured'
1542    };
1543
1544    // Allow accessing
1545    c.selectors = selectors;
1546
1547    /** INIT *******************************************/
1548
1549    c.init = function () {
1550        c.attachEventHandlers();
1551    };
1552
1553    /** EVENTS *****************************************/
1554
1555    c.attachEventHandlers = function() {
1556
1557        /* Delete item */
1558
1559        $(selectors.link).on('click', function (e) {
1560            e.preventDefault();
1561
1562            ctx.setItemAsFeatured($(this), function(res) {
1563                if (res.status === 'success') {
1564                    location.reload();
1565                } else {
1566                    alert(res.message);
1567                }
1568            });
1569        });
1570    };
1571
1572    // Fire.
1573    $(document).ready(function () {
1574        c.init();
1575    });
1576
1577})(jQuery, snax);
1578
1579/*******************************
1580 *
1581 * Module: Froala for items
1582 *
1583 ******************************/
1584
1585(function ($, ctx) {
1586
1587    'use strict';
1588
1589    /** CONFIG *******************************************/
1590
1591    // Register new component.
1592    ctx.froalaSimple = {};
1593
1594    // Component namespace shortcut.
1595    var c = ctx.froalaSimple;
1596
1597    // CSS selectors.
1598    var selectors = {
1599        'froalaEditor':   '.froala-editor-simple'
1600    };
1601
1602    // Allow accessing
1603    c.selectors = selectors;
1604
1605    /** INIT *******************************************/
1606
1607    c.init = function () {
1608        c.attachEventHandlers();
1609        c.applyFroala();
1610    };
1611
1612    /** EVENTS *****************************************/
1613
1614    c.attachEventHandlers = function() {
1615        $( 'body' ).on( 'snaxNewCardAdded', function($card) {
1616            c.applyFroala();
1617        });
1618    };
1619
1620    c.renderFroala = function() {
1621        var $textarea = $(this);
1622        var config = {
1623            'key':              'CMFIZJNKLDXIREJI==',
1624            'language':         c.getFroalaEditorConfig('language'),
1625            'heightMin':        200,
1626            // Toolbar buttons on large devices (≥ 1200px).
1627            'toolbarButtons':   ['bold', 'italic', 'insertLink', '|', 'undo', 'redo'],
1628            // On medium devices (≥ 992px).
1629            toolbarButtonsMD:   ['bold', 'italic', 'insertLink', '|', 'undo', 'redo'],
1630            // On small devices (≥ 768px).
1631            toolbarButtonsSM:   ['bold', 'italic', 'insertLink', '|', 'undo', 'redo'],
1632            // On extra small devices (< 768px).
1633            toolbarButtonsXS:   ['bold', 'italic', 'insertLink', '|', 'undo', 'redo'],
1634            charCounterMax:     c.getFroalaEditorMaxCharacters($textarea)
1635        };
1636        // Override Froala's config using this filter function.
1637        if (typeof c.froalaEditorConfig === 'function') {
1638            config = c.froalaEditorConfig(config);
1639        }
1640        if (snax.inDebugMode()) {
1641            snax.log(config);
1642        }
1643        // Init.
1644        $textarea.froalaEditor(config);
1645    };
1646
1647    c.getFroalaEditorConfig = function(id) {
1648        var config = c.config.froala;
1649
1650        if (typeof config[id] !== 'undefined') {
1651            return config[id];
1652        }
1653
1654        return null;
1655    };
1656
1657    c.getFroalaEditorMaxCharacters = function($editor) {
1658        var maxCharacters = parseInt($editor.attr('maxlength'), 10);
1659
1660        return maxCharacters > 0 ? maxCharacters : -1;
1661    };
1662
1663    c.applyFroala = function () {
1664
1665        // Check if Froals script is loaded.
1666        if (!$.fn.froalaEditor) {
1667            return;
1668        }
1669        $(selectors.froalaEditor).each(c.renderFroala);
1670    };
1671
1672    // Fire.
1673    $(document).ready(function () {
1674        if (snax.frontendSubmission) {
1675            c.config = snax.frontendSubmission.config;
1676        }
1677        if (snax.post) {
1678            c.config = snax.post.config;
1679        }
1680        if (typeof c.config === 'undefined') {
1681            return;
1682        }
1683        c.init();
1684    });
1685
1686})(jQuery, snax);
1687
1688/*******************************
1689 *
1690 * Module: Single item comments
1691 *
1692 ******************************/
1693
1694(function ($, ctx) {
1695
1696    'use strict';
1697
1698    /** CONFIG *******************************************/
1699
1700    // Register new component.
1701    ctx.singleItemComments = {};
1702
1703    // Component namespace shortcut.
1704    var c = ctx.singleItemComments;
1705
1706    var seeMoreHtml = '<a class="snax-see-all-replies">' + ctx.config.i18n.see_all_replies + '</a>';
1707
1708    // CSS selectors.
1709    var selectors = {
1710        'section':              '.snax-item-comments',
1711        'topLevelComment':      '.snax-item-comments .depth-1',
1712        'moreCommentsLink':     '.snax-item-comments-more-link',
1713        'allRepliesLink':       '.snax-see-all-replies',
1714        'list':                 '.comment-list',
1715        'commentForm':          '.snax-item-comments .comment-form',
1716        'textarea':             '.snax-item-comments .comment-form textarea',
1717        'submitButton':         '.submit',
1718        'cancelReply':          '#cancel-comment-reply-link',
1719        'respondSection':       '#respond',
1720        'replyLogin':           '.comment-reply-login',
1721        'respondLogin':         '.snax-comment-login',
1722        'authorFields':         '.snax-item-comment-autor',
1723    };
1724
1725     var $spinner = $('<div class="snax-upload-icon"></div>');
1726
1727    // Allow accessing
1728    c.selectors = selectors;
1729
1730    /** INIT *******************************************/
1731
1732    c.init = function () {
1733        $(selectors.submitButton, selectors.commentForm).attr('disabled', true);
1734        c.renderSeeMore();
1735        c.attachEventHandlers();
1736    };
1737
1738    /** EVENTS *****************************************/
1739
1740    c.renderSeeMore = function() {
1741        $(selectors.topLevelComment).each(function( index ) {
1742            if($('.children li', this).length>1 && $(this).attr('appendedSeeMoreLink')!== 'true'){
1743               $(this).append(seeMoreHtml);
1744               $(this).attr('appendedSeeMoreLink','true');
1745            }
1746        });
1747        $(selectors.allRepliesLink).on('click', function (e) {
1748            var $parent         = $(this).closest(selectors.topLevelComment);
1749            $('.children', $parent).addClass('children-visible');
1750            $(this).remove();
1751        });
1752    };
1753
1754    //overrides core comment-reply.js to handle multiple forms
1755    c.overrideDefaultHandler = function() {
1756        if (typeof addComment === 'undefined') {
1757            return;
1758        }
1759
1760        addComment.moveForm = function( commId, parentId, respondId, postId ) {
1761                var div, element, style, cssHidden,
1762                    t           = this,
1763                    comm        = t.I( commId ),
1764                    respond     = t.I( respondId ),
1765                    cancel      = respond.querySelector( '#cancel-comment-reply-link' ),
1766                    parent      = respond.querySelector( '#comment_parent' ),
1767                    post        = respond.querySelector( '#comment_post_ID' ),
1768                    commentForm = respond.getElementsByTagName( 'form' )[0];
1769
1770                if ( ! comm || ! respond || ! cancel || ! parent || ! commentForm ) {
1771                    return;
1772                }
1773
1774                t.respondId = respondId;
1775                postId = postId || false;
1776
1777                if ( ! t.I( 'wp-temp-form-div' ) ) {
1778                    div = document.createElement( 'div' );
1779                    div.id = 'wp-temp-form-div';
1780                    div.style.display = 'none';
1781                    respond.parentNode.insertBefore( div, respond );
1782                }
1783
1784                comm.parentNode.insertBefore( respond, comm.nextSibling );
1785                if ( post && postId ) {
1786                    post.value = postId;
1787                }
1788                parent.value = parentId;
1789                cancel.style.display = '';
1790
1791                cancel.onclick = function() {
1792                    var t       = addComment,
1793                        temp    = t.I( 'wp-temp-form-div' ),
1794                        respond = t.I( t.respondId );
1795
1796                    if ( ! temp || ! respond ) {
1797                        return;
1798                    }
1799
1800                    parent.value = '0';
1801                    temp.parentNode.insertBefore( respond, temp );
1802                    temp.parentNode.removeChild( temp );
1803                    this.style.display = 'none';
1804                    this.onclick = null;
1805                    return false;
1806                };
1807
1808                /*
1809                * Set initial focus to the first form focusable element.
1810                * Try/catch used just to avoid errors in IE 7- which return visibility
1811                * 'inherit' when the visibility value is inherited from an ancestor.
1812                */
1813                try {
1814                    for ( var i = 0; i < commentForm.elements.length; i++ ) {
1815                        element = commentForm.elements[i];
1816                        cssHidden = false;
1817
1818                        // Modern browsers.
1819                        if ( 'getComputedStyle' in window ) {
1820                            style = window.getComputedStyle( element );
1821                        // IE 8.
1822                        } else if ( document.documentElement.currentStyle ) {
1823                            style = element.currentStyle;
1824                        }
1825
1826                        /*
1827                        * For display none, do the same thing jQuery does. For visibility,
1828                        * check the element computed style since browsers are already doing
1829                        * the job for us. In fact, the visibility computed style is the actual
1830                        * computed value and already takes into account the element ancestors.
1831                        */
1832                        if ( ( element.offsetWidth <= 0 && element.offsetHeight <= 0 ) || style.visibility === 'hidden' ) {
1833                            cssHidden = true;
1834                        }
1835
1836                        // Skip form elements that are hidden or disabled.
1837                        if ( 'hidden' === element.type || element.disabled || cssHidden ) {
1838                            continue;
1839                        }
1840
1841                        element.focus();
1842                        // Stop after the first focusable element.
1843                        break;
1844                    }
1845
1846                } catch( er ) {}
1847
1848                return false;
1849            };
1850
1851        addComment.I = function( id ) {
1852            return document.getElementById( id );
1853        };
1854    };
1855
1856    c.attachEventHandlers = function() {
1857
1858        var loadMoreComments = function($section) {
1859            var $that           = $(selectors.moreCommentsLink, $section);
1860            var postId          = $section.attr('data-snax-post-id');
1861            var loadedPages     = parseInt($section.attr('data-snax-loaded-pages'),10);
1862            var $list    = $(selectors.list, $section);
1863            var requestData     = {
1864                'action':           'snax_load_more_item_comments',
1865                'snax_item_id':     postId,
1866                'loaded_pages':     loadedPages
1867            };
1868
1869            $spinner.appendTo($list);
1870
1871            var xhr = $.ajax({
1872                'type':     'POST',
1873                'url':      ctx.config.ajax_url,
1874                'dataType': 'json',
1875                'data':     requestData
1876            });
1877
1878            xhr.done(function (res) {
1879                if ('success' === res.status) {
1880                    $spinner.remove();
1881                    if (res.args.html) {
1882                        $list.append(res.args.html);
1883                        removeDuplicateComments($list);
1884                        maybeRemoveSeeMoreLink($list,$that);
1885                        c.renderSeeMore();
1886                        $section.attr('data-snax-loaded-pages',loadedPages + 1);
1887
1888                        addComment.init();
1889                    }
1890                }
1891            });
1892        };
1893
1894        var removeDuplicateComments = function($list){
1895            var seen = {};
1896            $(selectors.topLevelComment, $list).each(function( index ) {
1897                    var id = $(this).attr('id');
1898                    if (seen[id]) {
1899                        $(this).remove();
1900                    } else {
1901                         seen[id] = true;
1902                    }
1903            });
1904        };
1905
1906        var maybeRemoveSeeMoreLink = function($list,$link){
1907            var topLevels = $('.depth-1', $list).length;
1908            var topLevelComments = parseInt( $list.attr('data-snax-top-level-comments'), 10 );
1909            if (topLevels >= topLevelComments){
1910                $link.remove();
1911            }
1912        };
1913
1914        $(selectors.moreCommentsLink).on('click', function (e) {
1915            e.preventDefault();
1916            var $section         = $(this).closest(selectors.section);
1917            loadMoreComments($section);
1918        });
1919
1920        $(selectors.commentForm).on('submit', function(e) {
1921            e.preventDefault();
1922            var $form           = $(this);
1923            var url             = $form.attr('action');
1924            var commentParent   = '0';
1925            var $textarea       = $('textarea', $form);
1926            var $section        = $form.closest(selectors.section);
1927            var $list           = $(selectors.list, $section);
1928            var $respondSection = $form.closest(selectors.respondSection);
1929            var $cancelButton   = $(selectors.cancelReply, $respondSection);
1930            var $submitButton   = $(selectors.submitButton, $form);
1931            var requestData = {};
1932
1933            $.each($form.serializeArray(), function(i, field) {
1934                requestData[field.name] = field.value;
1935            });
1936
1937            requestData['is_ajax_item_comment_form'] = true;
1938            commentParent = requestData['comment_parent'];
1939
1940            if (commentParent === '0') {
1941                $spinner.prependTo($list);
1942            } else {
1943                var $commentParent = $('#comment-' + commentParent);
1944                var $commentParentChildren = $('#comment-' + commentParent + '> .children');
1945                if (! $commentParentChildren.length) {
1946                    $commentParent.append('<ul class="children"></ul>');
1947                    $commentParentChildren = $('#comment-' + commentParent + '> .children');
1948                }
1949                $spinner.prependTo($commentParentChildren);
1950            }
1951
1952            var xhr = $.ajax({
1953                'type':     'POST',
1954                'url':      url,
1955                'data':     requestData
1956            });
1957
1958            xhr.done(function (res) {
1959                $textarea.val('');
1960                $cancelButton.trigger('click');
1961                $submitButton.attr('disabled', true);
1962                if (res.indexOf('<body id="error-page">') != -1){
1963                    res = $(res).filter('p')[1];
1964                }
1965                $spinner.replaceWith(res);
1966                if (commentParent !== '0') {
1967                    var $parent         = $commentParentChildren.closest(selectors.topLevelComment);
1968                    $('.children', $parent).addClass('children-visible');
1969                }
1970            });
1971
1972            xhr.fail(function( jqXHR, textStatus ) {
1973                if(jqXHR.status===409){
1974                    alert(ctx.config.i18n.duplicate_comment);
1975                }else{
1976                    alert(ctx.config.i18n.comment_fail);
1977                }
1978                $spinner.remove();
1979            });
1980        });
1981
1982        var validateForm = function( $form ) {
1983            var $submitButton   = $(selectors.submitButton, $form);
1984            var $author         = $(selectors.authorFields, $form);
1985            var $input          = $('textarea', $form);
1986            var disable         = false;
1987            if ( $author.length > 0 ){
1988                var $authorName = $('#author', $author);
1989                var $authorMail = $('#email', $author);
1990                if ( $authorName.val() === '' || $authorMail.val() === '' ) {
1991                    disable = true;
1992                }
1993            }
1994            if ($input.val() === '') {
1995                    disable = true;
1996                }
1997            $submitButton.attr('disabled', disable);
1998        };
1999
2000        $(selectors.textarea).keyup(function() {
2001            var $parent         = $(this).closest(selectors.commentForm);
2002            var $author         = $(selectors.authorFields, $parent);
2003            while($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css('borderTopWidth')) + parseFloat($(this).css('borderBottomWidth'))) {
2004                $(this).height($(this).height()+1);
2005            }
2006            if ($(this).val()){
2007                $author.show();
2008                $parent.removeClass('snax-comment-form-collapsed').addClass('snax-comment-form-extended');
2009            } else {
2010                $author.hide();
2011                $parent.removeClass('snax-comment-form-extended').addClass('snax-comment-form-collapsed');
2012            }
2013            validateForm($parent);
2014        });
2015
2016        $(selectors.authorFields).keyup(function() {
2017            var $parent         = $(this).closest(selectors.commentForm);
2018            validateForm($parent);
2019        });
2020
2021        $(selectors.replyLogin).click(function(e){
2022            e.preventDefault();
2023            ctx.loginRequired();
2024        });
2025        $(selectors.respondLogin).click(function(e){
2026            e.preventDefault();
2027            ctx.loginRequired();
2028        });
2029    };
2030
2031    // Fire.
2032    $(document).ready(function () {
2033        c.init();
2034        c.overrideDefaultHandler();
2035    });
2036
2037})(jQuery, snax);
2038
2039/*************************
2040 *
2041 * Module: Delete Post
2042 *
2043 ************************/
2044
2045(function ($, ctx) {
2046
2047    'use strict';
2048
2049    /** CONFIG *******************************************/
2050
2051        // Register new component.
2052    ctx.deletePostModule = {};
2053
2054    // Component namespace shortcut.
2055    var c = ctx.deletePostModule;
2056
2057    // CSS selectors.
2058    var selectors = {
2059        'deleteLink':   '.snax-delete-post'
2060    };
2061
2062    // Allow accessing
2063    c.selectors = selectors;
2064
2065    /** INIT *******************************************/
2066
2067    c.init = function () {
2068        c.attachEventHandlers();
2069    };
2070
2071    /** EVENTS *****************************************/
2072
2073    c.attachEventHandlers = function() {
2074
2075        /* Delete item */
2076
2077        $(selectors.deleteLink).on('click', function (e) {
2078            e.preventDefault();
2079            var $link = $(this);
2080
2081            if (!confirm(ctx.config.i18n.are_you_sure)) {
2082                return;
2083            }
2084
2085            var $item = $link.parents('.g1-collection-item');
2086
2087            if ( $item.length === 0 ) {
2088                var $item = $link.parents('article.post');
2089            }
2090
2091            $item.addClass('snax-post-removing');
2092
2093            ctx.deletePost($link, function(res) {
2094                if (res.status === 'success') {
2095                    var redirectUrl = $link.attr('href');
2096
2097                    // Redirect and show status note on top of a target page.
2098                    if (redirectUrl.length > 0) {
2099                        var queryVarDelimiter = redirectUrl.indexOf('?') === -1 ? '?' : '&';
2100
2101                        window.location.href = redirectUrl + queryVarDelimiter + ctx.config.delete_status_var + '=success';
2102                    // Remove DOM element and show notification.
2103                    } else {
2104                        $item.addClass('snax-post-removed');
2105                        $item.slideToggle(750);
2106
2107                        setTimeout(function() {
2108                            snax.notifications.add(res.message);
2109                        }, 1500);
2110                    }
2111
2112                } else {
2113                    ctx.notifications.add(res.message);
2114                }
2115            });
2116        });
2117    };
2118
2119    // Fire.
2120    $(document).ready(function () {
2121        c.init();
2122    });
2123
2124})(jQuery, snax);
2125
2126/*******************************
2127 *
2128 * Module: Password Reset
2129 *
2130 ******************************/
2131
2132(function ($, ctx) {
2133
2134    'use strict';
2135
2136    /** CONFIG *******************************************/
2137
2138    // Register new component.
2139    ctx.passwordReset = {};
2140
2141    // Component namespace shortcut.
2142    var c = ctx.passwordReset;
2143
2144    // CSS selectors.
2145    var selectors = {
2146        'resetPasswordForm':   '#snax_reset_password_form',
2147        'newPassword':          '#snax_reset_password_form #new_password',
2148        'repeatPassword':       '#snax_reset_password_form #repeat_password',
2149        'cookieName':           '#snax_reset_password_form .rp-cookie-name',
2150        'cookieValue':          '#snax_reset_password_form .rp-cookie_value',
2151        'resetErrorMessage':   '#snax_reset_password_form  .snax-reset-pass-error-message',
2152        'resetSuccessMessage': '#snax_reset_password_form  .snax-reset-pass-success-message',
2153    };
2154
2155    // Allow accessing
2156    c.selectors = selectors;
2157
2158    /** INIT *******************************************/
2159
2160    c.init = function () {
2161        c.attachEventHandlers();
2162    };
2163
2164    /** EVENTS *****************************************/
2165
2166    c.attachEventHandlers = function() {
2167        c.matchPasswords();
2168        c.handleForm();
2169    };
2170
2171    c.matchPasswords = function() {
2172            var $newPassword    = $(selectors.newPassword),
2173                $repeatPassword = $(selectors.repeatPassword);
2174
2175            $repeatPassword.on('change', function(e) {
2176                if ($newPassword.val() !== $repeatPassword.val()){
2177                    $repeatPassword.get(0).setCustomValidity( ctx.config.i18n.passwords_dont_match);
2178                } else {
2179                    $repeatPassword.get(0).setCustomValidity('');
2180                }
2181            });
2182    }
2183
2184    c.handleForm = function() {
2185        var $form           = $(selectors.resetPasswordForm),
2186            $cookieName     = $(selectors.cookieName),
2187            $cookieValue    = $(selectors.cookieValue),
2188            $newPassword    = $(selectors.newPassword),
2189            $errorMessage   = $(selectors.resetErrorMessage),
2190            $successMessage = $(selectors.resetSuccessMessage);
2191
2192        $form.on('submit', function(e) {
2193
2194            e.preventDefault();
2195            e.stopPropagation();
2196            e.stopImmediatePropagation();
2197
2198            $errorMessage.text('');
2199            $successMessage.text('');
2200
2201            ctx.createCookie($cookieName.val(), $cookieValue.val(), 24);
2202
2203            var xhr = $.ajax({
2204                'type':     'POST',
2205                'url':      $form.attr('action') + '?action=resetpass',
2206                'data':     $form.serialize(),
2207            });
2208
2209            xhr.done(function (res) {
2210                if ($('.reset-pass', res).length){
2211                    $successMessage.html( '<p class="snax-validation-tip">' + ctx.config.i18n.password_set + '</p>' );
2212                }
2213                if ($('#login_error', res).length){
2214                    $errorMessage.html( '<p class="snax-validation-tip">' + ctx.config.i18n.link_invalid + '</p>' );
2215                }
2216            });
2217
2218            return false;
2219        });
2220    };
2221
2222    // Fire.
2223    $(document).ready(function () {
2224        if ($(selectors.resetPasswordForm).length){
2225            c.init();
2226        }
2227    });
2228
2229})(jQuery, snax);
2230
2231/*******************************
2232 *
2233 * Module: BuddyPress registration captcha
2234 *
2235 ******************************/
2236
2237(function ($, ctx) {
2238
2239    'use strict';
2240
2241    var useReCaptcha;
2242    var reCaptchaToken;
2243
2244    ctx.registerForm = function () {
2245        useReCaptcha = ctx.config.use_login_recaptcha;
2246        if (useReCaptcha && $('#buddypress #register-page').length >0) {
2247            loadReCaptcha();
2248            $('#signup_submit').attr('disabled', true);
2249        }
2250    };
2251
2252    var loadReCaptcha = function() {
2253        var apiUrl  = ctx.config.recaptcha_api_url;
2254        var ver     = ctx.config.recaptcha_version;
2255        var siteKey = ctx.config.recaptcha_site_key;
2256
2257        if (!siteKey || !apiUrl) {
2258            return;
2259        }
2260
2261        var renderLoginReCaptcha = function() {
2262            if ('30' === ver) {
2263                grecaptcha.execute(
2264                    siteKey,
2265                    { action: 'login' }
2266                ).then( function( token ) {
2267                        $('#snax-register-recaptcha').html('<input type="hidden" name="g-recaptcha-response" value="'+ token +'">');
2268                        reCaptchaEnteredCorrectly(token);
2269                    } );
2270            } else {
2271                grecaptcha.render('snax-register-recaptcha', {
2272                    'sitekey' : siteKey,
2273                    'callback': reCaptchaEnteredCorrectly
2274                });
2275            }
2276        };
2277
2278        // Google reCaptcha API loaded.
2279        if (typeof grecaptcha !== 'undefined') {
2280            renderLoginReCaptcha();
2281        } else {
2282            // API not loaded. Register callback and load script.
2283            window.snaxReCaptchaOnloadCallback = function() {
2284                renderLoginReCaptcha();
2285            };
2286
2287            if ('30' === ver) {
2288                $('head').append('<script src="' + apiUrl + '?onload=snaxReCaptchaOnloadCallback&render='+siteKey+'" async defer>');
2289            } else {
2290                $('head').append('<script src="' + apiUrl + '?onload=snaxReCaptchaOnloadCallback&render=explicit" async defer>');
2291            }
2292        }
2293    };
2294
2295    var reCaptchaEnteredCorrectly = function(response) {
2296        reCaptchaToken = response;
2297        $('#signup_submit').attr('disabled', false);
2298    };
2299
2300    // Fire.
2301    $(document).ready(function () {
2302        ctx.registerForm();
2303    });
2304
2305})(jQuery, snax);
2306
2307/*******************************
2308 *
2309 * Module: Notifications
2310 *
2311 ******************************/
2312
2313(function ($, ctx) {
2314
2315    'use strict';
2316
2317    var api              = {};      // Public API.
2318    var timeout          = 5000;
2319    var $notifications   = false;
2320    var $notificationTpl = false;
2321
2322    var selectors = {
2323        'notifications':    '.snax-notifications',
2324        'notification':     '.snax-notification',
2325        'notificationText': '.snax-notification-text',
2326        'notificationClose':'.snax-notification-close'
2327    };
2328
2329    var classes = {
2330        'on':   'snax-notifications-on',
2331        'off':  'snax-notifications-off',
2332    };
2333
2334    api.add = function(html) {
2335        var $notification = $notificationTpl.clone(true);
2336        $notification.find(selectors.notificationText).html(html);
2337
2338        $notification.on('click', selectors.notificationClose, function() {
2339            api.remove($notification);
2340        });
2341
2342        // Auto-remove.
2343        setTimeout(function() {
2344            api.remove($notification);
2345        }, timeout);
2346
2347        $notifications.prepend($notification);
2348        $notifications.removeClass(classes.off).addClass(classes.on);
2349    };
2350
2351    api.remove = function($notification) {
2352        $notification.addClass('snax-notification-removed');
2353        setTimeout(function() {
2354            $notification.remove();
2355
2356            if (api.isQueueEmpty()) {
2357                $notifications.removeClass(classes.on).addClass(classe
2357s.off);
2358            }
2359        }, 5000);
2360    };
2361
2362    api.isQueueEmpty = function() {
2363        return $notifications.find(selectors.notification).length === 0;
2364    };
2365
2366    var initNotifications = function() {
2367        $notifications = $(selectors.notifications);
2368
2369        if ($notifications.length === 0) {
2370            return;
2371        }
2372
2373        // Store notification template and rmeove it from DOM.
2374        $notificationTpl = $notifications.find(selectors.notification).detach();
2375
2376        // Enable API.
2377        ctx.notifications = api;
2378    };
2379
2380    // Fire.
2381    $(document).ready(function () {
2382        initNotifications();
2383    });
2384
2385})(jQuery, snax);
2386
2387/********************************
2388 *
2389 * Social Login GDPR integration
2390 *
2391 *******************************/
2392
2393(function ($) {
2394
2395    'use strict';
2396
2397    $(document).ready(function () {
2398        $('.snax-gdpr-consent-form').each(function() {
2399            var $form = $(this);
2400            var $links = $form.parent().find('.snax-social-login-links');
2401            var $link;  // A requested social login link.
2402
2403            // Toggle GDPR and Social Links visibility.
2404            var toggleVisiblity = function() {
2405                $form.toggleClass('snax-gdpr-consent-form-hidden snax-gdpr-consent-form-visible');
2406                $links.toggleClass('snax-social-login-links-visible snax-social-login-links-hidden');
2407            };
2408
2409            // Social login link requested.
2410            $links.on('click', 'a.snax-social-login', function(e) {
2411                e.preventDefault();
2412
2413                $link = $(this);
2414
2415                toggleVisiblity();
2416            });
2417
2418            // Accept GDPR.
2419            $form.on('click', '.snax-slog-gdpr-accept', function(e) {
2420                e.preventDefault();
2421
2422                window.location.href = $link.attr('href');
2423            });
2424
2425            // Cancel GDPR.
2426            $form.on('click', '.snax-slog-gdpr-cancel', function(e) {
2427                e.preventDefault();
2428
2429                toggleVisiblity();
2430            });
2431        });
2432    });
2433
2434})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.