MediaWiki:Common.js: Difference between revisions

From HorizonXI Wiki
No edit summary
m (sorting should now work on mobile)
 
(64 intermediate revisions by 2 users not shown)
Line 1: Line 1:
mw.loader.getScript( 'https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js' );
mw.loader.getScript( 'https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js' );
mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:VanaTime.js' );
mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:ASBSearch.js' );
//mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:FFXIWeatherForecast.js' );


var tooltips = {
var tooltips = {
Line 434: Line 437:
});
});


//*********************************************************************
////////////////////////////////////////
// Javascript below contributes to live Vana'diel Time listed in Sidebar
///////    Move to Top: Button  //////
// All code taken from: https://www.pyogenes.com/ffxi/timer/v2.html
const button_scrollToTop = document.createElement('button');
//***************************
button_scrollToTop.className = "mainpage-button-scrollToTop";
basisDate = new Date();
button_scrollToTop.innerHTML = '<img src="https://horizonffxi.wiki/w/images/0/06/Up_arrow.png" style="width: 25px; height: 25px;"/>';
basisDate.setUTCFullYear(2002, 5, 23); // Set date to 2003-06-23
//button_scrollToTop.style = "right: 2%; background: #FFFFFF; opacity: 1; position: fixed; display: none; border-radius: 10px; border: 0.5px solid #a7a7a7; box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5); z-index: 1000;"
basisDate.setUTCHours(15, 0, 0, 0);    // Set time to 15:00:00.0000
document.body.appendChild(button_scrollToTop);
Mndate = new Date();
Mndate.setUTCFullYear(2004, 0, 25); // Set date to 2004-01-25
Mndate.setUTCHours(2, 31, 12, 0);    // Set time to 02:31:12.0000
msGameDay = (24 * 60 * 60 * 1000 / 25); // milliseconds in a game day
msRealDay = (24 * 60 * 60 * 1000); // milliseconds in a real day
VanaDay = new Array("Firesday", "Earthsday", "Watersday", "Windsday", "Iceday", "Lightningday", "Lightsday", "Darksday");
DayColor = new Array("#DD000", "#AAAA00", "#0000DD", "#00AA22", "#7799FF", "#AA00AA", "#AAAAAA", "#333333");
//PhaseName = new Array("Full Moon","Waning Gibbous","Last Quarter","Waning Crescent","New Moon","Waxing Crescent","First Quarter","Waxing Gibbous");
PhaseName = new Array('\u{1F315}','\u{1F316}','\u{1F317}','\u{1F318}','\u{1F311}','\u{1F312}','\u{1F313}','\u{1F314}');
function resetGameTime() {
// **** Game time
var now = new Date();
vanaDate =  ((898 * 360 + 30) * msRealDay) + (now.getTime() - basisDate.getTime()) * 25;


vYear = Math.floor(vanaDate / (360 * msRealDay));
button_scrollToTop.addEventListener("click", function() {
vMon  = Math.floor((vanaDate % (360 * msRealDay)) / (30 * msRealDay)) + 1;
  $("html, body").animate({ scrollTop: 0 }, "slow");
vDate = Math.floor((vanaDate % (30 * msRealDay)) / (msRealDay)) + 1;
  return false;
vHour = Math.floor((vanaDate % (msRealDay)) / (60 * 60 * 1000));
});
vMin  = Math.floor((vanaDate % (60 * 60 * 1000)) / (60 * 1000));
vSec  = Math.floor((vanaDate % (60 * 1000)) / 1000);
vDay  = Math.floor((vanaDate % (8 * msRealDay)) / (msRealDay));


if (vYear < 1000) { VanaYear = "0" + vYear; } else { VanaYear = vYear; }
// //https://stackoverflow.com/questions/31223341/detecting-scroll-direction
if (vMon  < 10)   { VanaMon  = "0" + vMon; }  else { VanaMon  = vMon; }
// function scrollEventThrottle(fn) {
if (vDate < 10)   { VanaDate = "0" + vDate; } else { VanaDate = vDate; }
//   var last_known_scroll_position = 0;
if (vHour < 10)   { VanaHour = "0" + vHour; } else { VanaHour = vHour; }
//   var ticking = false;
if (vMin  < 10)  { VanaMin  = "0" + vMin; }  else { VanaMin  = vMin; }
//   window.addEventListener("scroll", function () {
if (vSec  < 10)   { VanaSec  = "0" + vSec; }  else { VanaSec  = vSec; }
//     var previous_known_scroll_position = last_known_scroll_position;
//    last_known_scroll_position = window.scrollY;
// Moon phase
//    if (!ticking) {
var timenow = new Date();
//      window.requestAnimationFrame(function () {
    var localTime = timenow.getTime();
//         fn(last_known_scroll_position, previous_known_scroll_position);
    var moonDays = (Math.floor((localTime - Mndate.getTime()) / msGameDay))  % 84;
//        ticking = false;
//       });
    var mnElapsedTime = (localTime - Mndate.getTime()) % msGameDay;
//      ticking = true;
//    }
    // determine phase percentage
//  });
        moonpercent = - Math.round((42 - moonDays) / 42 * 100);
// }
        if (moonpercent <= -94)  {
            mnPhase = 0;
            optPhase = 4;
            toNextPhase = (3 - moonDays) * msGameDay - mnElapsedTime;
            toOptimalPhase = (38 - moonDays) * msGameDay - mnElapsedTime;


        }  else if (moonpercent >= 90) {
// scrollEventThrottle(function(scrollPos, previousScrollPos) {
    mnPhase = 0;
//    if (previousScrollPos > scrollPos && scrollPos >= 400) {
            optPhase = 4;
// if(window.getComputedStyle(button_scrollToTop).display !== "block") {
            toNextPhase = (87 - moonDays) * msGameDay - mnElapsedTime;
// button_scrollToTop.style.display = "block";
            toOptimalPhase = (38 + 84 - moonDays) * msGameDay - mnElapsedTime;
// if (document.body.clientWidth >= 850) button_scrollToTop.style.top = "60px";
// else button_scrollToTop.style.top = "5px";
// }
//    } else {
//      button_scrollToTop.style.display = "none";
//    }
// });


        }  else if (moonpercent >= -93 && moonpercent <= -62)  {
var previousScrollPos = 0;
      mnPhase = 1;
var lastScrollPos = 0;
            optPhase = 4;
var performing = false;
            toNextPhase = (17 - moonDays) * msGameDay - mnElapsedTime;
            toOptimalPhase = (38 - moonDays) * msGameDay - mnElapsedTime;


        } else if (moonpercent >= -61 && moonpercent <= -41) {
/**
      mnPhase = 2;
* show the button #scroll-to-top only
            optPhase = 4;
* on bottom part of the page
            toNextPhase = (25 - moonDays) * msGameDay - mnElapsedTime;
  */
            toOptimalPhase = (38 - moonDays) * msGameDay - mnElapsedTime;
const b = document.querySelector('.mainpage-button-scrollToTop');
//console.log(document.querySelector('.mainpage-button-scrollToTop'));
function toggleVisibility(scrollPos, buttonId) {
//console.log(previousScrollPos, scrollPos);
  if(previousScrollPos > scrollPos && scrollPos > 500) {
  //console.log("showing" + $(buttonId));
    if(window.getComputedStyle(b).display !== "block") {
button_scrollToTop.style.display = "block";
if (document.body.clientWidth >= 850) button_scrollToTop.style.top = "60px";
else button_scrollToTop.style.top = "5px";
}
  }
  else {
button_scrollToTop.style.display = "none";
  }
}


        }  else if (moonpercent >= -40 && moonpercent <= -11) {
document.addEventListener('scroll', function(evt) {
      mnPhase = 3;
  //console.log(performance.now())
            optPhase = 4;
previousScrollPos = lastScrollPos;
            toNextPhase = (38 - moonDays) * msGameDay - mnElapsedTime;
lastScrollPos = window.scrollY;
            toOptimalPhase = (38 - moonDays) * msGameDay - mnElapsedTime;
  if(!performing) {
    setTimeout(function () {
      toggleVisibility(lastScrollPos, 'mainpage-button-scrollToTop');
      performing = false;
    }, 100);
  }
  performing = true;
}, {passive: true}) ;
////////////////////////////////////////


        }  else if (moonpercent >= -10 && moonpercent <= 6)  {
// function that sorts a table on page load
      mnPhase = 4;
// based on the column header which has one of the classes sort-col-1, sort-col-2, ...
            optPhase = 0;
            toNextPhase = (45 - moonDays) * msGameDay - mnElapsedTime;
            toOptimalPhase = (80 - moonDays) * msGameDay - mnElapsedTime;


        }  else if (moonpercent >= 7 && moonpercent <= 36) {
window.addEventListener('load', function() {
      mnPhase = 5;
    // Add a small delay to ensure everything is loaded, especially on slower mobile networks
            optPhase = 0;
    setTimeout(function() {
            toNextPhase = (58 - moonDays) * msGameDay - mnElapsedTime;
        // Select all tables with classes that match "sort-col-1" through "sort-col-6"
            toOptimalPhase = (80 - moonDays) * msGameDay - mnElapsedTime;
        var tables = document.querySelectorAll('.sortable.sort-col-1, .sortable.sort-col-2, .sortable.sort-col-3, .sortable.sort-col-4, .sortable.sort-col-5, .sortable.sort-col-6');


        }  else if (moonpercent >= 37 && moonpercent <= 56) {
        // Loop through each table and determine the column to sort by based on its class
      mnPhase = 6;
        Array.prototype.forEach.call(tables, function(table) {
             optPhase = 0;
             // Find which "sort-col-X" class is applied to the table
             toNextPhase = (66 - moonDays) * msGameDay - mnElapsedTime;
             var classList = Array.prototype.slice.call(table.classList);
             toOptimalPhase = (80 - moonDays) * msGameDay - mnElapsedTime;
             var sortClass = null;


        }  else if (moonpercent >= 57 && moonpercent <= 89) {
            for (var i = 0; i < classList.length; i++) {
      mnPhase = 7;
                if (classList[i].indexOf('sort-col-') === 0) {
            optPhase = 0;
                    sortClass = classList[i];
            toNextPhase = (60 - moonDays) * msGameDay - mnElapsedTime;
                    break;
            toOptimalPhase = (80 - moonDays) * msGameDay - mnElapsedTime;
                }
        }
            }


        mnpercent = PhaseName[mnPhase]  + Math.abs(moonpercent) + "%";
            if (sortClass) {
 
                // Extract the column number from the class name (e.g., "sort-col-3" => 3)
        if (moonpercent <= 5 && moonpercent >= -10) {
                var columnIndex = parseInt(sortClass.replace('sort-col-', ''), 10) - 1; // Convert to 0-based index
              mnpercent = "<FONT COLOR='#FF0000'>" + mnpercent+ "</FONT>";
               
        } else if (moonpercent >= 90 || moonpercent <= -95)  {
                // Find the header cell for the specified column index
              mnpercent = "<FONT COLOR='#0000FF'>" + mnpercent+ "</FONT>";
                var headerCell = table.querySelectorAll('th')[columnIndex];
        }
               
 
                // If the header cell exists, simulate a click on it to trigger sorting
  //nextPhase = "Next phase (" + PhaseName[(mnPhase + 1) % 8] + "): " + formatCountdown(toNextPhase);
                if (headerCell) {
  //nextOptPhase = "Next " + PhaseName[optPhase] + ": " + formatCountdown(toOptimalPhase);
                    headerCell.click()
                }
//draw to sidebare element
            }
VanaTime = "<div><li><b>" + VanaHour + ":" + VanaMin + "</b>  ~  " + VanaYear + "-" + VanaMon + "-" + VanaDate + "</li>";
        });
VanaTime += "<li><b><font color=" + DayColor[vDay] + ">" + VanaDay[vDay] + " ~ " + mnpercent + "</font></b></li>";
    }, 500); // 500ms delay to help on slower devices
// VanaTime += "<li><b>" + VanaYear + "-" + VanaMon + "-" + VanaDate + "</b></li></div>";
});
VanaTime += "</div>";
 
document.getElementById("n-vanatime").innerHTML = VanaTime;
const collection = document.getElementsByClassName("example");
//console.log("here:" + collection.length);
// if (collection.length != undefined) {
//for (let i = 0; i < collection.length; i++) { collection[i].textContent = VanaTime; }
setTimeout("resetGameTime()", 50);
}
resetGameTime();
//*********************************************************************

Latest revision as of 18:50, 14 November 2024

mw.loader.getScript( 'https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js' );
mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:VanaTime.js' );
mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:ASBSearch.js' );
//mw.loader.getScript( '/w/index.php?action=raw&ctype=text/javascript&title=MediaWiki:FFXIWeatherForecast.js' );

var tooltips = {
    debug: false,
    
    api: false,
    types: [],
    classes: ['basic-tooltip', 'advanced-tooltip'],
    advancedCounter: 1,
    
    events: [],
    timeouts: [],
    
    offsetX: 20,
    offsetY: 20,
    waitForImages: true,
    noCSS: false,
    
    flip: false,
    
    init: function() {
        if($(document.body).hasClass('mw-special-InfoboxBuilder')) return;
        if(location.search.search(/ttdebug=(1|[Tt]rue)/) != -1 || (typeof tooltips_debug != 'undefined' && tooltips_debug)) tooltips.debug = true;

        url = new URL($('link[rel="canonical"]').attr('href'));

        if(typeof url == 'undefined' || !url) {
            console.log('Tooltips: script couldn\'t find required  link[rel="canonical"]  tag');
            tooltips.disabled = true;
            return false;
        }
        tooltips.api = url.host+'/api.php?format=json&action=parse&disablelimitreport=true&prop=text&title='+url.pathname;
        if(mw.util.getParamValue('uselang')) tooltips.api += '&uselang='+mw.util.getParamValue('uselang');
		// Cache tooltip contents on the CDN for 10 minutes for anonymous users
		tooltips.api += '&maxage=600&smaxage=600'
        tooltips.api += '&text=';
        
        tooltips.types['basic-tooltip'] = {};
        tooltips.types['advanced-tooltip'] = {};
        
        if(!tooltips.config()) {
            console.log('Tooltips: missing config');
            tooltips.disabled = true;
            return false;
        }
        
        var content = $('#WikiaMainContent');
        if(!content.length) content = $('#mw-content-text');
                
        if($('#tooltip-wrapper').length === 0) $('<div id="tooltip-wrapper" class="WikiaArticle"></div>').appendTo(document.body);
        if($('#tooltip-storage').length === 0) $('<div id="tooltip-storage" class="WikiaArticle"></div>').append('<div class="main-tooltip tt-basic-tooltip" id="tooltip-basic-tooltip">Lorem ipsum dolor sit amet</div>').appendTo(content);
        
        $('#tooltip-wrapper')
            .css({'margin':'0px','position':'fixed','height':'auto','min-height':'0','z-index': 6000000,'font-size':'14px'})
            .hide();
        
        $('#tooltip-storage')
            .css({'height':'0px','min-height':'0','visibility':'hidden','overflow':'hidden','position':'static','font-size':'14px'});

        $('#tooltip-basic-tooltip').data('type', 'basic-tooltip');
        
        tooltips.applyTooltips(document);
        
        mw.hook('wikipage.content').add(function(elem) {
            tooltips.applyTooltips($(elem));
        });
        
        if(typeof tooltips.events == 'string') tooltips.events = [tooltips.events];
        for(var x=0; x<tooltips.events.length; x++) { $(window).on(tooltips.events[x], function(ev, elem) { tooltips.applyTooltips(elem || this) }) }
        
        if(tooltips.debug) {
            $('#tooltip-wrapper').css({'background-color':'rgba(255,0,0,0.2)'});
            $('#tooltip-storage').css({'background-color':'rgba(0,255,0,0.2)','height':'500px','overflow-y':'scroll','visibility':'visible'});
        }
    },
    config: function() {
        if(typeof tooltips_list != 'undefined') {
            $(tooltips_list).each(function(i, v) { tooltips.addType(v) });
        }
        if(typeof tooltips_config == 'object') {
            tooltips.offsetX = tooltips_config.offsetX || tooltips.offsetX;
            tooltips.offsetY = tooltips_config.offsetY || tooltips.offsetY;
            tooltips.waitForImages = (tooltips_config.waitForImages || tooltips.waitForImages) && true;
            tooltips.noCSS = tooltips_config.noCSS || tooltips.noCSS;
            tooltips.events = tooltips_config.events || tooltips.events;
        }
        
        return true;
    },
    applyTooltips: function(elem) {
        $(elem).find('.'+tooltips.classes.join(', .')).each(function() {
            $this = $(this);
            if($this.hasClass('tooltips-init-complete')) return;
            
            $this.find('*').removeAttr('title');
            $this.mouseover(tooltips.handlers.mouseOver);
            $this.mouseout(tooltips.handlers.mouseOut);
            $this.mousemove(tooltips.handlers.mouseMove);
            
            $this.data('tooltip-contents', $(this).attr('title'));
            $this.removeAttr('title');
            
            tooltips.advancedTooltip($this);
            
            $(this).addClass('tooltips-init-complete');
        });
    },
    advancedTooltip: function(elem) {
        elem = $(elem);
        if(!elem.hasClass('advanced-tooltip')) return;
        var tips = elem.find('.tooltip-contents');
        if(!tips.length) return;
        var tip = $('<div class="main-tooltip tt-advanced-tooltip"></div>').attr('id', 'tooltip-advanced-tooltip-'+tooltips.advancedCounter).appendTo('#tooltip-storage').data('type', 'advanced-tooltip').append($(tips[0]).contents()).each(tooltips.calcSize);
        tips.remove();
        elem.data('tooltip-id-advanced-tooltip', tooltips.advancedCounter);
        tooltips.advancedCounter++;
    },
    addType: function(tt) {
        if(typeof tooltips.types[tt.classname] == 'undefined') {
            var obj = {};
            
            if(typeof tt.parse == 'string' || typeof tt.parse == 'function') var parse = tt.parse; else var parse = false;
            if(typeof tt.text == 'string' || typeof tt.text == 'function') var text = tt.text; else var text = false;
            
            if(parse) {
                obj.text = parse;
                obj.parse = true;
            } else if(text) {
                obj.text = text;
                obj.parse = false;
            } else return;
            
            if(typeof obj.text == 'string') obj.parameters = tooltips.getParameters(obj.text); else obj.parameters = [];
            
            if(typeof tt.delay == 'string' || typeof tt.delay == 'number') obj.delay = parseInt(tt.delay); else obj.delay = false;
            if(typeof tt.onParsed == 'function') obj.onParsed = tt.onParsed;
            if(typeof tt.onShow == 'function') obj.onShow = tt.onShow;
            if(typeof tt.onHide == 'function') obj.onHide = tt.onHide;
            
            tooltips.types[tt.classname] = obj;
            if(tooltips.classes.indexOf(tt.classname) == -1) tooltips.classes.push(tt.classname);
        } else {
            if(typeof tt.delay == 'string' || typeof tt.delay == 'number') tooltips.types[tt.classname].delay = parseInt(tt.delay);
            if(typeof tt.onParsed == 'function') tooltips.types[tt.classname].onParsed = tt.onParsed;
            if(typeof tt.onShow == 'function') tooltips.types[tt.classname].onShow = tt.onShow;
            if(typeof tt.onHide == 'function') tooltips.types[tt.classname].onHide = tt.onHide;
        }
    },
    getParameters: function(text) {
        var list = [];
        var matches = text.match(/<#\s*[a-z0-9_\-]+?\s*#>/gi);
        if(matches) {
            for(var x=0; x<matches.length; x++) {
                list.push(/<#\s*([a-z0-9_\-]+?)\s*#>/i.exec(matches[x])[1]);
            }
        }
        return list;
    },
    getAPI: function(text) {
        return tooltips.api+encodeURIComponent(text);
    },
    getText: function(type, elem) {
        if(typeof tooltips.types[type].text == 'function') {
            var text = tooltips.types[type].text($(elem)[0]);
        } else {
            var text = tooltips.types[type].text;
            for(var x=0; x<tooltips.types[type].parameters.length; x++) {
                var param = tooltips.types[type].parameters[x];
                var value = $(elem).data(param);
                if(typeof value == 'undefined') value = '';
                var rx = new RegExp('<#\\s*'+param.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")+'\\s*#>', 'g');
                text = text.replace(rx, value);
            }
        }
        return text;
    },
    getTooltip: function(type, elem) {
        elem = $(elem);
        if(elem.data('tooltip-id-'+type)) return $('#tooltip-'+type+'-'+elem.data('tooltip-id-'+type));
        
        var text = tooltips.getText(type, elem);
        var id = tooltips.hash(text);
        elem.data('tooltip-id-'+type, id);
        
        var tip = $('#tooltip-'+type+'-'+elem.data('tooltip-id-'+type));
        if(tip.length) return tip;
        
        tip = $('<div class="main-tooltip"></div>').attr('id', 'tooltip-'+type+'-'+id).appendTo('#tooltip-storage').data('type', type).addClass('tt-'+type);
        
        tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]);
        tooltips.sameWidth();
        
        if(!tooltips.types[type].parse) {
            tip.html(text).each(tooltips.calcSize);
            tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]);
            tooltips.sameWidth();
        } else {
            tip.addClass('tooltip-loading');
            var api = tooltips.getAPI(text);
            if(tooltips.debug) tip.html('<pre style="padding:2px 3px;font-size:11px;">'+api+'</pre>');
            tip.attr('title', api);
            $.ajax({
                url: api,
                dataType: 'json',
                context: tip,
                success: function(data, textStatus, jqXHR) {
                    $(this).html(data['parse']['text']['*']).each(tooltips.calcSize);
                    tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]);
                    tooltips.sameWidth();
                    var images = $(this).find('img');
                    images.fadeTo(0, 0).one('load', function() {
                        if(tooltips.waitForImages) {
                            $(this).fadeTo(0,1);
                            $(this).addClass('image-loaded');
                            tip = $(this).closest('.main-tooltip');
                            if(tip.find('img').length == tip.find('img.image-loaded').length) {
                                tip.removeClass('tooltip-loading').each(tooltips.calcSize);
                                tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]);
                                tooltips.sameWidth();
                            }
                        } else $(this).fadeTo(100,1);
                    });
                    if(tooltips.waitForImages) {
                        if(images.length === 0) {
                            $(this).removeClass('tooltip-loading').each(tooltips.calcSize);
                        }
                    } else {
                        $(this).removeClass('tooltip-loading').each(tooltips.calcSize);
                    }
                    var type = $(this).data('type') || false;
                    if(type && typeof tooltips.types[type].onParsed == 'function') {
                        tooltips.types[type].onParsed.call(this);
                        tip.each(tooltips.calcSize);
                    }
                    if($(this).find('a.new').length > 0) $(this).addClass('has-redlinks');
                    tooltips.wrapperPosition(tooltips.lastKnownMousePos[0], tooltips.lastKnownMousePos[1]);
                    tooltips.sameWidth();
                }
            });
        }
        return tip;
    },
    getBasicTooltip: function(elem) {
        return $("#tooltip-basic-tooltip").html(mw.html.escape($(elem).data('tooltip-contents')).replace(/\\n/g,'<br />')).each(tooltips.calcSize);
    },
    getAdvancedTooltip: function(elem) {
        return $("#tooltip-advanced-tooltip-"+$(elem).data('tooltip-id-advanced-tooltip'));
    },
    getTooltips: function(elem) {
        elem = $(elem);
        var classes = elem.attr('class').split(' ');
        var tips = [];
        for(var i=0;i<classes.length;i++) {
            var tip = false;
            if(classes[i] == 'advanced-tooltip') tip = tooltips.getAdvancedTooltip(elem);
            else if(classes[i] == 'basic-tooltip') tip = tooltips.getBasicTooltip(elem);
            else if(typeof tooltips.types[classes[i]] != 'undefined') tip = tooltips.getTooltip(classes[i], elem);
            if(tip) tips.push(tip[0]);
        }
        return $(tips);
    },
    setOwnWidth: function() {
        $this = $(this);
        if(typeof $this.data('width') != 'undefined') $this.css('width', $this.data('width')+'px');
        else $this.css('width', '');
    },
    calcSize: function() {
        $this = $(this);
        $this.css('position', 'absolute');
        var temp = $this.css('width');
        $this.css('width', '');
        $this.data('width', parseFloat(window.getComputedStyle($this[0]).width));
        $this.data('height', parseFloat(window.getComputedStyle($this[0]).height));
        $this.data('outerwidth', $this.outerWidth(true));
        $this.data('outerheight', $this.outerHeight(true));
        $this.css('width', $this.data('width')+'px');
        $this.css('position', '');
        $this.css('width', temp);
    },
    sameWidth: function() {
        if($("#tooltip-wrapper").find('.main-tooltip').length == 1) {
            $("#tooltip-wrapper").find('.main-tooltip').each(tooltips.setOwnWidth);
        } else {
            var width = 0;
            $("#tooltip-wrapper").find('.main-tooltip').each(function() { width = Math.max(width, $(this).data('width') || 0); });
            $("#tooltip-wrapper").find('.main-tooltip').each(function() { $(this).css('width', width+'px'); });
        }
    },
    wrapperPosition: function(mouseX, mouseY) {
        var tipH = parseInt($("#tooltip-wrapper").css('padding-top')) + parseInt($("#tooltip-wrapper").css('padding-bottom'));
        var tipW = 0;
       
        $("#tooltip-wrapper").find('.main-tooltip').each( function(){ if(typeof $(this).data('outerheight') != 'undefined') tipH += $(this).data('outerheight'); });
        $("#tooltip-wrapper").find('.main-tooltip').each( function(){ if(typeof $(this).data('outerwidth') != 'undefined') tipW = Math.max(tipW, $(this).data('outerwidth') + parseInt($("#tooltip-wrapper").css('padding-left')) + parseInt($("#tooltip-wrapper").css('padding-right'))); });
        
        var spaceTop = mouseY - tooltips.offsetY;
        var spaceLeft = mouseX - tooltips.offsetX;
        var spaceRight = $(window).width() - mouseX - tooltips.offsetX;
        var spaceBottom = $(window).height() - mouseY - tooltips.offsetY;
        
        var coordX = mouseX + tooltips.offsetX;
        var coordY = mouseY + tooltips.offsetY;
        
        if(spaceRight < tipW && spaceBottom < tipH) {
            if(spaceLeft >= tipW && tooltips.flip != 'h') {
                coordX = mouseX - tipW - tooltips.offsetX;
                tooltips.flip = 'v';
            } else if(spaceTop >= tipH) {
                coordY = mouseY - tipH - tooltips.offsetY;
                tooltips.flip = 'h';
            } else {
                coordX = mouseX - tipW - tooltips.offsetX;
                coordY = mouseY - tipH - tooltips.offsetY;
                tooltips.flip = 'vh';
            }
        } else {
            tooltips.flip = false;
        }
        if ($("#tooltip-wrapper").css('position') == 'fixed') {
            coordX = coordX-$(window).scrollLeft();
            coordY = coordY-$(window).scrollTop();
            
            coordX = Math.min(coordX, $(window).width() - tipW);
            coordY = Math.min(coordY, $(window).height() - tipH);
        } else {
            coordX = Math.min(coordX, $(window).width() - tipW);
            coordY = Math.min(coordY, $(window).height() - tipH + $(window).scrollTop());
        }
        $("#tooltip-wrapper").css({left: coordX + 'px', top: coordY + 'px'});
    },
    handlers: {
        mouseOver: function(e) {
            tooltips.lastKnownMousePos = [e.pageX, e.pageY];
            tooltips.wrapperPosition(e.pageX, e.pageY);
            
            var tips = tooltips.getTooltips(this);
            $("#tooltip-wrapper").prepend(tips).show();
            tooltips.sameWidth();
            
            var handle = this;
            tips.each(function() {
                var $this = $(this);
                var type = $(this).data('type') || false;
                
                $this.show();
                $(window).trigger('scroll');// trigger image lazy loader
                if(type && typeof tooltips.types[type] != 'undefined' && tooltips.types[type].delay) {
                    $this.hide();
                    tooltips.timeouts[$(this).attr('id')] = setTimeout(function(){
                        $this.show();
                        if(type && typeof tooltips.types[type].onShow == 'function') tooltips.types[type].onShow.call($this[0], handle);
                    }, tooltips.types[type].delay);
                } else if(type && typeof tooltips.types[type].onShow == 'function') tooltips.types[type].onShow.call(this, handle);
            });
        },
        mouseOut: function(e) {
            tooltips.lastKnownMousePos = [e.pageX, e.pageY];
            tooltips.wrapperPosition(e.pageX, e.pageY);
            
            var handle = this;
            $("#tooltip-wrapper").hide();
            $("#tooltip-wrapper").find('.main-tooltip').appendTo('#tooltip-storage').each(function() {
                var type = $(this).data('type') || false;
                if(type && typeof tooltips.types[type].onHide == 'function') tooltips.types[type].onHide.call(this, handle);
                $(this).show();
                clearTimeout(tooltips.timeouts[$(this).attr('id')]);
                delete tooltips.timeouts[$(this).attr('id')];
            });
        },
        mouseMove: function(e) {
            tooltips.lastKnownMousePos = [e.pageX, e.pageY];
            tooltips.wrapperPosition(e.pageX, e.pageY);
        },
    },
    hash: function(text) {
        /* Source: https://archive.is/nq2F9 */
        var hash = 0, i, char;
        if (text.length === 0) return hash;
        for (i = 0, l = text.length; i < l; i++) {
            char  = text.charCodeAt(i);
            hash  = ((hash<<5)-hash)+char;
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    },
};
$(tooltips.init);

$(document).keydown(function() {
  var nothingIsFocused = document.activeElement === document.body;
  if (nothingIsFocused) {

    if(event.code == 'Slash') {
      $('#searchInput').focus();
      return false;
    }
    
    if(event.code == 'KeyE') {
      window.location.href = $('*[accesskey="e"]').prop('href');
    }
    
    // if(event.code == 'KeyF') {
    //   window.location.href = 'https://test.vana.wiki/Special:Upload';
    // }
    
    if(event.code == 'KeyH') {
      window.location.href = $('*[accesskey="h"]').prop('href');
    }
    
    if(event.code == 'KeyM') {
      window.location.href = $('*[accesskey="m"]').prop('href');
    }

    if(event.code == 'KeyN') {
      $("#new-page-modal-content,#new-page-modal-background").fadeIn(200);
      $('#new-page-create-name-input').focus();
      return false;
    }
    
    if(event.code == 'Escape') {
       $("#new-page-modal-content,#new-page-modal-background").fadeOut(200);
    }

  }
});

$("#new-page-modal-background").click(function () {
  $("#new-page-modal-content,#new-page-modal-background").fadeOut(200);
});

$("#new-page-create-button").click(function () {
  url = new URL($('link[rel="canonical"]').attr('href'));
  window.location.href = 'https://'+url.host+'/w/index.php?title=' + $('#new-page-create-name-input').val() + '&action=edit';
});

////////////////////////////////////////
///////     Move to Top: Button   //////
const button_scrollToTop = document.createElement('button');
button_scrollToTop.className = "mainpage-button-scrollToTop";
button_scrollToTop.innerHTML = '<img src="https://horizonffxi.wiki/w/images/0/06/Up_arrow.png" style="width: 25px; height: 25px;"/>';
//button_scrollToTop.style = "right: 2%; background: #FFFFFF; opacity: 1; position: fixed; display: none; border-radius: 10px; border: 0.5px solid #a7a7a7; box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5);  z-index: 1000;"
document.body.appendChild(button_scrollToTop);

button_scrollToTop.addEventListener("click", function() {
  $("html, body").animate({ scrollTop: 0 }, "slow");
  return false;
});

// //https://stackoverflow.com/questions/31223341/detecting-scroll-direction
// function scrollEventThrottle(fn) {
//   var last_known_scroll_position = 0;
//   var ticking = false;
//   window.addEventListener("scroll", function () {
//     var previous_known_scroll_position = last_known_scroll_position;
//     last_known_scroll_position = window.scrollY;
//     if (!ticking) {
//       window.requestAnimationFrame(function () {
//         fn(last_known_scroll_position, previous_known_scroll_position);
//         ticking = false;
//       });
//       ticking = true;
//     }
//   });
// }

// scrollEventThrottle(function(scrollPos, previousScrollPos) {
//     if (previousScrollPos > scrollPos && scrollPos >= 400) {
// 		if(window.getComputedStyle(button_scrollToTop).display !== "block") {
// 			button_scrollToTop.style.display = "block";
// 			if (document.body.clientWidth >= 850) button_scrollToTop.style.top = "60px";
// 			else button_scrollToTop.style.top = "5px";
// 		}
//     } else {
//       button_scrollToTop.style.display = "none";
//     }
// });

var previousScrollPos = 0;
var lastScrollPos = 0;
var performing = false;

/**
 * show the button #scroll-to-top only
 * on bottom part of the page 
 */
const b = document.querySelector('.mainpage-button-scrollToTop');
//console.log(document.querySelector('.mainpage-button-scrollToTop'));
function toggleVisibility(scrollPos, buttonId) {
	//console.log(previousScrollPos, scrollPos);
  if(previousScrollPos > scrollPos && scrollPos > 500) {
  	//console.log("showing" + $(buttonId));
    	if(window.getComputedStyle(b).display !== "block") {
			button_scrollToTop.style.display = "block";
			if (document.body.clientWidth >= 850) button_scrollToTop.style.top = "60px";
			else button_scrollToTop.style.top = "5px";
		}
  }
  else {
	button_scrollToTop.style.display = "none";
  }
}

document.addEventListener('scroll', function(evt) {
  //console.log(performance.now())
	previousScrollPos = lastScrollPos;
	lastScrollPos = window.scrollY;
  if(!performing) {
    setTimeout(function () {
      toggleVisibility(lastScrollPos, 'mainpage-button-scrollToTop');
      performing = false;
    }, 100);
  }
  performing = true;
}, {passive: true}) ;
////////////////////////////////////////

// function that sorts a table on page load
// based on the column header which has one of the classes sort-col-1, sort-col-2, ...

window.addEventListener('load', function() {
    // Add a small delay to ensure everything is loaded, especially on slower mobile networks
    setTimeout(function() {
        // Select all tables with classes that match "sort-col-1" through "sort-col-6"
        var tables = document.querySelectorAll('.sortable.sort-col-1, .sortable.sort-col-2, .sortable.sort-col-3, .sortable.sort-col-4, .sortable.sort-col-5, .sortable.sort-col-6');

        // Loop through each table and determine the column to sort by based on its class
        Array.prototype.forEach.call(tables, function(table) {
            // Find which "sort-col-X" class is applied to the table
            var classList = Array.prototype.slice.call(table.classList);
            var sortClass = null;

            for (var i = 0; i < classList.length; i++) {
                if (classList[i].indexOf('sort-col-') === 0) {
                    sortClass = classList[i];
                    break;
                }
            }

            if (sortClass) {
                // Extract the column number from the class name (e.g., "sort-col-3" => 3)
                var columnIndex = parseInt(sortClass.replace('sort-col-', ''), 10) - 1;  // Convert to 0-based index
                
                // Find the header cell for the specified column index
                var headerCell = table.querySelectorAll('th')[columnIndex];
                
                // If the header cell exists, simulate a click on it to trigger sorting
                if (headerCell) {
                    headerCell.click()
                }
            }
        });
    }, 500); // 500ms delay to help on slower devices
});