....................................../////.===Shadow-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 51.91.236.193  /  Your IP : 216.73.216.177
Web Server : Apache
System : Linux webm019.cluster128.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User : thillelirn ( 8290)
PHP Version : 8.0.30
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/thillelirn/www/wp-content/plugins/imagify/_dev/src/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/thillelirn/www/wp-content/plugins/imagify/_dev/src/bulk.js
window.imagify = window.imagify || {};

(function( $, undefined ) { // eslint-disable-line no-shadow, no-shadow-restricted-names

    var jqPropHookChecked = $.propHooks.checked;

    // Force `.prop()` to trigger a `change` event.
    $.propHooks.checked = {
        set: function( elem, value, name ) {
            var ret;

            if ( undefined === jqPropHookChecked ) {
                ret = ( elem[ name ] = value );
            } else {
                ret = jqPropHookChecked( elem, value, name );
            }

            $( elem ).trigger( 'change.imagify' );

            return ret;
        }
    };

    // Custom jQuery functions =====================================================================
    /**
     * Hide element(s).
     *
     * @param  {int}      duration A duration in ms.
     * @param  {function} callback A callback to execute once the element is hidden.
     * @return {element}  The jQuery element(s).
     */
    $.fn.imagifyHide = function( duration, callback ) {
        if ( duration && duration > 0 ) {
            this.hide( duration, function() {
                $( this ).addClass( 'hidden' ).css( 'display', '' );

                if ( undefined !== callback ) {
                    callback();
                }
            } );
        } else {
            this.addClass( 'hidden' );

            if ( undefined !== callback ) {
                callback();
            }
        }

        return this.attr( 'aria-hidden', 'true' );
    };

    /**
     * Show element(s).
     *
     * @param  {int}      duration A duration in ms.
     * @param  {function} callback A callback to execute before starting to display the element.
     * @return {element} The jQuery element(s).
     */
    $.fn.imagifyShow = function( duration, callback ) {
        if ( undefined !== callback ) {
            callback();
        }

        if ( duration && duration > 0 ) {
            this.show( duration, function() {
                $( this ).removeClass( 'hidden' ).css( 'display', '' );
            } );
        } else {
            this.removeClass( 'hidden' );
        }

        return this.attr( 'aria-hidden', 'false' );
    };

}( jQuery ));

(function($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names

    w.imagify.bulk = {

        // Properties ==============================================================================
        charts: {
            overview: {
                canvas: false,
                donut:  false,
                data:   {
                    // Order: unoptimized, optimized, error.
                    labels: [
                        imagifyBulk.labels.overviewChartLabels.unoptimized,
                        imagifyBulk.labels.overviewChartLabels.optimized,
                        imagifyBulk.labels.overviewChartLabels.error
                    ],
                    datasets: [ {
                        data:            [],
                        backgroundColor: [ '#10121A', '#46B1CE', '#C51162' ],
                        borderWidth:     0
                    } ]
                }
            },
            files: {
                donuts: {}
            },
            share: {
                canvas: false,
                donut:  false
            }
        },
        /**
         * Folder types in queue.
         * An array of objects: {
         *     @type {string} groupID The group ID, like 'library'.
         *     @type {string} context The context, like 'wp'.
         *     @type {int}    level   The optimization level: 0, 1, or 2.
         * }
         */
        folderTypesQueue:     [],
        /**
         * Status of each folder type. Type IDs are used as keys.
         * Each object contains: {
         *     @type {bool}   isError Tell if the status is considered as an error.
         *     @type {string} id      ID of the status, like 'waiting', 'fetching', or 'optimizing'.
         * }
         */
        status:               {},
        // Tell if the message displayed when retrieving the image IDs has been shown once.
        displayedWaitMessage: false,
        // Tell how many rows are available.
        hasMultipleRows:      true,
        // Set to true to stop the whole thing.
        processIsStopped:     false,
        // Global stats.
        globalOptimizedCount: 0,
        globalGain:           0,
        globalOriginalSize:   0,
        globalOptimizedSize:  0,
        /**
         * Folder types used in the page.
         *
         * @var {object} {
         *     An object of objects. The keys are like: {groupID|context}.
         *
         *     @type {string} groupID The group ID.
         *     @type {string} context The context.
         * }
         */
        folderTypesData:      {},

        // Methods =================================================================================

        /*
         * Init.
         */
        init: function () {
            var $document = $( d );

            // Overview chart.
            this.drawOverviewChart();

            this.hasMultipleRows = $( '.imagify-bulk-table [name="group[]"]' ).length > 1;

            // Selectors (like the level selectors).
            $( '.imagify-selector-button' )
                .on( 'click.imagify', this.openSelectorFromButton );

            $( '.imagify-selector-list input' )
                .on( 'change.imagify init.imagify', this.syncSelectorFromRadio )
                .filter( ':checked' )
                .trigger( 'init.imagify' );

            $document
                .on( 'keypress.imagify click.imagify', this.closeSelectors );

            // Other buttons/UI.
            $( '.imagify-bulk-table [name="group[]"]' )
                .on( 'change.imagify init.imagify', this.toggleOptimizationButton )
                .trigger( 'init.imagify' );

            $( '#imagify-bulk-action' )
                .on( 'click.imagify', this.maybeLaunchAllProcesses );

            // Optimization events.
            $( w )
                .on( 'processQueue.imagify', this.processQueue )
                .on( 'queueEmpty.imagify', this.queueEmpty );

            if ( imagifyBulk.ajaxActions.getStats && $( '.imagify-bulk-table [data-group-id="library"][data-context="wp"]' ).length ) {
                // On large WP library, don't request stats periodically, only when everything is done.
                imagifyBulk.imagifybeatIDs.stats = false;
            }

            if ( imagifyBulk.imagifybeatIDs.stats ) {
                // Imagifybeat for stats.
                $document
                    .on( 'imagifybeat-send', this.addStatsImagifybeat )
                    .on( 'imagifybeat-tick', this.processStatsImagifybeat );
            }

            // Imagifybeat for optimization queue.
            $document
                .on( 'imagifybeat-send', this.addQueueImagifybeat )
                .on( 'imagifybeat-tick', this.processQueueImagifybeat );

            // Imagifybeat for requirements.
            $document
                .on( 'imagifybeat-send', this.addRequirementsImagifybeat )
                .on( 'imagifybeat-tick', this.processRequirementsImagifybeat );

            if ( imagifyBulk.optimizing ) {
                // Fasten Imagifybeat: 1 tick every 15 seconds, and disable suspend.
                w.imagify.beat.interval( 15 );
                w.imagify.beat.disableSuspend();
            }
        },

        /*
         * Get the URL used for ajax requests.
         *
         * @param  {string} action An ajax action, or part of it.
         * @param  {object} item   The current item.
         * @return {string}
         */
        getAjaxUrl: function ( action, item ) {
            var url = ajaxurl + w.imagify.concat + '_wpnonce=' + imagifyBulk.ajaxNonce + '&action=' + imagifyBulk.ajaxActions[ action ];

            if ( item && item.context ) {
                url += '&context=' + item.context;
            }

            if ( item && Number.isInteger( item.level ) ) {
                url += '&optimization_level=' + item.level;
            }

            return url;
        },

        /**
         * Get folder types used in the page.
         *
         * @see    this.folderTypesData
         * @return {object}
         */
        getFolderTypes: function () {
            if ( ! $.isEmptyObject( w.imagify.bulk.folderTypesData ) ) {
                return w.imagify.bulk.folderTypesData;
            }

            $( '.imagify-row-folder-type' ).each( function() {
                var $this = $( this ),
                    data  = {
                        groupID: $this.data( 'group-id' ),
                        context: $this.data( 'context' ),
                        level:   $this.find( '.imagify-cell-level [name="level[' + $this.data( 'group-id' ) + ']"]:checked' ).val()
                    },
                    key   = data.groupID + '|' + data.context;

                w.imagify.bulk.folderTypesData[ key ] = data;
            } );

            return w.imagify.bulk.folderTypesData;
        },

        /*
         * Get the message displayed to the user when (s)he leaves the page.
         *
         * @return {string}
         */
        getConfirmMessage: function () {
            return imagifyBulk.labels.processing;
        },

        /*
         * Close the given optimization level selector.
         *
         * @param {object} $lists A jQuery object.
         * @param {int}    timer  Timer in ms to close the selector.
         */
        closeLevelSelector: function ( $lists, timer ) {
            if ( ! $lists || ! $lists.length ) {
                return;
            }

            if ( undefined !== timer && timer > 0 ) {
                w.setTimeout( function() {
                    w.imagify.bulk.closeLevelSelector( $lists );
                }, timer );
                return;
            }

            $lists.attr( 'aria-hidden', 'true' );
        },

        /*
         * Stop everything and update the current item status as an error.
         *
         * @param {string} errorId An error ID.
         * @param {object} item    The current item.
         */
        stopProcess: function ( errorId, item ) {
            w.imagify.bulk.processIsStopped = true;

            w.imagify.bulk.status[ item.groupID ] = {
                isError: true,
                id:      errorId
            };

            $( w ).trigger( 'queueEmpty.imagify' );
        },

        /*
         * Tell if we have a blocking error. Can also display an error message in a swal.
         *
         * @param  {bool} displayErrorMessage False to not display any error message.
         * @return {bool}
         */
        hasBlockingError: function ( displayErrorMessage ) {
            displayErrorMessage = undefined !== displayErrorMessage && displayErrorMessage;

            if ( imagifyBulk.curlMissing ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        html: imagifyBulk.labels.curlMissing
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            if ( imagifyBulk.editorMissing ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        html: imagifyBulk.labels.editorMissing
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            if ( imagifyBulk.extHttpBlocked ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        html: imagifyBulk.labels.extHttpBlocked
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            if ( imagifyBulk.apiDown ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        html: imagifyBulk.labels.apiDown
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            if ( ! imagifyBulk.keyIsValid ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        title: imagifyBulk.labels.invalidAPIKeyTitle,
                        type:  'info'
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            if ( imagifyBulk.isOverQuota ) {
                if ( displayErrorMessage ) {
                    w.imagify.bulk.displayError( {
                        title:             imagifyBulk.labels.overQuotaTitle,
                        html:              $( '#tmpl-imagify-overquota-alert' ).html(),
                        type:              'info',
                        customClass:       'imagify-swal-has-subtitle imagify-swal-error-header',
                        showConfirmButton: false
                    } );
                }

                w.imagify.bulk.processIsStopped = true;

                return true;
            }

            return false;
        },

        /*
         * Display an error message in a modal.
         *
         * @param {string} title The modal title.
         * @param {string} text  The modal text.
         * @param {object} args  Other less common args.
         */
        displayError: function ( title, text, args ) {
            var def = {
                title:             '',
                html:              '',
                type:              'error',
                customClass:       '',
                width:             620,
                padding:           0,
                showCloseButton:   true,
                showConfirmButton: true
            };

            if ( $.isPlainObject( title ) ) {
                args = $.extend( {}, def, title );
            } else {
                args = args || {};
                args = $.extend( {}, def, {
                    title: title || '',
                    html:  text  || ''
                }, args );
            }

            args.title        = args.title || imagifyBulk.labels.error;
            args.customClass += ' imagify-sweet-alert';

            swal( args ).catch( swal.noop );
        },

        /*
         * Display the share box.
         */
        displayShareBox: function () {
            var $complete, globalSaved;

            if ( ! this.globalGain || this.folderTypesQueue.length ) {
                this.globalOptimizedCount = 0;
                this.globalGain           = 0;
                this.globalOriginalSize   = 0;
                this.globalOptimizedSize  = 0;
                return;
            }

            globalSaved = this.globalOriginalSize - this.globalOptimizedSize;

            $complete = $( '.imagify-row-complete' );
            $complete.find( '.imagify-ac-rt-total-images' ).html( this.globalOptimizedCount );
            $complete.find( '.imagify-ac-rt-total-gain' ).html( w.imagify.humanSize( globalSaved, 1 ) );
            $complete.find( '.imagify-ac-rt-total-original' ).html( w.imagify.humanSize( this.globalOriginalSize, 1 ) );
            $complete.find( '.imagify-ac-chart' ).attr( 'data-percent', Math.round( this.globalGain ) );

            // Chart.
            this.drawShareChart();

            $complete.addClass( 'done' ).imagifyShow();

            $( 'html, body' ).animate( {
                scrollTop: $complete.offset().top
            }, 200 );

            // Reset the stats.
            this.globalOptimizedCount = 0;
            this.globalGain           = 0;
            this.globalOriginalSize   = 0;
            this.globalOptimizedSize  = 0;
        },

        /**
         * Print optimization stats.
         *
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        updateStats: function ( data ) {
            var donutData;

            if ( ! data || ! $.isPlainObject( data ) ) {
                return;
            }

            if ( w.imagify.bulk.charts.overview.donut.data ) {
                donutData = w.imagify.bulk.charts.overview.donut.data.datasets[0].data;

                if ( data.unoptimized_attachments === donutData[0] && data.optimized_attachments === donutData[1] && data.errors_attachments === donutData[2] ) {
                    return;
                }
            }

            /**
             * User account.
             */
            data.unconsumed_quota = data.unconsumed_quota.toFixed( 1 ); // A mystery where a float rounded on php side is not rounded here anymore. JavaScript is fun, it always surprises you in a manner you didn't expect.
            $( '.imagify-meteo-icon' ).html( data.quota_icon );
            $( '.imagify-unconsumed-percent' ).html( data.unconsumed_quota + '%' );
            $( '.imagify-unconsumed-bar' ).css( 'width', data.unconsumed_quota + '%' ).parent().attr( 'class', data.quota_class );

            /**
             * Global chart.
             */
            $( '#imagify-overview-chart-percent' ).html( data.optimized_attachments_percent + '<span>%</span>' );
            $( '.imagify-total-percent' ).html( data.optimized_attachments_percent + '%' );

            w.imagify.bulk.drawOverviewChart( [
                data.unoptimized_attachments,
                data.optimized_attachments,
                data.errors_attachments
            ] );

            /**
             * Stats block.
             */
            // The total optimized images.
            $( '#imagify-total-optimized-attachments' ).html( data.already_optimized_attachments );

            // The original bar.
            $( '#imagify-original-bar' ).find( '.imagify-barnb' ).html( data.original_human );

            // The optimized bar.
            $( '#imagify-optimized-bar' ).css( 'width', ( 100 - data.optimized_percent ) + '%' ).find( '.imagify-barnb' ).html( data.optimized_human );

            // The Percent data.
            $( '#imagify-total-optimized-attachments-pct' ).html( data.optimized_percent + '%' );
        },

        // Event callbacks =========================================================================

        /*
         * Selector (like optimization level selector): on button click, open the dropdown and focus the current radio input.
         * The dropdown must be open or the focus event won't be triggered.
         *
         * @param {object} e jQuery's Event object.
         */
        openSelectorFromButton: function ( e ) {
            var $list = $( '#' + $( this ).attr( 'aria-controls' ) );
            // Stop click event from bubbling: this will allow to close the selector list if anything else id clicked.
            e.stopPropagation();
            // Close other lists.
            $( '.imagify-selector-list' ).not( $list ).attr( 'aria-hidden', 'true' );
            // Open the corresponding list and focus the radio.
            $list.attr( 'aria-hidden', 'false' ).find( ':checked' ).trigger( 'focus.imagify' );
        },

        /*
         * Selector: on radio change, make the row "current" and update the button text.
         */
        syncSelectorFromRadio: function () {
            var $row = $( this ).closest( '.imagify-selector-choice' );
            // Update rows attributes.
            $row.addClass( 'imagify-selector-current-value' ).attr( 'aria-current', 'true' ).siblings( '.imagify-selector-choice' ).removeClass( 'imagify-selector-current-value' ).attr( 'aria-current', 'false' );
            // Change the button text.
            $row.closest( '.imagify-selector-list' ).siblings( '.imagify-selector-button' ).find( '.imagify-selector-current-value-info' ).html( $row.find( 'label' ).html() );
        },

        /*
         * Selector: on Escape or Enter kaystroke, close the dropdown.
         *
         * @param {object} e jQuery's Event object.
         */
        closeSelectors: function ( e ) {
            if ( 'keypress' === e.type && 27 !== e.keyCode && 13 !== e.keyCode ) {
                return;
            }
            w.imagify.bulk.closeLevelSelector( $( '.imagify-selector-list[aria-hidden="false"]' ) );
        },

        /*
         * Enable or disable the Optimization button depending on the checked checkboxes.
         * Also, if there is only 1 checkbox in the page, don't allow it to be unchecked.
         */
        toggleOptimizationButton: function () {
            // Prevent uncheck if there is only one checkbox.
            if ( ! w.imagify.bulk.hasMultipleRows && ! this.checked ) {
                $( this ).prop( 'checked', true );
                return;
            }

            if ( imagifyBulk.optimizing ) {
                $( '#imagify-bulk-action' ).prop( 'disabled', true );

                return;
            }

            // Enable or disable the Optimization button.
            if ( $( '.imagify-bulk-table [name="group[]"]:checked' ).length ) {
                $( '#imagify-bulk-action' ).prop( 'disabled', false );
            } else {
                $( '#imagify-bulk-action' ).prop( 'disabled', true );
            }
        },

        /*
         * Maybe display a modal, then launch all processes.
         */
        maybeLaunchAllProcesses: function () {
            var $infosModal;

            if ( $( this ).prop('disabled') ) {
                return;
            }

            if ( ! $( '.imagify-bulk-table [name="group[]"]:checked' ).length ) {
                return;
            }

            if ( w.imagify.bulk.hasBlockingError( true ) ) {
                return;
            }

            $infosModal = $( '#tmpl-imagify-bulk-infos' );

            if ( ! $infosModal.length ) {
                w.imagify.bulk.launchAllProcesses();
                return;
            }

            // Swal Information before loading the optimize process.
            swal( {
                title:             imagifyBulk.labels.bulkInfoTitle,
                html:              $infosModal.html(),
                type:              '',
                customClass:       'imagify-sweet-alert imagify-swal-has-subtitle imagify-before-bulk-infos',
                showCancelButton:  true,
                padding:           0,
                width:             554,
                confirmButtonText: imagifyBulk.labels.confirmBulk,
                cancelButtonText:  imagifySwal.labels.cancelButtonText,
                reverseButtons:    true
            } ).then( function() {
                var $row = $( '.imagify-bulk-table [name="group[]"]:checked' ).first().closest( '.imagify-row-folder-type' );

                $.get( w.imagify.bulk.getAjaxUrl( 'bulkInfoSeen', {
                    context: $row.data( 'context' )
                } ) );

                $infosModal.remove();

                w.imagify.bulk.launchAllProcesses();
            } ).catch( swal.noop );
        },

        /*
         * Build the queue and launch all processes.
         */
        launchAllProcesses: function () {
            var $w      = $( w ),
                $button = $( '#imagify-bulk-action' );

            // Disable the button.
            $button.prop( 'disabled', true ).find( '.dashicons' ).addClass( 'rotate' );

            // Hide the "Complete" message.
            $( '.imagify-row-complete' ).imagifyHide( 200, function() {
                $( this ).removeClass( 'done' );
            } );

            // Make sure to reset properties.
            this.folderTypesQueue     = [];
            this.status               = {};
            this.displayedWaitMessage = false;
            this.processIsStopped     = false;
            this.globalOptimizedCount = 0;
            this.globalGain           = 0;
            this.globalOriginalSize   = 0;
            this.globalOptimizedSize  = 0;

            $( '.imagify-bulk-table [name="group[]"]:checked' ).each( function() {
                var $checkbox = $( this ),
                    $row      = $checkbox.closest( '.imagify-row-folder-type' ),
                    groupID   = $row.data( 'group-id' ),
                    context   = $row.data( 'context' ),
                    level     = $row.find( '.imagify-cell-level [name="level[' + groupID + ']"]:checked' ).val();

                // Build the queue.
                w.imagify.bulk.folderTypesQueue.push( {
                    groupID: groupID,
                    context: context,
                    level:   undefined === level ? -1 : parseInt( level, 10 )
                } );

                // Set the status.
                w.imagify.bulk.status[ groupID ] = {
                    isError: false,
                    id:      'waiting'
                };
            } );

            // Fasten Imagifybeat: 1 tick every 15 seconds, and disable suspend.
            w.imagify.beat.interval( 15 );
            w.imagify.beat.disableSuspend();

            // Process the queue.
            $w.trigger( 'processQueue.imagify' );
        },

        /*
         * Process the first item in the queue.
         */
        processQueue: function () {
            var $row, $table, $progressBar, $progress;

            if ( w.imagify.bulk.processIsStopped ) {
                return;
            }

            if ( ! w.imagify.bulk.displayedWaitMessage ) {
                // Display an alert to wait.
                swal( {
                    title:             imagifyBulk.labels.waitTitle,
                    html:              imagifyBulk.labels.waitText,
                    showConfirmButton: false,
                    padding:           0,
                    imageUrl:          imagifyBulk.waitImageUrl,
                    customClass:       'imagify-sweet-alert'
                } ).catch( swal.noop );
                w.imagify.bulk.displayedWaitMessage = true;
            }

            w.imagify.bulk.folderTypesQueue.forEach( function( item ) {
                // Start async process for current context
                $.get( w.imagify.bulk.getAjaxUrl( 'bulkProcess', item ) )
                    .done( function( response ) {
                        var errorMessage;

                        swal.close();

                        if ( response.data && response.data.message ) {
                            errorMessage = response.data.message;
                        } else {
                            errorMessage = imagifyBulk.ajaxErrorText;
                        }

                        if ( ! response.success ) {
                            // Error.
                            w.imagify.bulk.stopProcess( errorMessage, item );
                            return;
                        }

                        if ( ! response.data || ! ( $.isPlainObject( response.data ) || $.isArray( response.data ) ) ) {
                            // Error: should be an array if empty, or an object otherwize.
                            w.imagify.bulk.stopProcess( errorMessage, item );
                            return;
                        }

                        // Success.
                        if ( response.success ) {
                            $row         = $( '#cb-select-' + item.groupID ).closest( '.imagify-row-folder-type' );
                            $table       = $row.closest( '.imagify-bulk-table' );
                            $progressBar = $table.find( '.imagify-row-progress' );
                            $progress    = $progressBar.find( '.bar' );

                            $row.find( '.imagify-cell-checkbox-loader' ).removeClass( 'hidden' ).attr( 'aria-hidden', 'false' );
                            $row.find( '.imagify-cell-checkbox-box' ).addClass( 'hidden' ).attr( 'aria-hidden', 'true' );

                            // Reset and display the progress bar.
                            $progress.css( 'width', '0%' ).find( '.percent' ).text( '0%' );
                            $progressBar.slideDown().attr( 'aria-hidden', 'false' );
                        }
                    } )
                    .fail( function() {
                        // Error.
                        w.imagify.bulk.stopProcess( 'get-unoptimized-images', item );
                    } );
            } );
        },

        /*
         * End.
         */
        queueEmpty: function () {
            var $tables   = $( '.imagify-bulk-table' ),
                errorArgs = {},
                hasError  = false,
                noImages  = true,
                errorMsg  = '';

            // Reset Imagifybeat interval and enable suspend.
            w.imagify.beat.resetInterval();
            w.imagify.beat.enableSuspend();

            // Reset the queue.
            w.imagify.bulk.folderTypesQueue = [];

            // Display the share box.
            w.imagify.bulk.displayShareBox();

            // Fetch and display generic stats if stats via Imagifybeat are disabled.
            if ( ! imagifyBulk.imagifybeatIDs.stats ) {
                $.get( w.imagify.bulk.getAjaxUrl( 'getStats' ), {
                    types: w.imagify.bulk.getFolderTypes()
                } )
                    .done( function( response ) {
                        if ( response.success ) {
                            w.imagify.bulk.updateStats( response.data );
                        }
                    } );
            }

            // Maybe display error.
            if ( ! $.isEmptyObject( w.imagify.bulk.status ) ) {
                $.each( w.imagify.bulk.status, function( groupID, typeStatus ) {
                    if ( ! typeStatus.isError ) {
                        noImages = false;
                    } else if ( 'no-images' !== typeStatus.id && typeStatus.isError ) {
                        hasError = typeStatus.id;
                        noImages = false;
                        return false;
                    }
                } );

                if ( hasError ) {
                    if ( 'invalid-api-key' === hasError ) {
                        errorArgs = {
                            title: imagifyBulk.labels.invalidAPIKeyTitle,
                            type:  'info'
                        };
                    }
                    else if ( 'over-quota' === hasError ) {
                        errorArgs = {
                            title:             imagifyBulk.labels.overQuotaTitle,
                            html:              $( '#tmpl-imagify-overquota-alert' ).html(),
                            type:              'info',
                            customClass:       'imagify-swal-has-subtitle imagify-swal-error-header',
                            showConfirmButton: false
                        };
                    }
                    else if ( 'get-unoptimized-images' === hasError || 'consumed-all-data' === hasError ) {
                        errorArgs = {
                            title: imagifyBulk.labels.getUnoptimizedImagesErrorTitle,
                            html:  imagifyBulk.labels.getUnoptimizedImagesErrorText,
                            type:  'info'
                        };
                    }
                    w.imagify.bulk.displayError( errorArgs );
                }
                else if ( noImages ) {
                    if ( Object.prototype.hasOwnProperty.call( imagifyBulk.labels.nothingToDoText, w.imagify.bulk.imagifyAction ) ) {
                        errorMsg = imagifyBulk.labels.nothingToDoText[ w.imagify.bulk.imagifyAction ];
                    } else {
                        errorMsg = imagifyBulk.labels.nothingToDoText.optimize;
                    }
                    w.imagify.bulk.displayError( {
                        title: imagifyBulk.labels.nothingToDoTitle,
                        html:  errorMsg,
                        type:  'info'
                    } );
                }
            }

            // Reset status.
            w.imagify.bulk.status = {};

            // Reset the progress bars.
            $tables.find( '.imagify-row-progress' ).slideUp().attr( 'aria-hidden', 'true' ).find( '.bar' ).removeAttr( 'style' ).find( '.percent' ).text( '0%' );

            $tables.find( '.imagify-cell-checkbox-loader' ).each( function() {
                $(this).addClass( 'hidden' ).attr( 'aria-hidden', 'true' );
            } );

            $tables.find( '.imagify-cell-checkbox-box' ).each( function() {
                $(this).removeClass( 'hidden' ).attr( 'aria-hidden', 'false' );
            } );

            // Enable (or not) the main button.
            if ( $( '.imagify-bulk-table [name="group[]"]:checked' ).length ) {
                $( '#imagify-bulk-action' ).prop( 'disabled', false ).find( '.dashicons' ).removeClass( 'rotate' );
            } else {
                $( '#imagify-bulk-action' ).find( '.dashicons' ).removeClass( 'rotate' );
            }
        },

        // Imagifybeat =============================================================================

        /**
         * Add a Imagifybeat ID for global stats on "imagifybeat-send" event.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        addStatsImagifybeat: function ( e, data ) {
            data[ imagifyBulk.imagifybeatIDs.stats ] = Object.keys( w.imagify.bulk.getFolderTypes() );
        },

        /**
         * Listen for the custom event "imagifybeat-tick" on $(document).
         * It allows to update various data periodically.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        processStatsImagifybeat: function ( e, data ) {
            if ( typeof data[ imagifyBulk.imagifybeatIDs.stats ] !== 'undefined' ) {
                w.imagify.bulk.updateStats( data[ imagifyBulk.imagifybeatIDs.stats ] );
            }
        },

        /**
         * Add a Imagifybeat ID on "imagifybeat-send" event to sync the optimization queue.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        addQueueImagifybeat: function ( e, data ) {
            data[ imagifyBulk.imagifybeatIDs.queue ] = Object.values( w.imagify.bulk.getFolderTypes() );
        },

        /**
         * Listen for the custom event "imagifybeat-tick" on $(document).
         * It allows to update various data periodically.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        processQueueImagifybeat: function ( e, data ) {
            var queue, $row, $progress, $bar;

            if ( typeof data[ imagifyBulk.imagifybeatIDs.queue ] !== 'undefined' ) {
                queue = data[ imagifyBulk.imagifybeatIDs.queue ];

                if ( false !== queue.result ) {
                    w.imagify.bulk.globalOriginalSize = queue.result.original_size;
                    w.imagify.bulk.globalOptimizedSize = queue.result.optimized_size;
                    w.imagify.bulk.globalOptimizedCount = queue.result.total;
                    w.imagify.bulk.globalGain = w.imagify.bulk.globalOptimizedSize * 100 / w.imagify.bulk.globalOriginalSize;
                }

                if ( ! w.imagify.bulk.processIsStopped && w.imagify.bulk.hasBlockingError( true ) ) {
                    $( w ).trigger( 'queueEmpty.imagify' );
                    return;
                }

                if ( Object.prototype.hasOwnProperty.call( queue, 'groups_data' ) ) {
                    Object.entries( queue.groups_data ).forEach( function( item ) {
                        $row = $( '[data-context=' + item[0] + ']' );

                        $row.children( '.imagify-cell-count-optimized' ).first().html( item[1]['count-optimized'] );
                        $row.children( '.imagify-cell-count-errors' ).first().html( item[1]['count-errors'] );
                        $row.children( '.imagify-cell-optimized-size-size' ).first().html( item[1]['optimized-size'] );
                        $row.children( '.imagify-cell-original-size-size' ).first().html( item[1]['original-size'] );
                    } );
                }

                if ( 0 === queue.remaining ) {
                    $( w ).trigger( 'queueEmpty.imagify' );
                    return;
                }

                $progress = $( '.imagify-row-progress' );
                $bar      = $progress.find( '.bar' );

                $bar.css( 'width', queue.percentage + '%' ).find( '.percent' ).html( queue.percentage + '%' );
                $progress.slideDown().attr( 'aria-hidden', 'false' );
            }
        },

        /**
         * Add a Imagifybeat ID for requirements on "imagifybeat-send" event.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        addRequirementsImagifybeat: function ( e, data ) {
            data[ imagifyBulk.imagifybeatIDs.requirements ] = 1;
        },

        /**
         * Listen for the custom event "imagifybeat-tick" on $(document).
         * It allows to update requirements status periodically.
         *
         * @param {object} e    Event object.
         * @param {object} data Object containing all Imagifybeat IDs.
         */
        processRequirementsImagifybeat: function ( e, data ) {
            if ( typeof data[ imagifyBulk.imagifybeatIDs.requirements ] === 'undefined' ) {
                return;
            }

            data = data[ imagifyBulk.imagifybeatIDs.requirements ];

            imagifyBulk.curlMissing    = data.curl_missing;
            imagifyBulk.editorMissing  = data.editor_missing;
            imagifyBulk.extHttpBlocked = data.external_http_blocked;
            imagifyBulk.apiDown        = data.api_down;
            imagifyBulk.keyIsValid     = data.key_is_valid;
            imagifyBulk.isOverQuota    = data.is_over_quota;
        },

        // Charts ==================================================================================

        /**
         * Overview chart.
         * Used for the big overview chart.
         */
        drawOverviewChart: function ( data ) {
            var initData, legend;

            if ( ! this.charts.overview.canvas ) {
                this.charts.overview.canvas = d.getElementById( 'imagify-overview-chart' );

                if ( ! this.charts.overview.canvas ) {
                    return;
                }
            }

            data = data && $.isArray( data ) ? data : [];

            if ( this.charts.overview.donut ) {
                // Update existing donut.
                if ( data.length ) {
                    if ( data.reduce( function( a, b ) { return a + b; }, 0 ) === 0 ) {
                        data[0] = 1;
                    }

                    this.charts.overview.donut.data.datasets[0].data = data;
                    this.charts.overview.donut.update();
                }
                return;
            }

            // Create new donut.
            this.charts.overview.data.datasets[0].data = [
                parseInt( this.charts.overview.canvas.getAttribute( 'data-unoptimized' ), 10 ),
                parseInt( this.charts.overview.canvas.getAttribute( 'data-optimized' ), 10 ),
                parseInt( this.charts.overview.canvas.getAttribute( 'data-errors' ), 10 )
            ];
            initData = $.extend( {}, this.charts.overview.data );

            if ( data.length ) {
                initData.datasets[0].data = data;
            }

            if ( initData.datasets[0].data.reduce( function( a, b ) { return a + b; }, 0 ) === 0 ) {
                initData.datasets[0].data[0] = 1;
            }

            this.charts.overview.donut = new w.imagify.Chart( this.charts.overview.canvas, {
                type:    'doughnut',
                data:    initData,
                options: {
                    plugins: {
                        legend: {
                            display: false
                        }
                    },
                    events:    [],
                    animation: {
                        easing: 'easeOutBounce'
                    },
                    tooltips: {
                        displayColors: false,
                        callbacks:     {
                            label: function( tooltipItem, localData ) {
                                return localData.datasets[ tooltipItem.datasetIndex ].data[ tooltipItem.index ];
                            }
                        }
                    },
                    responsive:       false,
					cutout: 75
                }
            } );

            // Then generate the legend and insert it to your page somewhere.
            legend = '<ul class="imagify-doughnut-legend">';

            $.each( initData.labels, function( i, label ) {
                legend += '<li><span style="background-color:' + initData.datasets[0].backgroundColor[ i ] + '"></span>' + label + '</li>';
            } );

            legend += '</ul>';

            d.getElementById( 'imagify-overview-chart-legend' ).innerHTML = legend;
        },

        /*
         * Share Chart.
         * Used for the chart in the share box.
         */
        drawShareChart: function () {
            var value;

            if ( ! this.charts.share.canvas ) {
                this.charts.share.canvas = d.getElementById( 'imagify-ac-chart' );

                if ( ! this.charts.share.canvas ) {
                    return;
                }
            }

            value = parseInt( $( this.charts.share.canvas ).closest( '.imagify-ac-chart' ).attr( 'data-percent' ), 10 );

            if ( this.charts.share.donut ) {
                // Update existing donut.
                this.charts.share.donut.data.datasets[0].data[0] = value;
                this.charts.share.donut.data.datasets[0].data[1] = 100 - value;
                this.charts.share.donut.update();
                return;
            }

            // Create new donut.
            this.charts.share.donut = new w.imagify.Chart( this.charts.share.canvas, {
                type: 'doughnut',
                data: {
                    datasets: [{
                        data:            [ value, 100 - value ],
                        backgroundColor: [ '#40B1D0', '#FFFFFF' ],
                        borderWidth:     0
                    }]
                },
                options: {
                    plugins: {
                        legend: {
                            display: false
                        }
                    },
                    events:    [],
                    animation: {
                        easing: 'easeOutBounce'
                    },
                    tooltips: {
                        enabled: false
                    },
                    responsive:       false,
                    cutoutPercentage: 70
                }
            } );
        }
    };

    w.imagify.bulk.init();

    if (imagifyBulk.isOverQuota) {
        w.imagify.bulk.displayError( {
            title:             imagifyBulk.labels.overQuotaTitle,
            html:              $( '#tmpl-imagify-overquota-alert' ).html(),
            type:              'info',
            customClass:       'imagify-swal-has-subtitle imagify-swal-error-header',
            showConfirmButton: false
        } );
    }


} )(jQuery, document, window);

Youez - 2016 - github.com/yon3zu
LinuXploit