1(function ($) { 2 3 var $document = $(document); 4 5 var ONE_MINUTE = 60; 6 var ONE_HOUR = ONE_MINUTE * 60; 7 var ONE_DAY = ONE_HOUR * 24; 8 9 // private utils 10 11 function nowTimestamp() { 12 return Math.floor((new Date()).valueOf() / 1000); 13 } 14 15 function getSeconds(endTimestamp) { 16 return Math.max(0, endTimestamp - nowTimestamp()); 17 } 18 19 function getScrollTop() { 20 return document.documentElement.scrollTop || document.body.scrollTop; 21 } 22 23 24 var COUNTDOWN_DEFAULTS = { 25 removeDelay: 3, 26 seconds: 0, 27 endTimestamp: 0, 28 }; 29 30 $.fn.jq_countdown = function (options) { 31 var $this = $(this); 32 33 if ($this.length > 1) { 34 $this.each(function () { 35 $(this).jq_countdown(options); 36 }); 37 return this; 38 } 39 40 options = $.extend({}, COUNTDOWN_DEFAULTS, options); 41 42 var endTimestamp = 0 + $this.data('timestamp'); 43 if (endTimestamp) { 44 options.endTimestamp = endTimestamp; 45 } 46 47 endTimestamp = options.endTimestamp || (nowTimestamp() + options.seconds); 48 49 if (!endTimestamp) { 50 console.error('init countdownTimer error', this); 51 return; 52 } 53 54 var template = options.template || $this.data('template'); 55 var removeDelay = options.removeDelay; 56 57 var timer = null; 58 var tick = function () { 59 if (!$this) { 60 timer && clearInterval(timer); 61 timer = null; 62 return; 63 } 64 var seconds = getSeconds(endTimestamp); 65 var s = seconds; 66 67 // days 68 var d = 0; 69 if (template.indexOf('{d}') !== -1) { 70 d = Math.floor(s / ONE_DAY); 71 s -= d * ONE_DAY; 72 if (d < 10) { 73 d = '0' + d; 74 } 75 } 76 77 // hours 78 var h = Math.floor(s / ONE_HOUR); 79 s -= h * ONE_HOUR; 80 if (h < 10) { 81 h = '0' + h; 82 } 83 84 // minutes 85 var m = Math.floor(s / ONE_MINUTE); 86 s -= m * ONE_MINUTE; 87 if (m < 10) { 88 m = '0' + m; 89 } 90 91 // seconds 92 if (s < 10) { 93 s = '0' + s; 94 } 95 96 var html = template.replace('{d}', d) 97 .replace('{h}', h) 98 .replace('{m}', m) 99 .replace('{s}', s); 100 101 $this.html(html); 102 103 if (seconds <= 0) { 104 $this.trigger('countdown:end'); 105 timer && clearInterval(timer); 106 timer = null; 107 $this = null; 108 } else if (!$this.is(':visible') && !$this.is('[data-no-remove]')) { 109 removeDelay--; 110 if (removeDelay < 0) { 111 timer && clearInterval(timer); 112 timer = null; 113 $this = null; 114 } 115 } 116 }; 117 // start 118 if (getSeconds(endTimestamp) > 0) { 119 timer = setInterval(tick, 1000); 120 } 121 tick(); 122 123 return this; 124 }; 125 126 127 $.fn.scroll_top_button = function (animationTime) { 128 129 var $this = $(this); 130 if ($this.length === 0) { 131 return this; 132 } 133 134 $(window).scroll(function () { 135 if ($(this).scrollTop() > 0) { 136 $this.addClass('active'); 137 } else { 138 $this.removeClass('active'); 139 } 140 }); 141 142 $this.on('click', function (event) { 143 event.preventDefault(); 144 $('html, body').animate({ 145 scrollTop: 0, 146 }, animationTime || 200); 147 }); 148 }; 149 150 151 var DROPDOWN_DEFAULTS = { 152 animationType: 'slide', 153 animationTime: 200, 154 }; 155 $.fn.jq_dropdown = function (options) { 156 var $this = $(this); 157 158 if ($this.length > 1) { 159 $this.each(function () { 160 $(this).jq_dropdown(options); 161 }); 162 return this; 163 } 164 165 options = $.extend({}, DROPDOWN_DEFAULTS, options); 166 167 function show($menu) { 168 switch (options.animationType) { 169 case 'slide': 170 $menu.slideDown(options.animationTime); 171 break; 172 case 'fade': 173 $menu.fadeIn(options.animationTime); 174 break; 175 default: 176 $menu.show(); 177 break; 178 } 179 } 180 181 function hide($menu) { 182 switch (options.animationType) { 183 case 'slide': 184 $menu.slideUp(options.animationTime); 185 break; 186 case 'fade': 187 $menu.fadeOut(options.animationTime); 188 break; 189 default: 190 $menu.hide(); 191 break; 192 } 193 } 194 195 function open() { 196 var $menu = $this.find('.dd__menu'); 197 show($menu); 198 $this.addClass('open'); 199 200 setTimeout(function () { 201 $document.one('click', function (event) { 202 close(); 203 }); 204 }, 1); 205 } 206 207 function close() { 208 var $menu = $this.find('.dd__menu'); 209 210 $this.removeClass('open'); 211 hide($menu); 212 } 213 214 function isOpen() { 215 return $this.hasClass('open'); 216 } 217 218 $this.on('click', '.pll-parent-menu-item', function () { 219 isOpen() ? close() : open(); 220 }); 221 222 $this.on('click', '.sub-menu', function () { 223 close(); 224 }); 225 }; 226 227 228 var BUTTON_UP_DEFAULTS = { 229 scrollTime: 400, 230 }; 231 $.fn.jq_button_up = function (options) { 232 var $this = $(this); 233 234 options = $.extend({}, BUTTON_UP_DEFAULTS, options); 235 236 $([document, document.documentElement, document.body]).on('scroll', function () { 237 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; 238 if (scrollTop > 0) { 239 $this.fadeIn(); 240 } else { 241 $this.fadeOut(); 242 } 243 }); 244 245 $this.click(function (event) { 246 event.preventDefault(); 247 248 $([document.documentElement, document.body]).animate({ 249 scrollTop: 0, 250 }, options.scrollTime); 251 }); 252 }; 253 254 255 var GAMES_AJAX_DEFAULTS = { 256 form: '#filter_term', 257 links: null, 258 searchDelay: 300, 259 searchOnInput: true, 260 updateContainers: ['#games_list'], 261 clearGridBeforeUpdate: true, 262 loaderInGrid: true, 263 264 beforeUpdate: $.noop, 265 afterUpdate: $.noop, 266 onSubmit: $.noop, 267 onLink: $.noop, 268 resolveUrl: null, 269 270 pushState: true, 271 }; 272 $.fn.games_ajax = function (options) { 273 var $this = $(this); 274 275 if ($this.length > 1) { 276 $this.each(function () { 277 $(this).games_ajax(options); 278 }); 279 return this; 280 } 281 282 options = $.extend({}, GAMES_AJAX_DEFAULTS, options); 283 284 var $grid = $this; 285 var $form = $(options.form); 286 287 if (!$grid.length) throw new Error('games_ajax: $grid not found'); 288 if (!$form.length) throw new Error('games_ajax: $form not found'); 289
290 var $term_input = $form.find('input:visible'); 291 var request = null; 292 293 $form.on('submit', function (event) { 294 event.preventDefault(); 295 var $this = $(this); 296 var url = $this.attr('action'); 297 if (options.resolveUrl) { 298 var params = $this.serializeArray(); 299 url = options.resolveUrl(url, params); 300 } else { 301 var params = $this.serializeArray().filter(function (item) { 302 return !!item.value; 303 }).map(function (item) { 304 return encodeURIComponent(item.name) + '=' + encodeURIComponent(item.value); 305 }); 306 if (params.length) { 307 url += (url.indexOf('?') === -1 ? '?' : '&') + params.join('&'); 308 } 309 } 310 update(url, false); 311 options.onSubmit.call(this); 312 }); 313 314 if (options.searchOnInput) { 315 $term_input.on('input', search); 316 $form.find('select').on('change', search); 317 } 318 319 $form.find('input:radio').on('change', search); 320 $form.find('input:checkbox').on('change', search); 321 322 if (options.links) { 323 $document.on('click', options.links, function (event) { 324 event.preventDefault(); 325 var url = $(this).attr('href'); 326 update(url, true); 327 options.onLink.call(this); 328 }); 329 } 330 331 var search_timer = null; 332 333 function search() { 334 if (options.searchDelay) { 335 search_timer && clearTimeout(search_timer); 336 search_timer = setTimeout(function () { 337 $form.submit(); 338 }, options.searchDelay); 339 } else { 340 $form.submit(); 341 } 342 } 343 344 function abort() { 345 request && request.abort(); 346 request = null; 347 } 348 349 function complete() { 350 $grid.removeLoader(); 351 request = null; 352 353 options.afterUpdate(); 354 } 355 356 function update(url, resetTerm) { 357 abort(); 358 359 options.beforeUpdate(); 360 361 // fix "%20" => "+" 362 url = url.replace(/\%20/g, '+'); 363 364 request = $.ajax({ 365 url: url, 366 method: 'get', 367 success: function (html) { 368 options.loaderInGrid && $grid.removeLoader(); 369 370 // build page 371 var $page = $('<div>' + html + '</div>'); 372 373 // update containers 374 var $old, $new, selector; 375 for (var i = 0; i < options.updateContainers.length; i++) { 376 selector = options.updateContainers[i]; 377 378 $old = $document.find(selector); 379 $new = $page.find(selector); 380 381 if ($old.length && $new.length) { 382 $old.html($new.html()); 383 } 384 } 385 386 // update form 387 $old = $form; 388 $new = $page.find(options.form); 389 if ($old.length && $new.length) { 390 $old.attr('action', $new.attr('action')); 391 } 392 393 // clear? 394 $old = null; 395 $new = null; 396 397 if (resetTerm) { 398 $term_input.val(''); 399 } 400 401 // update url 402 if (options.pushState) { 403 history.pushState({}, '', url); 404 } 405 406 // afterUpdate 407 window.dispatchEvent(new Event('resize')); 408 window.dispatchEvent(new Event('scroll')); 409 options.afterUpdate(); 410 411 // clear? 412 $page.remove(); 413 $page = null; 414 }, 415 error: function (err) { 416 }, 417 complete: complete, 418 }); 419 420 options.clearGridBeforeUpdate && $grid.empty(); 421 options.loaderInGrid && $grid.addLoader(); 422 } 423 424 }; 425 426 var GAMES_SEARCH_DEFAULTS = { 427 url: null, 428 data: null, 429 showCount: 3, 430 showItemTemplate: '<div class="item">{id} / {title}</div>', 431 emptyText: '<div class="empty">empty</div>', 432 input: 'input', 433 content: '.dd__content', 434 searchInFields: ['fullGameName'], 435 }; 436 $.fn.games_search = function (options) { 437 var $this = $(this); 438 439 if ($this.length > 1) { 440 $this.each(function () { 441 $(this).games_search(options); 442 }); 443 return this; 444 } 445 446 options = $.extend({}, GAMES_SEARCH_DEFAULTS, options); 447 448 var $input = $this.find(options.input); 449 var $content = $this.find(options.content); 450 var loading = false;
451 452 function open() { 453 $this.addClass('open'); 454 setTimeout(function () { 455 $document.on('click', checkClose); 456 }, 100); 457 } 458 459 function checkClose(event) { 460 if ($input.parent().has(event.target).length === 0) { 461 close(); 462 } 463 } 464 465 function close() { 466 $this.removeClass('open'); 467 $document.off('click', checkClose); 468 } 469 470 function focus(event) { 471 // make ajax request, cache games 472 if (options.data === null && options.url) { 473 options.data = []; 474 $.ajax({ 475 url: options.url, 476 method: 'get', 477 success: function (data) { 478 options.data = data; 479 }, 480 complete: function () { 481 $content.removeLoader(); 482 loading = false; 483 search(); 484 }, 485 }); 486 $content.addLoader(); 487 loading = true; 488 } 489 490 search(); 491 } 492 493 function change(event) { 494 search(); 495 } 496 497 function search() { 498 var searchText = $input.val().toLowerCase(); 499 if (searchText) { 500 open(); 501 } else { 502 close(); 503 return; 504 } 505 506 if (loading) { 507 // dont show results 508 return; 509 } 510 511 var results = []; 512 for (var i = 0; i < options.data.length; i++) { 513 var found = false; 514 var item = options.data[i]; 515 for (var j = 0; j < options.searchInFields.length; j++) { 516 var fieldName = options.searchInFields[j]; 517 if (typeof item[fieldName] === 'string') { 518 if (item[fieldName].toLowerCase().indexOf(searchText) >= 0) { 519 found = true; 520 break; 521 } 522 } 523 } 524 if (found) { 525 results.push(item); 526 if (results.length >= options.showCount) { 527 break; 528 } 529 } 530 } 531 532 533 showResults(results); 534 } 535 536 function renderItem(item) { 537 var template = options.showItemTemplate; 538 var html = template.replace(/\{([\w\d\_]+)\}/gm, function (matchText, fieldName) { 539 if (fieldName === 'name') { 540 fieldName = 'fullGameName'; 541 } 542 if (item[fieldName] !== undefined) { 543 return item[fieldName]; 544 } 545 return matchText; 546 }); 547 return $(html); 548 } 549 550 function showResults(items) { 551 if (items.length) { 552 var $scroll = $('<div class="dd__scroll"></div>'); 553 $scroll.append(items.map(renderItem)); 554 $content.empty().append($scroll); 555 } else { 556 $content.empty().append($(options.emptyText)); 557 } 558 } 559 560 $input.on('focus', focus); 561 $input.on('input', change); 562 }; 563 564 565 var TREE_MENU_DEFAULTS = { 566 submenuSelector: '.menu.sub', 567 itemSelector: '.item', 568 activeClass: 'hovered', 569 activateActiveDelay: 300, 570 animationTime: 300, 571 }; 572 $.fn.tree_menu = function (options) { 573 var $this = $(this); 574 575 if ($this.length > 1) { 576 $this.each(function () { 577 $(this).tree_menu(options); 578 }); 579 return this; 580 } 581 582 options = $.extend({}, TREE_MENU_DEFAULTS, options); 583 584 var $submenu = $this.next(); 585 var activateActiveTimer = null; 586 var $prevmenu = null; 587 var showSub = true; 588 589 function resetTimer() { 590 activateActiveTimer && clearTimeout(activateActiveTimer); 591 activateActiveTimer = null; 592 } 593 594 function activate($item) { 595 resetTimer(); 596 $this.find(options.itemSelector + '.' + options.activeClass).not($item).removeClass(options.activeClass); 597 $item.addClass(options.activeClass); 598 599 var $menu = $item.find(options.submenuSelector).eq(0); 600 if ($menu.length) { 601 // show it 602 var $tmp = $menu.clone(); 603 $submenu.append($tmp); 604 if ($prevmenu) { 605 $prevmenu.remove(); 606 } else { 607 $tmp.hide().slideDown(options.animationTime); 608 } 609 $prevmenu = $tmp; 610 } else { 611 if ($prevmenu) { 612 $prevmenu.slideUp(options.animationTime, function () { 613 $(this).remove(); 614 }); 615 $prevmenu = null; 616 } 617 } 618 } 619 620 function activateDefault() { 621 var $item = $this.find(options.itemSelector + '.active'); 622 if ($item && $item.length) { 623 activate($item); 624 } 625 } 626 627 function activateDefaultDelayed() { 628 resetTimer(); 629 activateActiveTimer = setTimeout(activateDefault, options.activateActiveDelay); 630 } 631 632 $this 633 .on('tap', options.itemSelector, function (event) { 634 var url = $(event.target).attr('href'); 635 if (url) { 636 location.replace(url); 637 showSub = false 638 } 639 }) 640 .on('mouseover', options.itemSelector, function (event) { 641 if (showSub == true){ 642 activate($(this)); 643 } 644 }) 645 .on('mouseleave', options.itemSelector, activateDefaultDelayed) 646 $submenu 647 .on('mouseover', resetTimer) 648 .on('mouseleave', activateDefaultDelayed); 649 650 activateDefault(); 651 }; 652 653 654 var TABULAR_MENU_DEFAULTS = { 655 menuItem: 'item', 656 activeClass: 'active', 657 initializedClass: 'initialized', 658 tabStretch: false, 659 autoplay: 0, 660 }; 661 $.fn.tabular_menu = function (options) { 662 var $this = $(this); 663 664 if ($this.length > 1) { 665 $this.each(function () { 666 $(this).tree_menu(options); 667 }); 668 return this; 669 } 670 671 options = $.extend({}, TABULAR_MENU_DEFAULTS, options); 672 673 var $items = $this.find('.' + options.menuItem); 674 675 function activate($item) { 676 $items.not($item).removeClass(options.activeClass).each(function () { 677 var content = $(this).attr('href'); 678 $(content).hide(); 679 }); 680 $item.addClass(options.activeClass); 681 var content = $item.attr('href'); 682 $(content).fadeIn(); 683 } 684 685 // find active 686 var $active = null; 687 $items.each(function () { 688 if ($active === null && $(this).hasClass(options.activeClass)) { 689 $active = $(this); 690 } 691 }); 692 if ($active === null) { 693 $active = $items.eq(0); 694 } 695 696 activate($active); 697 698 // init 699 (function () { 700 var $tabs = $items.map(function () { 701 return $($(this).attr('href')); 702 }); 703 704 var maxHeight = 0; 705 $tabs.each(function () { 706 this.addClass(options.initializedClass); 707 maxHeight = Math.max(maxHeight, this.outerHeight()); 708 }); 709 if (options.tabStretch) { 710 $tabs.each(function () { 711 this.css('min-height', maxHeight + 'px'); 712 }); 713 } 714 $tabs = null; 715 })(); 716 717 $this.on('click', '.' + options.menuItem, function (event) { 718 event.preventDefault(); 719 activate($(this)); 720 }); 721 722 function autoplayNext() { 723 var nextIndex = $items.index($items.filter('.active').get(0)) + 1; 724 if (nextIndex >= $items.length) { 725 nextIndex = nextIndex % $items.length; 726 } 727 $items.eq(nextIndex).click(); 728 } 729 730 if (options.autoplay) { 731 var autoplayTimer = setInterval(autoplayNext, options.autoplay); 732 } 733 }; 734 735 // .drag-slider-wrap > .drag-slider 736 var DRAG_SLIDER_DEFAULTS = { 737 }; 738 $.fn.drag_slider = function (options) { 739 var $this = $(this); 740 741 if ($this.length > 1) { 742 $this.each(function () { 743 $(this).drag_slider(options); 744 }); 745 return this; 746 } 747 748 options = $.extend({}, DRAG_SLIDER_DEFAULTS, options); 749 750 var $container = $this; 751 var isDown, isScroll, startX, scrollLeft; 752 var $slider = $container.find('.drag-slider'); 753 754 function stopClick(e){ 755 e.preventDefault(); 756 e.stopPropagation(); 757 e.stopImmediatePropagation(); 758 } 759 760 $slider.on('mousedown', function (e) { 761 isDown = true; 762 isScroll = false;
763 startX = e.clientX; 764 scrollLeft = e.currentTarget.scrollLeft; 765 stopClick(e); 766 }); 767 $slider.on('mouseleave', function () { 768 isDown = false; 769 isScroll = false; 770 }); 771 $slider.on('mouseup', function (e) { 772 if (isScroll === true) { 773 $slider.one('click', stopClick, false); 774 } 775 isDown = false; 776 isScroll = false; 777 }); 778 $slider.on('mousemove', function (e) { 779 if (isDown) { 780 var x = e.clientX; 781 var walk = x - startX; 782 e.currentTarget.scrollLeft = scrollLeft - walk; 783 if (walk) { 784 isScroll = true; 785 } 786 } 787 }); 788 789 function prev () { 790 var $item = $slider.children() 791 var scrollLeft = $slider.scrollLeft() 792 793 var left; 794 var scroledSlidesNum = scrollLeft / Math.floor($item.outerWidth()); 795 796 left = Math.floor(scroledSlidesNum) * $item.outerWidth() 797 if (scroledSlidesNum - Math.floor(scroledSlidesNum) <= 0.3) { 798 left = Math.floor(scroledSlidesNum - 1) * $item.outerWidth() 799 } 800 $slider.animate({scrollLeft: left}, 200) 801 } 802 803 function next () { 804 var $item = $slider.children() 805 var scrollLeft = $slider.scrollLeft() 806 807 var left; 808 var scroledSlidesNum = scrollLeft / Math.floor($item.outerWidth()); 809 810 left = Math.floor(scroledSlidesNum + 1) * $item.outerWidth() 811 if (scroledSlidesNum - Math.floor(scroledSlidesNum) >= 0.8) {
812 left = Math.ceil(scroledSlidesNum + 1) * $item.outerWidth(); 813 } 814 $slider.animate({scrollLeft: left}, 200) 815 } 816 817 $container.on('click', '.prev', function (event) { 818 event.preventDefault(); 819 prev(); 820 }); 821 822 $container.on('click', '.next', function (event) { 823 event.preventDefault(); 824 next(); 825 }); 826 }; 827})(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.