English
Personal tools
Namespaces

Variants
Actions

MediaWiki:Common.js

From Tanki Online Wiki
(Difference between revisions)
Jump to: navigation, search
Line 361: Line 361:
 
if($('.showPaint').length){  
 
if($('.showPaint').length){  
  
   var parts_url  = 'images/en/6/66/Tank_parts_resources.json?v=006';
+
   var parts_url  = 'images/en/6/66/Tank_parts_resources.json?v=007';
 
   var paints_url = 'images/en/6/6d/Paints_textures.json?v=010';
 
   var paints_url = 'images/en/6/6d/Paints_textures.json?v=010';
 
   var swfobject_url = 'https://cdnjs.cloudflare.com/ajax/libs/swfobject/2.2/swfobject.min.js';
 
   var swfobject_url = 'https://cdnjs.cloudflare.com/ajax/libs/swfobject/2.2/swfobject.min.js';

Revision as of 15:30, 15 October 2019

/*======= Hide recent changes ======*/

var hideRecentChanges = false;
var el = document.getElementById("mw-content-text");
if (mw.config.values.wgTitle === "RecentChanges" && hideRecentChanges === true) {
  if (
    mw.config.values.wgUserGroups.indexOf("administrator") !== -1 ||
    mw.config.values.wgUserGroups.indexOf("bureaucrat") !== -1 ||
    mw.config.values.wgUserGroups.indexOf("user") !== -1
  ) {
    el.style.display = "block";
  } else {
    el.parentNode.removeChild(el);
  }
}

/*============================================================================================*/

/* Simple polyfill */

if (!Object.keys) Object.keys = function(o) {
  if (o !== Object(o))
    throw new TypeError('Object.keys called on a non-object');
  var k = [], p;
  for (p in o) if (Object.prototype.hasOwnProperty.call(o, p)) k.push(p);
  return k;
}

function getRandomKey(obj){
  var keys = Object.keys(obj);
  return keys[Math.floor(Math.random()*keys.length)];
};

function getRandomVal(obj){
  return obj[getRandomKey(obj)];
};

function getSplitNumber(num) {
  return num.toString().replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
}

function getSelectedText() {
  if (window.getSelection) {
    return window.getSelection().toString();
  } else if (document.getSelection) {
    return document.getSelection().toString();
  } else if (document.selection) {
    return document.selection.createRange().text;
  } else {
    return false;
  }
}

function isNotEmpty(_var){
  return !( _var == "" || new RegExp(/^\s+$/).test(_var) || _var == null || _var == [] || _var == {} );
}

function isDesktopChrome() {
  var ua = window.navigator.userAgent.toLowerCase();
  return (
    window.navigator.vendor.toLowerCase().indexOf("google") > -1 &&
    window.chrome != null &&
    ua.indexOf("opr") == -1 && ua.indexOf("opera") == -1 &&
    ua.indexOf("yabrowser") == -1 && ua.indexOf("yowser") == -1 &&
    ua.indexOf("edge") == -1 &&
    ua.indexOf("android") == -1 && ua.indexOf("crios") == -1
  );
}

/*============================================================================================*/

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root.tingle = factory();
  }
}
  (this, function () {

    function Modal(options) {
      var defaults = {
        onClose: null,
        onOpen: null,
        beforeOpen: null,
        beforeClose: null,
        closeMethods: ['overlay', 'button', 'escape'],
        cssClass: []
      };
      this.opts = extend({}, defaults, options);
      this.init();
    }

    Modal.prototype.init = function () {
      if (this.modal) {
        return;
      }
      _build.call(this);
      _bindEvents.call(this);
      document.body.appendChild(this.modal);
    };

    Modal.prototype.destroy = function () {
      if (this.modal === null) {
        return;
      }
      _unbindEvents.call(this);
      this.modal.parentNode.removeChild(this.modal);
      this.modal = null;
    };

    Modal.prototype.open = function () {
      var self = this;
      if (typeof self.opts.beforeOpen === 'function') {
        self.opts.beforeOpen();
      }
      if (this.modal.style.removeProperty) {
        this.modal.style.removeProperty('display');
      } else {
        this.modal.style.removeAttribute('display');
      }
      _addClass(document.body, 'tingle-enabled');
      _addClass(this.modal, 'tingle-modal--visible');
      if (typeof self.opts.onOpen === 'function') {
        self.opts.onOpen.call(self);
      }
      this.checkOverflow();
    };

    Modal.prototype.isOpen = function () {
      return this.modal ? _hasClass(this.modal, "tingle-modal--visible") : false;
    };

    Modal.prototype.close = function () {
      if (typeof this.opts.beforeClose === "function") {
        var close = this.opts.beforeClose.call(this);
        if (!close) {
          return;
        }
      }
      var self = this;
      jQuery(this.modal).fadeOut(200, function(){
        _removeClass(document.body, 'tingle-enabled');
        _removeClass(this, 'tingle-modal--visible');

        self.modal.style.display = 'none';
        if (typeof self.opts.onClose === "function") {
          self.opts.onClose.call(this);
        }
        self.destroy();
      });
    };

    Modal.prototype.setContent = function (content) {
      if (typeof content === 'string') {
        this.modalBoxContent.innerHTML = content;
      } else {
        this.modalBoxContent.innerHTML = "";
        this.modalBoxContent.appendChild(content);
      }
    };

    Modal.prototype.getContent = function () {
      return this.modalBoxContent;
    };

    Modal.prototype.isOverflow = function () {
      return this.modalBox.clientHeight >= window.innerHeight;
    };

    Modal.prototype.checkOverflow = function () {
      if (_hasClass(this.modal, 'tingle-modal--visible')) {
        if (this.isOverflow()) {
          _addClass(this.modal, 'tingle-modal--overflow');
        } else {
          _removeClass(this.modal, 'tingle-modal--overflow');
        }
      }
    }

    function _build() {
      this.modal = document.createElement('div');
      _addClass(this.modal, 'tingle-modal');
      this.modal.style.display = 'none';
      this.opts.cssClass.forEach(function (item) {
        if (typeof item === 'string') {
          _addClass(this.modal, item);
        }
      }, this);

      /*this.modalBoxTitle = '<div class="report-head"><div class="report-title">' + tingle.modal.title + '</div><div class="report-stripes"></div><div class="report-close"></div></div></div>';*/
      this.modalCloseBtnIcon = document.createElement('button');
      _addClass(this.modalCloseBtnIcon, 'tingle-modal__closeIcon');
      _addClass(this.modalCloseBtnIcon, 'tingle-modal__close');
      //this.modalCloseBtnIcon.innerHTML = '×';
      this.modalBox = document.createElement('div');
      _addClass(this.modalBox, 'tingle-modal-box');
      this.modalBoxContent = document.createElement('div');
      _addClass(this.modalBoxContent, 'tingle-modal-box__content');
      
      /*this.modalBox.appendChild(this.modalBoxTitle);*/
      this.modalBox.appendChild(this.modalBoxContent);
      //this.modalBox.appendChild(this.modalCloseBtnIcon);
      this.modal.appendChild(this.modalCloseBtnIcon);
      this.modal.appendChild(this.modalBox);
    }

    function _bindEvents() {
      this._events = {
        clickCloseBtn: this.close.bind(this),
        clickOverlay: _handleClickOutside.bind(this),
        resize: this.checkOverflow.bind(this),
        keyboardNav: _handleKeyboardNav.bind(this)
      };
      this.modalCloseBtnIcon.addEventListener('click', this._events.clickCloseBtn);
      this.modal.addEventListener('mousedown', this._events.clickOverlay);
      window.addEventListener('resize', this._events.resize);
      document.addEventListener("keydown", this._events.keyboardNav);
    }

    function _handleKeyboardNav(event) {
      if (event.which === 27 && this.isOpen()) {
        this.close();
      }
    }

    function _handleClickOutside(event) {
      if (this.opts.closeMethods.indexOf('overlay') !== -1 && !_findAncestor(event.target, 'tingle-modal') && event.clientX < this.modal.clientWidth) {
        this.close();
      }
    }

    function _findAncestor(el, cls) {
      while ((el = el.parentElement) && !_hasClass(el, cls));
      return el;
    }

    function _unbindEvents() {
      this.modalCloseBtnIcon.removeEventListener('click', this._events.clickCloseBtn);
      this.modal.removeEventListener('mousedown', this._events.clickOverlay);
      window.removeEventListener('resize', this._events.resize);
      document.removeEventListener("keydown", this._events.keyboardNav);
    }

    function _cleanClassName(target) {
      target.className = target.className.replace(/[\n\t]/g, " ").trim();
    }

    function _hasClass(target, classname) {
      _cleanClassName(target);
      return !!((" " + target.className + " ").indexOf(" " + classname.trim() + " ") > -1);
    }

    function _addClass(target, classname) {
      if (!_hasClass(target, classname)) {
        target.className += ' ' + classname.trim();
      }
    }

    function _removeClass(target, classname) {
      if (_hasClass(target, classname)) {
        var regexp = new RegExp('(\\s|^)' + classname.trim() + '(\\s|$)');
        target.className = target.className.replace(regexp, ' ').trim();
      }
    }

    function extend() {
      for (var i = 1; i < arguments.length; i++) {
        for (var key in arguments[i]) {
          if (arguments[i].hasOwnProperty(key)) {
            arguments[0][key] = arguments[i][key];
          }
        }
      }
      return arguments[0];
    }

    return {
      modal: Modal
    };

  }));

/*============================================================================================*/
/*============================================================================================*/
/*============================================================================================*/
/*Using jQuery from here*/

jQuery.noConflict();

jQuery(document).ready(function($) {

/*============================================================================================*/
//TOP button
  $('body').append('<div id="toTop-wrapper" style="display: none;"><div id="toTop-arrow"></div></div>');
  $(function() {
    $(window).scroll(function() {
      if($(this).scrollTop() > 500) {
        $('#toTop-wrapper').fadeIn(300);	
      } else {
        $('#toTop-wrapper').fadeOut(100);
      }
    });
    $('#toTop-wrapper').click(function() {
      $('body,html').animate({ scrollTop:0 }, 200);
    });	
  });	

/*====================================================================================*/
//Homepage turrets/hulls dropdown lists

if($("#HomepageDropdowns").length){
  var ddl = $(".drop-down-list");
  $(document).on('click', '.drop-down-block', function() {
    for(var i = 0; i < ddl.length; i++)
    {
      if(ddl[i] == ($(this).next().find('.drop-down-list'))[0])
      {
        $(ddl[i]).parent().prev().toggleClass("rotate180");
        $(ddl[i]).slideToggle();
      }
      else
      {
        $(ddl[i]).parent().prev().toggleClass("rotate180", false);
        $(ddl[i]).hide();
      }
    }
  });

  $(document).click(function(event){ 
    if(!$(event.target).hasClass('drop-down-list') && !$(event.target).parent().hasClass('drop-down-list') && !$(event.target).parent().parent().hasClass('drop-down-list') && !$(event.target).parent().hasClass('drop-down-block') && !$(event.target).hasClass('drop-down-block') && !$(event.target).hasClass('drop-down-list-wrapper')) 
    {
      for(var j = 0; j < ddl.length; j++)
      {
        if($(ddl[j]).is(":visible")) 
        {
          $(ddl[j]).parent().prev().toggleClass("rotate180", false);
          $(ddl[j]).slideUp("fast");
        }
      }
    }     
  });
}

/*============================================================================================*/
/*============================================================================================*/

if ($(".mapScreenshotsCarousel").length) {
  $('.mapScreenshotsCarousel .carouselContainer').remove();

  $.each($(".mapScreenshotsCarousel .open"), function(k,v) {
    $($(v).children()).detach().insertAfter($(v));
  });
}

/*============================================================================================*/
/* Tank Preview */

if($('.showPaint').length){ 

  var parts_url  = 'images/en/6/66/Tank_parts_resources.json?v=007';
  var paints_url = 'images/en/6/6d/Paints_textures.json?v=010';
  var swfobject_url = 'https://cdnjs.cloudflare.com/ajax/libs/swfobject/2.2/swfobject.min.js';

  var Viewer = {
      currentPaint: null,
      data: {},
      emptyTank: function(){
        return {
          "hull": {
            "type": null,
            "model": null
          },
          "turret": {
            "type": null,
            "model": null
          },
          "paint": {
            "type": null,
            "model": null
          }
        };
      },
      getRandomTank: function(){
        var tank = this.emptyTank();
        if(isNotEmpty(this.data)){
          tank.hull.type = getRandomKey(this.data.hulls);
          tank.turret.type = getRandomKey(this.data.turrets);
          tank.hull.model = getRandomKey(this.data.hulls[tank.hull.type]);
          tank.turret.model = getRandomKey(this.data.turrets[tank.turret.type]);
          
          return tank;
        } else {
          return false;
        }
      },
      appendViewer: function(tank, target_id){
        if(swfobject){
          swfobject.ua.pv = [100, 0, 0];
          var viewer_swf = 'images/en/2/24/Tank_viewer.swf';
          var items = {
            "hull": this.data.hulls[tank.hull.type][tank.hull.model],
            "turret": this.data.turrets[tank.turret.type][tank.turret.model],
            "paint": this.data.paints[tank.paint.type][tank.paint.model]
          };
          var flashvars = {
            "itemsXml": 
              "<response>" + 
              "<hull_model>" + items.hull.model + "</hull_model>" + 
              "<hull_details>" + items.hull.details + "</hull_details>" + 
              "<hull_details_alpha>" + items.hull.alpha + "</hull_details_alpha>" + 
              "<hull_lightmap>" + items.hull.lightmap + "</hull_lightmap>" + 
              "<turret_model>" + items.turret.model + "</turret_model>" + 
              "<turret_details>" + items.turret.details + "</turret_details>" + 
              "<turret_details_alpha>" + items.turret.alpha + "</turret_details_alpha>" + 
              "<turret_lightmap>" + items.turret.lightmap + "</turret_lightmap>" + 
              "<paint_texture>" + items.paint + "</paint_texture>" + 
              "</response>"
          };
          var params = {
            "menu": false,
            "seamlesstabbing": false,
            "wmode": "transparent"
          }
          
          swfobject.embedSWF(viewer_swf, target_id, "600", "400", "11", false, flashvars, params, false);
        } else {
          return false;
        }
      }
  };

  $.when(
    $.getJSON(parts_url, function(json){ 
      Viewer.data.hulls = json.hulls;
      Viewer.data.turrets = json.turrets;
    }),
    $.getJSON(paints_url, function(json){ 
      Viewer.data.paints = json;
    }),
    $.getScript(swfobject_url)
  ).done(function(){
   
    var templateMenu = [
      '<div class="report-head"><div class="report-title">Preview on a tank</div><div class="report-stripes"></div><div class="report-close"></div></div></div>',
      '<div id="TankPreview__wrapper">',
      ' <div id="TankPreview__viewer"><div id="TankPreview"></div></div>',
      ' <div id="TankPreview__controls">',
      '   <div class="wrapper">',
      '         Hull:',
      '         <select class="html5-control" size="1" id="hullType" name="hullType" data-category="hulls" data-child="hullModel">',
      '           <option selected hidden disabled value="title">Model</option>',
      '         </select>',
      '         <select class="html5-control" disabled size="1" id="hullModel" name="hullModel" data-parent="hullType">',
      '           <option selected hidden disabled value="title">Grade</option>',
      '         </select>',,
      '     </div>',
      '   <div class="wrapper">',
      '         Turret:',
      '         <select class="html5-control" size="1" id="turretType" name="turretType" data-category="turrets" data-child="turretModel">',
      '           <option selected hidden disabled value="title">Model</option>',
      '         </select>',
      '         <select class="html5-control" disabled size="1" id="turretModel" name="turretModel" data-parent="turretType">',
      '           <option selected hidden disabled value="title">Grade</option>',
      '         </select>',
      '   </div>',
      '   <button class="html5-control" id="showTank" disabled>Show</button>',
      ' </div>',
      '</div>'
    ].join('\n');
    
    var modal = null;
    var embedded_id = 'TankPreview';
    
    function fillDropdown(id, isParent){
      var _select = $("#" + id);
      _select.empty();
      var $keys;
      
      if(isParent){
        _select.append($('<option selected hidden disabled value="title">Model</option>'));
        $keys = $(Object.keys(Viewer.data[_select.data("category")]));
      } else {
        _select.append($('<option selected hidden disabled value="title">Grade</option>'));
        var _parent = $("#" + _select.data("parent"));
        var key = _parent.find("option:selected").val();
        $keys = $(Object.keys(Viewer.data[_parent.data("category")][key]));
      }
      
      $keys.each(function(k, v) {
        _select.append($('<option value="' + v + '">' + v + '</option>'));
      });
    }
    
    function onTypeChanged(){
      var childId = $(this).data("child");
      fillDropdown(childId, false);
      $("#" + childId).removeAttr("disabled");
    }
    
    function onSelectedChanged(){
      var flag = false;
      $("#TankPreview__controls select").each(function(i, el){
        flag = flag || ($(el).children(":selected").val() == "title");
      });
      if(flag){
        $("#showTank").attr("disabled", "disabled");
      } else {
        $("#showTank").removeAttr("disabled");
      }
    }
  
    function showTank(){
      var tank = Viewer.emptyTank();
      tank.hull.type = $("#hullType option:selected").val();
      tank.turret.type = $("#turretType option:selected").val();
      tank.hull.model = $("#hullModel option:selected").val();
      tank.turret.model = $("#turretModel option:selected").val();
      tank.paint.type = Viewer.currentPaint.type;
      tank.paint.model = Viewer.currentPaint.model;
      $("#TankPreview__viewer").empty().append('<div id="' + embedded_id + '"></div>');
      Viewer.appendViewer(tank, embedded_id);
    }
    
    function showTankPreviewModal(tank){
      modal = new tingle.modal({
        closeMethods: ['button', 'escape', 'overlay'],
        onOpen: function(){
          fillDropdown("hullType", true);
          fillDropdown("turretType", true);
          $("#hullType, #turretType").change(onTypeChanged);
          $("#TankPreview__controls select").change(onSelectedChanged);
          if(isDesktopChrome()){
            $("#TankPreview").append('<a href="https://get.adobe.com/flashplayer">Enable Adobe Flash Player</a>');
          }
          $("#showTank").click(showTank);
        },
        beforeClose: function(){
          $("#hullType, #turretType").off('change');
          $("#TankPreview__controls select").off('change');
          $("#showTank").off('click');
          return true;
        }
      });
      modal.setContent(templateMenu);
      /*tingle.modal.title("Preview on a tank");*/
      modal.open();
      $(".report-close").on("click", function() {modal.close();});
      $(".tingle-modal__close").remove();
      Viewer.appendViewer(tank, embedded_id);
    }

    $('.showPaint').click(function() {
      Viewer.currentPaint = { 
        "type": $(this).data('paintType'),
        "model": $(this).data('paintModel')
      };
      var tank = Viewer.getRandomTank();
      tank.paint.type = Viewer.currentPaint.type;
      tank.paint.model = Viewer.currentPaint.model;
      showTankPreviewModal(tank);
    });
    
  });
  
}

/*============================================================================================*/
//PrettySpoiler

if($(".pretty-spoiler").length) {

  var texts = { OPEN: "Reveal hidden contents", CLOSE: "Hide contents" };
  
  $('.pretty-spoiler > .title').click(function() {
    var content = $(this).next('div');
    changeTitleState($(this), content.is(":visible"));
    content.slideToggle(300);
  });

  function changeTitleState(elem, state) {
    if(state){
      elem.css("background-color", "rgba(255,255,255,0.1)");
      elem.prop('title', texts.OPEN);
    } else {
      elem.css("background-color", "rgba(255,255,255,0.3)");
      elem.prop('title', texts.CLOSE);
    }
    elem.children('.title-arrow').toggleClass('rotate180');
  }
}

/*============================================================================================*/
/*Upgrades calculator*/

if($('.item-upgrades-block').length){
  
  var isMouseDown = false;

  $('.item-upgrades-block').each(function(k,v){
    $(this).append('<span class="calc-mode bg-dark"><input id="calc-cb_' + k + '" type="checkbox"><label for="calc-cb_' + k + '">Calculator mode</label><span class="discounts hidden"><label for="calc-discount-step_' + k + '"> Upgrade discount: </label><input type="number" pattern="[0-9]{1,2}" value="0" min="0" max="95" step="5" class="step" id="calc-discount-step_' + k + '" ">% <label for="calc-discount-speed_' + k + '"> Speed-up discount: </label><input type="number" pattern="[0-9]{1,2}" value="0" min="0" max="95" step="5" class="speed" id="calc-discount-speed_' + k + '" ">% <button class="wiki-control grey-gradient reset" >Reset</button></span></span>');
    setInitial($(this).find('.item-upgrades-table'));
  });
  
  $(".item-upgrades-block input[type='checkbox']").change(function() {
    var parent = $(this).parents('.item-upgrades-block');
    var table = parent.find('.item-upgrades-table');
    var inputs = parent.find('input[type="number"], input[type="text"]');
    if(this.checked) {
      parent.find('.discounts').show();
      parent.find('.reset').on('click', function(){ reset(parent, table, 'soft'); });
      inputs.on('change keyup input', function(){ 
        $(this).focus();
        applyDiscount(this, parent);
        $(this).focus();
      });
      table.find('.sum').show();
      
      $(['speed','delay','step']).each(function(k,v){
        var n = k + 1;
        table.find("tr:not(.nocalc) td:nth-last-child(" + n + ")").on('mousedown', function(event){ 
          if(event.which == 1 || event.which == undefined) calculate(this, parent, v);
          if(event.which == 1) isMouseDown = true;
          return false;
        }).trigger('mousedown').on('mouseover', function(){
          if(isMouseDown) calculate(this, parent, v);
          return false;
        });
      });
      refreshSumAll(table);

    } else {
      parent.find('.reset').off('click');
      inputs.off('change');
      reset(parent, table, 'hard');
      table.find('.sum').hide();
      parent.find('.discounts').hide();
    }
  });

  function calculate(_this, parent, type) {
    var $this = $(_this);
    $this.toggleClass("highlighted");
    switch(type){
      case 'step':
        var value = parseInt($this.text());
        var td = parent.find('td.step');
        if ($this.hasClass("highlighted")) { td.text(parseInt(td.text()) + value); } 
        else { td.text(parseInt(td.text()) - value); }
        refreshSumAll(parent);
        break;
      case 'speed':
        var value = parseInt($this.text());
        var td = parent.find('td.speed');
        if ($this.hasClass("highlighted")) { td.text(parseInt(td.text()) + value); } 
        else { td.text(parseInt(td.text()) - value); }
        refreshSumAll(parent);
        break;
      case 'delay':
        var td = parent.find('td.delay');
        if ($this.hasClass("highlighted")) { 
          td.text(getDelay(getMinutes(td.text()) + getMinutes($this.text()))); 
        } else { 
          td.text(getDelay(getMinutes(td.text()) - getMinutes($this.text())));
        }
        break;
    }
    return false;
  };
    
  function applyDiscount(_this, parent) {
    var $this = $(_this);
    var _val = $this.val();
    if(parseInt(_val) > 95) $this.val(95);
    if(parseInt(_val.split('')[0]) == 0 && _val.length > 1) $this.val(_val.split('')[1]);
    if(parseInt(_val) < 0 || isNaN(parseInt(_val))) $this.val(0);

    $this.prop('disabled', true);
    var type, tdSum;
    if ($this.hasClass('step')) {
      type = 3;
      tdSum = parent.find('td.step');
    } else if ($this.hasClass('speed')) {
      type = 1;
      tdSum = parent.find('td.speed');
    } else return;

    var cells = parent.find('tr:not(.nocalc) td:nth-last-child(' + type + ')');
    var discount = parseFloat(((100 - parseInt($this.val())) / 100).toFixed(2));
    var sum = 0;
    cells.each(function(){
      var cur = $(this);
      var initialValue = parseInt(cur.data('initial'));
      var newValue = Math.floor(initialValue * discount);
      cur.text(newValue);
      if(cur.hasClass('highlighted')) sum += newValue;
    });
    tdSum.text(sum);
    refreshSumAll(parent);
    $this.prop('disabled', false);
  }
    
  function reset(parent, table, type){
    var cells = getCells(table);
    if(type == 'hard'){
      cells.off('mousedown mouseover');
    }
    parent.find('.discounts input[type="number"]').val('0').text('');
    table.find('td.step').text('0');
    table.find('td.delay').text('0');
    table.find('td.speed').text('0');
    table.find('td.sumAll').text('0');
    cells.each(function(){
      $(this).removeClass('highlighted');
      $(this).text($(this).data('initial'));
    });
  }  
  
  function getCells(table){
    return table.find("tr:not(.nocalc) td:nth-last-child(3),"
                      + "tr:not(.nocalc) td:nth-last-child(2), "
                      + "tr:not(.nocalc) td:nth-last-child(1)"
                     );
  }
  
  function setInitial(table){
    getCells(table).each(function(){
      $(this).data('initial', $(this).text());
    });
  }

  function refreshSumAll(table){
    table.find('td.sumAll').html(
      parseInt(table.find('td.step').text()) + 
      parseInt(table.find('td.speed').text())
    );
  }
  
  function getMinutes(s){
    var res = 0;
    $(s.split(' ')).each(function(){
      if(this.indexOf('d') != -1) {
        res += 24 * 60 * parseInt(this);
      }
      if(this.indexOf('h') != -1) {
        res += 60 * parseInt(this);
      }
      if(this.indexOf('m') != -1) {
        res += parseInt(this);
      }
    });
    return res;
  }

  function getDelay(time){
    if(time == 0) {
      return 0;
    }
    if(time < 60) {
      return time + 'm';
    }
    if (time >= 60 && time < 1440) {
      var minutes = time % 60;
      var hours = (time - minutes) / 60;
      if (minutes != 0) {
        return hours + 'h ' + minutes + 'm';
      } else {
        return hours + 'h';
      }
    }
    if (time >= 1440) {
      var minutes = time % 60;
      var t = (time - minutes) / 60;
      var hours = t % 24;
      var days = (t - hours) / 24;
      if (minutes != 0 && hours != 0) {
        return days + 'd ' + hours + 'h ' + minutes + 'm';
      }
      if (minutes != 0 && hours == 0) {
        return days + 'd ' + minutes + 'm';
      }
      if (minutes == 0 && hours != 0) {
        return days + 'd ' + hours + 'h';
      }
      if (minutes == 0 && hours == 0) {
        return days + 'd';
      }
    }
  }
  $(document).mouseup(function () {
    isMouseDown = false;
  });
}

/***********************************************************************************************/
/***Product kits filter/search feature*/

if (mw.config.values.wgPageName === 'Product_kits') { (function() {
  var hulls = {
    kind: 'hulls',
    values: ['Wasp', 'Hornet', 'Viking', 'Dictator', 'Hunter', 'Titan', 'Mammoth']
  };
  var turrets = {
    kind: 'turrets',
    values: ['Firebird', 'Freeze', 'Isida', 'Hammer', 'Twins', 'Ricochet', 'Smoky', 'Striker', 'Vulcan', 'Thunder', 'Railgun', 'Magnum', 'Gauss', 'Shaft']
  };
  
  function setFilters(checkAll) {
    filters[hulls.kind] = {
      shown: checkAll ? hulls.values.slice() : [],
      hidden: !checkAll ? hulls.values.slice() : [],
    };
    filters[turrets.kind] = {
      shown: checkAll ? turrets.values.slice() : [],
      hidden: !checkAll ? turrets.values.slice() : [],
    };
  }
  
  function applyFilters() {
    filters[hulls.kind].shown.forEach(function(value){
      $('tr[data-kit-hull="'+value+'"]').show();
    });
    filters[turrets.kind].shown.forEach(function(value){
      $('tr[data-kit-turret="'+value+'"]').show();
    });
    filters[hulls.kind].hidden.forEach(function(value){
      $('tr[data-kit-hull="'+value+'"]').hide();
    });
    filters[turrets.kind].hidden.forEach(function(value){
      $('tr[data-kit-turret="'+value+'"]').hide();
    });
  }
  
  function getCheckboxesHtml(entity, checked) {
    var htmlString = '';
    var checkedState = checked ? 'checked' : '';
    entity.values.forEach(function(value) {
      htmlString += '<label class="kit-filter-checkbox"><input class="tanki-control" type="checkbox" '+checkedState+' name="'+entity.kind+'" value="'+value+'">'+value+'</label>';
    });
    return htmlString;
  }
  
  function renderFilters(checked) {  
    var template = [
      '<fieldset>',
      '<legend>Show kits with hulls</legend>',
      getCheckboxesHtml(hulls, checked),
      '</fieldset>',
      '<fieldset>',
      '<legend>Show kits with turrets</legend>',
      getCheckboxesHtml(turrets, checked),
      '</fieldset>',
      '<button class="tanki-control" id="setChecked">Show all</button>',
      '<button class="tanki-control" id="setUnchecked">Clear all</button>',
    ].join('');
    $('#kit-filter').empty().html(template);
  }
  
  function bindListeners() {
    $('#kit-filter :checkbox').change(function() {
      var $this = $(this);
      var value = $this.val();
      var kind = $this.prop('name');
      if ($this.is(':checked')) {
        filters[kind].shown.push(value);
        filters[kind].hidden.splice(filters[kind].hidden.indexOf(value), 1);
      } else {
        filters[kind].hidden.push(value);
        filters[kind].shown.splice(filters[kind].shown.indexOf(value), 1);
      }
      applyFilters();
    });
    
    $('#kit-filter #setChecked').click(function() {
      setState(true);
    });
    $('#kit-filter #setUnchecked').click(function() {
      setState(false);
    });
  }
  
  function unbindListeners() {
    $('#kit-filter :checkbox').off();
    $('#kit-filter #setChecked').off();
    $('#kit-filter #setUnchecked').off();
  }
  
  function setState(flag) {
    setFilters(flag);
    unbindListeners();
    renderFilters(flag);
    bindListeners();
    applyFilters();
  }
  
  var filters = {};
  setFilters(true);
  renderFilters(true);
  bindListeners();
})();
}

/***********************************************************************************************/
/***Page filter/search feature*/

if($(".text-search").length) {
  var textSearchInputTemplate = [
  '<input class="text-search-input" type="search" autocomplete="on" placeholder="Search page" value="" />'
  ].join('\n');
  $(".text-search").before(textSearchInputTemplate);
  $(".text-search-input").bind("input", function() {
    var v = $(this).val().toLowerCase();
    $(".text-search p").filter(function() {
      $(this).toggle($(this).text().toLowerCase().indexOf(v) > -1);
      /* hide h3 headings on Dictionary page */
      if($(".text-search-input").val() != "") {
        $(".text-search").find("h3").hide();
      } else {
        $(".text-search").find("h3").show();
      }
    });
  });
}

if($(".text-search-paints").length) {
  var textSearchInputTemplate = [
  '<input class="text-search-input" type="search" autocomplete="on" placeholder="Search page" value="" />'
  ].join('\n');
  $(".text-search-paints").before(textSearchInputTemplate);
  $(".text-search-input").bind("input", function() {
    var v = $(this).val().toLowerCase();
    $(".text-search-paints table tbody tr td").filter(function() {
      $(this).toggle($(this).children("a").text().toLowerCase().indexOf(v) > -1);
    });
  });
}

/***********************************************************************************************/

if(mw.config.values.wgNamespaceNumber === 0){
  $('#bodyContent > .actions').append('<div class="vectorTabs customReport" style="float: right;"><ul><li><span><a href="#" title="Report a Wiki related error or add a suggestion">Report</a></span></li></ul></div>');
}

if(
  mw.config.values.wgNamespaceNumber === 0
  && mw.config.values.wgArticleId !== 1457
  && mw.config.values.wgArticleId !== 2226
  && mw.config.values.wgArticleId !== 3
  && mw.config.values.wgArticleId !== 634
){
  $( '#mw-content-text' ).append( '<div id = "custom-report-footer">Error or typo in the text? Select it with the mouse and press <kbd style="font-weight:bold;">Ctrl</kbd> + <kbd style="font-weight:bold;">Enter</kbd> to inform our Wiki Editors about it!</div>' );
}

var formTemplate = [
  '<div class="report-head"><div class="report-title">Report an error</div><div class="report-stripes"></div><div class="report-close"></div></div></div>',
  '<form id="custom-report-form" enctype="multipart/form-data">',
  '  <input type="hidden" name="lang" value="en">',
  '  <div class="disclaimer">Please <strong>do not</strong> use this form for complaints regarding a ban or block. This form is only to be used for <strong>wiki-related</strong> mistakes or suggestions.</div>',
  '  <div class="custom-report-nickname">',
  '    <div class="field-description">Your nickname <span class="red-asterisk"></span></div>',
  '    <input class="report-input-field" type="text" id="field-nickname" autocomplete="off" autofocus maxlength="20" name="nickname">',
  '    <div class="error"></div>',
  '  </div>',
  '  <div class="custom-report-pageurl">',
  '    <div class="field-description">Link to page <span class="red-asterisk"></span></div>',
  '    <div class="field-description more">We already filled this field in for you, but if it\'s incorrect, please copy the link to the correct page from the address bar in your browser and paste it here.</div>',
  '    <input class="report-input-field" type="text" id="field-pageurl" autocomplete="off" name="pageurl">',
  '    <div class="error"></div>',
  '  </div>',
  '  <div class="custom-report-message">',
  '    <div class="field-description">Your message <span class="red-asterisk"></span></div>',
  '    <div class="field-description more">Tell us what you would like to see changed on this page, or point out the mistake or outdated info. You may insert links to screenshots.</div>',
  '    <textarea class="report-input-field" id="field-message" name="message" maxlength="1000"></textarea>',
  '    <div class="error"></div>',
  '  </div>',
  '  <div id="recaptcha-wrapper">',
  '    <div class="error"></div>',
  '  </div>',
  '  <div class="custom-report-submit" tabindex="0">',
  '    <input type="submit" id="button-submit" name="submit" value="Send" tabindex="-1">',
  '  </div>',
  '  <img id="spinner" src="loading.gif">',
  '  <span class="custom-report-result"></span>',
  '</form>'
  ].join('\n');

function isNicknameValid(nickname){
  return (
    typeof nickname == 'string' &&
    new RegExp(/^[a-zA-Z0-9\-\_\.]{1,20}$/).test(nickname) &&
    new RegExp(/^[^\.\-\_](.*[^\.\-\_])?$/).test(nickname) &&
    !new RegExp(/(.)\1{5,}/g).test(nickname) &&
    _checkRepeated(nickname)          
  );
  function _checkRepeated(nick){
    var reg = new RegExp(/[\-\_\.]{2,}/g);
    var matches = nick.match(reg) || [];
    return matches.length > 0 ? (matches.length == 1 && matches[0].length==2 && nick.search(reg)==1) : true;
  }
}

function printError(_for, _message){
  $("#field-" + _for + " + .error").append(_message);
}

function getInputValues(){
  return {
    "nickname": $("#field-nickname").val(),
    "pageurl": $("#field-pageurl").val(),
    "message": $("#field-message").val(),
    "captcha": $("#g-recaptcha-response").val()
  }
}

function validateForm(type, obj){
  if(!(type === 'client' || type === 'server')) return false;
  $(".error").empty();
  if(type == 'server' && obj.status) return true;
  var regex;
  if(type == 'client') regex = new RegExp(/^(https?\:\/\/)?(ru|en|de|pl|br|es)\.tankiwiki\.com\/.*$/);
  var result = true;

  if((type == 'client' && !isNotEmpty(obj.captcha)) || (type == 'server' && obj.errors.indexOf(-1) > -1)){
    $("#recaptcha-wrapper > .error").html("This field is required");
    result = false;
  }
    
  if((type == 'client' && isNotEmpty(obj.nickname)) || (type == 'server' && obj.errors.indexOf(10) == -1)){
    if((type == 'client' && !isNicknameValid(obj.nickname)) || (type == 'server' && obj.errors.indexOf(11) > -1)){
      printError("nickname", "Incorrect nickname");
      result = false;
    }
  } else {
    printError("nickname", "This field is required");
    result = false;
  }
      
  if((type == 'client' && isNotEmpty(obj.pageurl)) || (type == 'server' && obj.errors.indexOf(20) == -1)){
    if((type == 'client' && !regex.test(obj.pageurl)) || (type == 'server' && obj.errors.indexOf(21) > -1)){      
      printError("pageurl", "Incorrect Wiki page link");
      result = false;
    }
  } else {
    printError("pageurl", "This field is required");
    result = false;
  }
      
  if((type == 'client' && isNotEmpty(obj.message)) || (type == 'server' && obj.errors.indexOf(30) == -1)){
    if((type == 'client' && obj["message"].length > 1000) || (type == 'server' && obj.errors.indexOf(31) > -1)){  
      printError("message", "The length of the message cannot exceed 1000 symbols");
      result = false;
    }
  } else {
    printError("message", "This field is required");
    result = false;
  } 
  
  return result;
}

function onFormSubmit(e){
  e.preventDefault();
  if(validateForm('client', getInputValues())){
    $(".custom-report-submit").hide();
    $("#spinner").css('display', 'inline-block');
    $(".custom-report-result").html("Sending...");
    $.post("custom/wiki_report.php", $("#custom-report-form").serialize(), function(response){
      if(validateForm('server', response)){
        $("#spinner").hide();
        $(".custom-report-result").html("Thank you, we have received your report! We will review and act upon it as soon as possible!");
        setTimeout(closeModal, 2000);
      } else {
        $("#spinner").hide();
        $(".custom-report-submit").show();
      }
    });
  }
}

var modal = null;

var Recaptcha = {
  id: null,
  container: $('<div id="recaptcha"></div>')[0],
  create: function(){
    if(null === Recaptcha.id) {
      Recaptcha.id = grecaptcha.render(Recaptcha.container, {
        'sitekey' : '6LdZ6D4UAAAAAEnOOpR4RhNNCbgxVnXVacWPQBaS',
        'theme': 'dark'
      });
    } else {
      grecaptcha.reset(Recaptcha.id);
    }
    return Recaptcha.container;
  }
}

function showCustomReportForm(selection){
  modal = new tingle.modal({
    closeMethods: ['escape', 'overlay'],
    onOpen: function(){
      $("#custom-report-form").submit(onFormSubmit);
      $("#field-pageurl").val(decodeURIComponent(location.href));
      if(typeof selection === 'string'){
        $("#field-message").val('"'+selection+'":\n');
      }
    },
    beforeClose: function(){
      $("#custom-report-form").off('submit');
      return true;
    }
  });
  modal.setContent(formTemplate);
  modal.open();
  $(".report-close").on("click", function() {closeModal();});
  $(".custom-report-submit").on("click", function() {
    $("#button-submit")[0].click();
  });
  $(".tingle-modal__close").remove();
  $("#recaptcha-wrapper").prepend(Recaptcha.create());
}

function closeModal(){
  modal.close();
}

$(".customReport").click(showCustomReportForm);

$(document).on('keydown', function (e) {
  var text = getSelectedText();
  if(text && (e.metaKey || e.ctrlKey) && e.which === 13 && (!modal || !modal.isOpen())) {
    showCustomReportForm(text);
  }
});

/*====================================================================================*/
/* Page Previews */

if(mw.config.values.wgNamespaceNumber === 0 && mw.config.values.wgPageName === "Test") {
  var pagePreviewsURL = "images/en/0/06/PagePreviews.json?v=003";
  var pagePreviewsObj = {};
  $.getJSON(pagePreviewsURL, function(data){
    pagePreviewsObj = data;
  });
  
  $("#mw-content-text a:not([rel='nofollow'])").hover(
    function() {
      var pagePreviewTemplate = [
      '<div class="page-preview">',
        '<div class="page-preview-heading"></div>',
        '<div class="page-preview-content">',
          'Loading...',
        '</div>',
        '<div class="page-preview-thumb"></div>',
      '</div>'
      ].join('\n');
      var pagePreviewTimeoutDuration = 650;
      var pagePreviewOffset = $(this).offset();
      var pagePreviewLink = $(this).attr('href');
      var pagePreviewPageName = $(this).attr('title');
      $("#mw-content-text").append(pagePreviewTemplate);
      $(".page-preview-heading").html(pagePreviewPageName);
      var pagePreviewsObjIndex = 0;
      var pagePreviewsObjFiltered = pagePreviewsObj.pagePreviews.find(function(pagePreviewsItem, pagePreviewsObjCounter){
        if(pagePreviewsItem.pageName === pagePreviewPageName){
          pagePreviewsObjIndex = pagePreviewsObjCounter;
          return pagePreviewsObjCounter;
        }
      });
      var pagePreviewsContent = pagePreviewsObj.pagePreviews[pagePreviewsObjIndex].pageDescription;
      $(".page-preview-content").html(pagePreviewsContent);
      $(".page-preview-thumb").css("background-image", "url('" + pagePreviewsObj.pagePreviews[pagePreviewsObjIndex].pageThumbnail + "')");
      $(".page-preview").css({
        left: pagePreviewOffset.left - 70,
        top: pagePreviewOffset.top -30,
        display: "none"
      });
      var pagePreviewTimeout = setTimeout(function() {
        $(".page-preview").fadeIn("fast");
        $(".page-preview").on("click", function() {
          window.location.pathname = pagePreviewLink;
        });
      }, pagePreviewTimeoutDuration);
    }, function() {
        $(".page-preview").fadeOut("fast");
        $(".page-preview").remove();
        clearTimeout(pagePreviewTimeout);
    }
  );
}

/*====================================================================================*/
/*YouTube Popup*/

if($('.ShowYouTubePopup').length){
  var modal = null;
  $('.ShowYouTubePopup').click(function () {
    showYouTubeModal($(this).data('id'));
  });
  function showYouTubeModal(yid){
    modal = new tingle.modal({
      closeMethods: ['button', 'escape', 'overlay']
    });
    modal.setContent('<div class="report-head"><div class="report-title">Watch video</div><div class="report-stripes"></div><div class="report-close"></div></div></div><div style="margin: 15px 10px 10px 10px; background: url("loading.gif") center no-repeat;"><iframe class="yt-video" width="640px" height="360px" src="https://www.youtube.com/embed/' + yid + '" frameborder="0" allowfullscreen></iframe></div>');
    modal.open();
    $(".report-close").on("click", function() {modal.close();});
    $(".tingle-modal__close").remove();
  }
}

/*====================================================================================*/
//RndTxt Template

if ($('#RandomTextContainer').length) {
  var facts = $('#RandomTextContainer > div').toArray();
  $(getRandomVal(facts)).show();
  $('#RandomTextRefresher').click(function () {
    $(facts).hide();
    $(getRandomVal(facts)).show();
  })
}

/*====================================================================================*/
//Rank limits embedded iframe

if($("#RankLimits").length){
  $("#RankLimits").append("<iframe frameborder='0' style='width:844px;height:758px;' scrolling='no' src='https://docs.google.com/spreadsheets/d/1YK7-kS6MpvT23HDycI79zdFn3lCphG8iwrl-w_HPosY/pubhtml?gid=1621919985&single=true&widget=false&chrome=false&headers=false'></iframe>");
}

/*============================================================================================*/

$(".linkElem").on('click', function(){ window.open($(this).data("url"),"_blank"); });

/*jQuery(document).ready() ends here*/
});