[ Disclaimer, Create new user --- Wiki markup help, Install P99 ]
Difference between revisions of "MediaWiki:LocMaps.js"
From Project 1999 Wiki
Line 1: | Line 1: | ||
− | + | /* Any JavaScript here will be loaded for all users on every page load. */ | |
− | + | ||
− | + | importScript('MediaWiki:Polyfills.js'); | |
− | + | importScript('MediaWiki:Zones.js'); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | /* p1999wiki.js | |
− | + | * written by http://wiki.project1999.com/User:Ravhin | |
− | + | * last update: 7 January, 2018 by Loramin | |
− | + | */ | |
− | + | $(function() { | |
− | + | var hideDelay = 0; | |
+ | var trigDelay = 250; | ||
+ | var hideTimer = null; | ||
+ | var ajax = null; | ||
+ | var currentPosition = { left: '0px', top: '0px' }; | ||
− | + | // One instance that's reused to show info for the current person | |
− | + | var container = $('<div id="itemHoverContainer">' | |
− | + | + '<div id="HoverContent"></div>' | |
− | + | + '</div>'); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | $('body').append(container); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | /* --- hoverbox for item/mob, currently only used in magelo --- */ | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | // Determine which "a" elements should trigger the item stats mouseover | |
− | + | var $mouseoverTargets = $('span.ih a'); | |
− | + | var isItemCategory = document.title.startsWith('Category:') && document.title.includes('Equipment - Project 1999 Wiki') && | |
− | + | !document.title.includes('Worshiper Equipment'); | |
− | + | if (isItemCategory) { | |
− | + | // Include the category's item list along with ".ih" links | |
− | + | $mouseoverTargets = $mouseoverTargets.add('.mw-content-ltr a'); | |
+ | } | ||
− | + | $mouseoverTargets = $mouseoverTargets.filter(function(i, a) { | |
+ | // Don't add hover to links like "next 200" | ||
+ | return !$(a).attr('href').startsWith('/Special:') && | ||
+ | !$(a).attr('href').includes('title=Category:') | ||
+ | }); | ||
− | var | + | $mouseoverTargets.on('mouseover', function() |
− | + | { | |
+ | var $this = $(this); | ||
+ | var itemname = $this.attr('title'); | ||
− | + | if (itemname == '' || itemname == 'undefined') | |
− | if ( | + | return; |
− | if ( | + | if (hideTimer) |
+ | clearTimeout(hideTimer); | ||
− | + | if ($this.parents('div.mw-content-ltr').length) { | |
− | + | var pos = $this.offset(); | |
+ | var width = $this.width(); | ||
− | + | container.css({ | |
− | + | left: pos.left + 5 + 'px', | |
− | + | top: pos.top + 5 + 'px' | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
}); | }); | ||
− | + | } | |
− | } | + | |
− | + | ||
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | $(this).trigger('mousemove'); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | $('#itemHoverContent').html(' '); | |
− | + | ||
− | + | ||
− | + | ||
− | + | //$('#itemHoverContent').html('<div class="itemtopbg"><div class="itemtitle">Loading...</div></div>' | |
− | + | // + '<div class="itembg" style="min-height:50px;"><div class="itemdata">' | |
− | + | // + '<div class="itemicon" style="float:right;"><img alt="" src="/images/Ajax_loader.gif" border="0"></div>' | |
+ | // + '<p></p></div></div><div class="itembotbg"></div>'); | ||
− | + | if (ajax) | |
− | + | { | |
− | + | ajax.abort(); | |
− | + | ajax = null; | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
+ | ajax = $.ajax({ | ||
+ | url: window.location.protocol + | ||
+ | '//wiki.project1999.com/index.php/Special:AjaxHoverHelper/' + itemname, | ||
+ | cacheResponse: true, | ||
+ | success: function(html) | ||
+ | { | ||
+ | var $html = $(html); | ||
+ | $('#itemHoverContent').html($html[2]).prepend($html[0]).prepend($html[1]); | ||
+ | } | ||
+ | }); | ||
− | + | container.css('display', 'block'); | |
− | + | //container.fadeIn('fast'); | |
− | + | ||
− | + | ||
− | + | }); //on mouseover | |
− | + | ||
− | + | ||
− | + | $('span.ih a').on('mouseout', function() | |
− | + | { | |
− | + | if (hideTimer) | |
− | + | clearTimeout(hideTimer); | |
+ | hideTimer = setTimeout(function() | ||
+ | { | ||
+ | container.css('display', 'none'); | ||
+ | //container.fadeOut('fast'); | ||
+ | }, hideDelay); | ||
+ | }); | ||
− | + | $('span.ih a').mousemove(function(e){ | |
− | + | var mousex = e.pageX + 20; //Get X coodrinates | |
− | + | var mousey = e.pageY + 20; //Get Y coordinates | |
+ | var tipWidth = container.width(); //Find width of tooltip | ||
+ | var tipHeight = container.height(); //Find height of tooltip | ||
+ | //Distance of element from the right edge of viewport | ||
+ | var tipVisX = $(window).width() - (mousex + tipWidth); | ||
+ | //Distance of element from the bottom of viewport | ||
+ | var tipVisY = $(window).height() - (mousey + tipHeight); | ||
− | + | if ( tipVisX < 20 ) { //If tooltip exceeds the X coordinate of viewport | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | if( tipWidth > e.pageX - 20 ){ | |
− | + | mousex = 0; | |
− | + | } else { | |
− | + | mousex = e.pageX - tipWidth - 20; | |
− | + | ||
} | } | ||
− | |||
− | |||
− | + | } if ( tipVisY < 20 ) { //If tooltip exceeds the Y coordinate of viewport | |
− | + | mousey = e.pageY - tipHeight - 20; | |
} | } | ||
+ | container.css({ top: mousey, left: mousex }); | ||
+ | }); | ||
− | + | // Allow mouse over of details without hiding details | |
− | + | $('#itemHoverContainer').mouseover(function() | |
− | + | { | |
− | + | if (hideTimer) | |
− | + | clearTimeout(hideTimer); | |
− | + | }); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | } | + | |
− | / | + | // Hide after mouseout |
− | + | $('#itemHoverContainer').mouseout(function() | |
− | + | { | |
− | + | if (hideTimer) | |
− | + | clearTimeout(hideTimer); | |
− | + | hideTimer = setTimeout(function() | |
− | + | { | |
− | } | + | container.css('display', 'none'); |
+ | //container.fadeOut('fast'); | ||
+ | }, hideDelay); | ||
+ | }); | ||
− | + | // magelo non-ajax item hover, but move box with mouse | |
− | + | $('.magelohb').mousemove(function(e){ | |
− | + | var childContainer = $(this).children('span.hb'); | |
− | + | ||
− | + | ||
+ | var tipWidth = childContainer.width(); //Find width of tooltip | ||
+ | var tipHeight = childContainer.height(); //Find height of tooltip | ||
− | + | var mousex = e.pageX + 20; //Get X coodrinates | |
− | + | var mousey = e.pageY + 20; //Get Y coordinates | |
− | var | + | //Distance of element from the right edge of viewport |
− | + | var tipVisX = $(window).width() - (mousex + tipWidth - 20); | |
− | + | //Distance of element from the bottom of viewport | |
+ | var tipVisY = $(window).height() - (mousey + tipHeight - 20); | ||
− | + | if ( tipVisX < 20 ) { //If tooltip exceeds the X coordinate of viewport | |
− | + | ||
− | + | if( tipWidth > e.pageX - 20){ | |
− | + | mousex = 0; | |
− | } | + | } else { |
− | + | mousex = e.pageX - tipWidth - 20; | |
} | } | ||
+ | |||
+ | } if ( tipVisY < 20 ) { //If tooltip exceeds the Y coordinate of viewport | ||
+ | mousey = e.pageY - tipHeight - 20; | ||
} | } | ||
− | + | childContainer.css({ top: mousey, left: mousex, 'z-index':'999' }); | |
− | + | }); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | // change to position:fixed on all hover divs if we have JS active | |
− | + | // otherwise leave as position:absolute so the stationary hovers are near their items | |
− | + | $('.magelohb span.hb').each(function(i) { | |
− | + | $(this).css({'position':'fixed'}); | |
− | + | }); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
+ | // Chrome no longer displays alt text when an image is hovered over. However the wiki only has | ||
+ | // alt attributes for images, not titles. This fixes that by converting alt => title | ||
+ | $('img[alt]').each(function (i, img) { | ||
+ | $(img).attr('title', $(img).attr('alt')); | ||
+ | }); | ||
− | + | // Fashion for item pages | |
− | + | var extractFashionHtml = function(html) { | |
− | + | return $(html).find('.fashion_show, .primary_secondary_show').map(function(i, el) { | |
− | + | var $el = $(el); | |
− | + | var data = $el.data(); | |
− | + | data.race = $el.find('.fashion_race').html(); | |
− | + | if ($el.is('.fashion_show')) { | |
− | + | data.armor = $el.find('.fashion_armor').html(); | |
− | $ | + | |
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | + | return data; | |
+ | }).toArray(); | ||
+ | }; | ||
+ | |||
+ | var getFashionShows = function(fashionCategory) { | ||
+ | var url = 'http://wiki.project1999.com/Category:Fashion: ' + fashionCategory; | ||
+ | return $.get(url).then(extractFashionHtml); | ||
+ | }; | ||
− | + | var getItemPageShows = function() { | |
− | + | var fashionCategories = | |
− | + | $('#catlinks li a') | |
+ | .map(function(i, a) { return $(a).text(); }) | ||
+ | .filter(function(i, text) { return text.startsWith('Fashion:'); }) | ||
+ | .map(function(i, text) { return text.substr('Fashion: '.length); }); | ||
+ | var fashion = fashionCategories[0]; | ||
+ | if (!fashion) return $.when(); | ||
− | + | var tint = fashionCategories[1]; | |
− | + | return getFashionShows(fashion).then(function(shows) { | |
− | + | var sameTint = []; | |
− | + | var otherTint = []; | |
− | + | shows.forEach(function(show) { | |
− | + | // Primary/secondary slots have no tint | |
− | + | if (show.primaryFashion || show.secondaryFashion) sameTint.push(show); | |
− | + | else (show.tint === tint ? sameTint : otherTint).push(show); | |
− | + | ||
− | + | ||
− | + | ||
}); | }); | ||
− | return | + | return { matches: sameTint, otherTint: otherTint, fashion: fashion, tint: tint }; |
− | }; | + | }); |
+ | } | ||
+ | var addFashionSection = function() { | ||
+ | getItemPageShows().then(function(pageShows) { | ||
+ | if(!pageShows || !pageShows.matches) return; | ||
+ | // Build fashion section | ||
+ | var lis = pageShows.matches.map(function(show) { | ||
+ | return '<li class="fashion-link" data-file="' + show.file +'">' + | ||
+ | '<a href="#">' + show.gender + ' ' + show.race + '</a></li>'; | ||
+ | }); | ||
+ | var $ul = $('<ul>').append(lis); | ||
+ | var $div = $('<div><h2>Fashion/Appearance</h2></div>').append($ul); | ||
+ | // Not sure why we have two IDs: two different item templates? | ||
+ | $('#Drop_looted_from, #Drops_From').parent().before($div); | ||
+ | }); | ||
+ | }; | ||
+ | addFashionSection(); | ||
+ | |||
+ | |||
+ | //***************************************** | ||
+ | // Add class-based filtering to item tables | ||
+ | //*****************************************w | ||
+ | |||
+ | // Determine whether or not a provided row should be shown for the provided | ||
+ | // class abbreviation (eg. "BRD") | ||
+ | var isRowShown = function($tr, classAbbrev) { | ||
+ | // Extract classes (and races) | ||
+ | var classText = $tr.find('td').eq(3).text().split('Class:')[1]; | ||
+ | if (!classText) return true; // Ignore (don't filter) rows without class text | ||
+ | |||
+ | // remove "Race: " part (if any) and upper-case text | ||
+ | classText = classText.split('Race:')[0] || classText; | ||
+ | classText = classText.toUpperCase(); | ||
+ | |||
+ | // determine matching text | ||
+ | var isMatch = classText.includes(classAbbrev); | ||
+ | var isAllMatch = classText.includes('ALL'); | ||
+ | var isExcept = classText.includes('ALL EXCEPT'); | ||
+ | |||
+ | // determine matches | ||
+ | if (isMatch && !isExcept) return true; // (eg. BRD in "BRD") | ||
+ | if (!isMatch && isExcept) return true; // (eg. BRD in "ALL EXCEPT WIZ") | ||
+ | if (!isExcept && isAllMatch) return true; // (eg. BRD in "ALL") | ||
+ | return false; | ||
+ | }; | ||
+ | |||
+ | var scrollToTable = function($table) { | ||
+ | window.setTimeout(function() { | ||
+ | $('html, body').animate({ scrollTop: ($table.offset().top) }, 200); | ||
+ | }, 100); | ||
+ | }; | ||
+ | |||
+ | // Filter the provided table to only display rows for the provided class | ||
+ | // abbreviation | ||
+ | var filterTable = function($table, classAbbrev) { | ||
+ | $table.find('tr').each(function (i, tr) { | ||
+ | var $tr = $(tr); | ||
+ | var rowIsShown = isRowShown($tr, classAbbrev); | ||
+ | $tr.toggle(rowIsShown); | ||
+ | }); | ||
+ | scrollToTable($table); | ||
+ | |||
+ | addFilterLink($table, false); | ||
+ | $('.itemsUnfilterLink').click(function() { | ||
+ | unfilterTable($table); | ||
+ | }); | ||
+ | |||
+ | alert('Filtered to only show rows containing ' + classAbbrev + ' gear.'); | ||
+ | }; | ||
+ | |||
+ | // Restore a table to its previous, un-filtered state | ||
+ | var unfilterTable = function($table) { | ||
+ | $table.find('tr').show(); | ||
+ | addFilterLink($table, true); | ||
+ | scrollToTable($table); | ||
+ | }; | ||
+ | |||
+ | // When a user clicks on a table class filter link, handle it by asking them | ||
+ | // which class (and then filtering the table for that class) | ||
+ | var handleItemFilterLinkClick = function(e) { | ||
+ | var promptMessage = 'Please enter the three-letter abbreviation for the ' + | ||
+ | 'class you want to filter by (eg. "brd" for "Bard").'; | ||
+ | |||
+ | var $table = $(e.target).closest('table'); | ||
+ | var classAbbrev = prompt(promptMessage).toUpperCase(); | ||
+ | if (!classAbbrev || classAbbrev.length !== 3 || classAbbrev === 'ALL') { | ||
+ | alert('A 3-digit abbreviation wasn\'t entered (or "All" was entered); ' + | ||
+ | 'filtering disabled'); | ||
+ | unfilterTable($table); | ||
+ | return false; | ||
+ | } | ||
+ | filterTable($table, classAbbrev); | ||
+ | }; | ||
+ | |||
+ | // Adds either a filter or unfilter link (as determined by showFilter) to the | ||
+ | // provided table | ||
+ | var addFilterLink = function($table, showFilter) { | ||
+ | var $statsHeaderCells = $table.find('th:contains("Stats")'); | ||
+ | var filterType = showFilter ? 'Filter' : 'Unfilter'; | ||
+ | $statsHeaderCells.html('Stats <span style="float:right">' + | ||
+ | '<a style="text-decoration: underline" class="items' + filterType + 'Link" href="#">' + | ||
+ | filterType + (showFilter ? ' by Class' : '') + '</a></span>'); | ||
+ | |||
+ | var $link = $statsHeaderCells.find('.items' + filterType + 'Link'); | ||
+ | if (showFilter) $link.click(handleItemFilterLinkClick); | ||
+ | else $link.click(function() { unfilterTable($table); }) | ||
+ | }; | ||
+ | |||
+ | // Add class filtering links to all item tables | ||
+ | var addItemFilteringLinks = function() { | ||
+ | var $tables = $('table th:contains("Item Name")').closest('table'); | ||
+ | $tables.each(function(i, table) { | ||
+ | var $table = $(table); | ||
+ | // Make sure it has both "Item Name" and "Stats" columns | ||
+ | if (!$table.has('th:contains("Stats")')) return; | ||
+ | |||
+ | addFilterLink($table, true); | ||
+ | }); | ||
+ | }; | ||
+ | addItemFilteringLinks(); | ||
+ | |||
+ | //***************************************** | ||
+ | // End class-based filtering to item tables | ||
+ | //***************************************** | ||
− | + | // Add No-Drop-Based filtering to the class equipment pages | |
− | + | if (window.location.pathname.includes('Special:ClassSlotEquip')) { | |
− | + | // Add checkboxes UI to the page | |
− | + | $('table') | |
− | + | .before('<label><input id="showNoDrop" type="checkbox" checked/> Show No Drop</label> ' + | |
− | + | '<label><input id="showDroppable" type="checkbox" checked/> Show Droppable</label>'); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | // Handle when either box is checked | |
− | + | $('#showNoDrop, #showDroppable').change(function() { | |
− | + | var showNoDrop = $('#showNoDrop').is(':checked'); | |
− | + | var showDroppable = $('#showDroppable').is(':checked'); | |
− | + | // NOTE: Some tables are weird and don't keep their TRs in THEAD | |
− | + | // .... but those rows do have an old bgcolor="#cccccc" attribute | |
− | + | // that we can use to identify (and not hide) them | |
− | + | $('tbody tr[bgcolor!=#cccccc]').each(function(i, el) { | |
− | + | var text = $(el).find('td:eq(0) .itemdata').text(); | |
− | + | var isNoDrop = text.includes('NO DROP'); | |
− | + | $(el).toggle((showNoDrop && isNoDrop) || (showDroppable && !isNoDrop)); | |
− | + | }); | |
− | + | }); | |
− | + | } | |
− | + | ||
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | // Generic Table Filtering (for Template:TableFilterCheckbox) | |
− | + | $('.table-filter-checkbox-container').each(function(i, el) { | |
− | + | var $container = $(el); | |
− | + | var matchSelector = $container.data('match'); | |
− | + | var text = $container.text(); | |
− | + | $container.html('<label><input class="table-filter-checkbox" type="checkbox" ' + | |
− | + | 'value="' + matchSelector + '" checked />' + text + '</label>'); | |
− | + | }); | |
− | + | ||
− | + | ||
− | var | + | var shouldRowBeShown = function(tr) { |
− | + | var $tr = $(tr); | |
− | }; | + | // Check all the checkboxes to see if any given row should appear |
+ | // TODO: Instead of checking *every* checkbox, check ones in the same .filter-group | ||
+ | return $('.table-filter-checkbox') | ||
+ | .toArray() | ||
+ | .reduce(function(isShown, checkbox) { | ||
+ | var matchSelector = $(checkbox).val(); | ||
+ | var matches = $tr.is(matchSelector) || | ||
+ | !!$tr.has(matchSelector).length; | ||
+ | var isChecked = $(checkbox).attr('checked'); | ||
+ | return isShown && !!(isChecked || (!isChecked && !matches)); | ||
+ | }, true); | ||
+ | } | ||
+ | $('body').on('change', '.table-filter-checkbox', function(e) { | ||
+ | $('table').show(); | ||
+ | $('table:not(.toc) tbody tr:not([bgcolor="#cccccc"])').each(function(i, tr) { | ||
+ | $(tr).toggle(shouldRowBeShown(tr)); | ||
+ | }); | ||
+ | // If all of a table's non-header rows are hidden, hide it | ||
+ | $('table').filter(function(i, table) { | ||
+ | return !$(table).has('tr:visible:not([bgcolor="#cccccc"])').length; | ||
+ | }).hide(); | ||
+ | }); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | importScript('MediaWiki:CheckboxLists.js'); | |
− | + | importScript('MediaWiki:LocMaps.js'); | |
− | + | var fullTitle = $('title').text(); | |
− | + | var title = fullTitle.substr(0, fullTitle.length - ' - Project 1999 Wiki'.length); | |
− | + | switch(title) { | |
− | + | // Give the Per-Level Hunting Guide Page its own JS | |
− | + | case 'Per-Level Hunting Guide': | |
− | + | importScript('MediaWiki:HuntingGuide.js'); | |
− | + | break; | |
− | + | // The item category search also needs special JS | |
− | + | case 'Item Category Search': | |
− | + | importScript('MediaWiki:ItemCategorySearch.js'); | |
− | // | + | break; |
− | + | // So does the Solo Artist Challenge | |
− | + | case 'Solo Artist Challenge': | |
− | + | importScript('MediaWiki:SoloArtistChallenge.js'); | |
− | + | break; | |
− | + | case 'Treasure Hunting Guide': | |
− | + | importScript('MediaWiki:TreasureHuntingGuide.js'); | |
− | + | break; | |
− | + | case 'Buff Lines': | |
− | + | importScript('MediaWiki:BuffLines.js'); | |
− | + | break; | |
− | + | case 'FashionQuest Finder': | |
− | + | importScript('MediaWiki:FashionQuest.js'); | |
− | + | break; | |
− | var | + | case 'Mobs By Level': |
− | + | // Basic DOM manipulation (since the wiki won't let us add <input> tags in the wiki text | |
− | + | $('#placeholder') | |
+ | .replaceWith( | ||
+ | '<form id="form">' + | ||
+ | 'Class: <input id="class" style="width: 8em" value="Warrior" /> ' + | ||
+ | 'Level: <input id="level" style="width: 4em" /> ' + | ||
+ | '<input type="submit"/>' + | ||
+ | '</form>' | ||
+ | ); | ||
+ | $('#form').submit(function() { | ||
+ | var clazz = $('#class').val(); | ||
+ | var level = $('#level').val(); | ||
+ | window.location = 'https://wiki.project1999.com/index.php?title=Special:Search&limit=500&offset=0&redirs=0&profile=default&search=%22Level%5C%3A%5C+' + | ||
+ | level + '%22+-%22Shopkeeper%22+-%22Merchant%22+%22Class%5C%3A%5C+'+ clazz + '%22+-"startMageloProfile"'; | ||
return false; | return false; | ||
− | |||
− | |||
− | |||
− | |||
}); | }); | ||
+ | break; | ||
+ | } | ||
− | + | // Warn users who accidentally try to edit a templated section | |
− | + | if ((window.location + '').includes('title=Template:Namedmobpage&action=edit')) { | |
− | + | alert('Warning: You are attempting you edit the template for all named mobs. You probably didn\'t mean to do that: you probably clicked on an edit link somewhere in the page and wound up here. To avoid this simply go back and use the edit *tab* at the top of the page instead.'); | |
+ | } | ||
− | + | // Warn uses who try to edit a mostly-transcluded section (and offer to take them to the transcluded page) | |
− | + | var text = $('#wpTextbox1').val(); | |
− | + | var match = text && text.match(/\{\{\#lsth\:(.*?)\|\[\[(.*?)\]\]\}\}/); | |
− | + | if (match) { | |
− | + | var pageName = match[1]; | |
− | + | var section = match[2]; | |
+ | var isEdit = (window.location + '').includes('action=edit'); | ||
+ | var isUnderTenLines = $('#wpTextbox1').val().split('\n').length < 10; | ||
+ | var url = '/' + pageName + '#' + section; | ||
+ | var message = 'This page uses "transclusion" to show part of another page, specifically the code:\n\n {{#lsth:' + pageName + | ||
+ | '|[[' + section + ']]}}\n\nIf you want to edit the transcluded section, click "Ok": you will be taken to that page.' + | ||
+ | ' If you want to stay on this page, click "Cancel".'; | ||
+ | if (isEdit && isUnderTenLines && confirm(message)) location = url; | ||
+ | } | ||
+ | // Add links to search the forum for items to their auction tracker | ||
+ | const forumSearchUrl = 'https://www.project1999.com/forums/search.php?do=process&forumchoice[]=27&query=%22' + | ||
+ | $('#firstHeading').text() + '%22'; | ||
+ | $('.auctrackerbox span span:contains("Project 1999 Auction Tracker")') | ||
+ | .append( | ||
+ | '<a ' + | ||
+ | 'style="font-size: 0.5em; float: right" '+ | ||
+ | 'target="_new" ' + | ||
+ | 'href="' + forumSearchUrl + '"' + | ||
+ | '>Search Forum</a>'); | ||
− | + | }); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Revision as of 16:02, 14 September 2019
/* Any JavaScript here will be loaded for all users on every page load. */ importScript('MediaWiki:Polyfills.js'); importScript('MediaWiki:Zones.js'); /* p1999wiki.js * written by http://wiki.project1999.com/User:Ravhin * last update: 7 January, 2018 by Loramin */ $(function() { var hideDelay = 0; var trigDelay = 250; var hideTimer = null; var ajax = null; var currentPosition = { left: '0px', top: '0px' }; // One instance that's reused to show info for the current person var container = $('<div id="itemHoverContainer">' + '<div id="HoverContent"></div>' + '</div>'); $('body').append(container); /* --- hoverbox for item/mob, currently only used in magelo --- */ // Determine which "a" elements should trigger the item stats mouseover var $mouseoverTargets = $('span.ih a'); var isItemCategory = document.title.startsWith('Category:') && document.title.includes('Equipment - Project 1999 Wiki') && !document.title.includes('Worshiper Equipment'); if (isItemCategory) { // Include the category's item list along with ".ih" links $mouseoverTargets = $mouseoverTargets.add('.mw-content-ltr a'); } $mouseoverTargets = $mouseoverTargets.filter(function(i, a) { // Don't add hover to links like "next 200" return !$(a).attr('href').startsWith('/Special:') && !$(a).attr('href').includes('title=Category:') }); $mouseoverTargets.on('mouseover', function() { var $this = $(this); var itemname = $this.attr('title'); if (itemname == '' || itemname == 'undefined') return; if (hideTimer) clearTimeout(hideTimer); if ($this.parents('div.mw-content-ltr').length) { var pos = $this.offset(); var width = $this.width(); container.css({ left: pos.left + 5 + 'px', top: pos.top + 5 + 'px' }); } $(this).trigger('mousemove'); $('#itemHoverContent').html(' '); //$('#itemHoverContent').html('<div class="itemtopbg"><div class="itemtitle">Loading...</div></div>' // + '<div class="itembg" style="min-height:50px;"><div class="itemdata">' // + '<div class="itemicon" style="float:right;"><img alt="" src="/images/Ajax_loader.gif" border="0"></div>' // + '<p></p></div></div><div class="itembotbg"></div>'); if (ajax) { ajax.abort(); ajax = null; } ajax = $.ajax({ url: window.location.protocol + '//wiki.project1999.com/index.php/Special:AjaxHoverHelper/' + itemname, cacheResponse: true, success: function(html) { var $html = $(html); $('#itemHoverContent').html($html[2]).prepend($html[0]).prepend($html[1]); } }); container.css('display', 'block'); //container.fadeIn('fast'); }); //on mouseover $('span.ih a').on('mouseout', function() { if (hideTimer) clearTimeout(hideTimer); hideTimer = setTimeout(function() { container.css('display', 'none'); //container.fadeOut('fast'); }, hideDelay); }); $('span.ih a').mousemove(function(e){ var mousex = e.pageX + 20; //Get X coodrinates var mousey = e.pageY + 20; //Get Y coordinates var tipWidth = container.width(); //Find width of tooltip var tipHeight = container.height(); //Find height of tooltip //Distance of element from the right edge of viewport var tipVisX = $(window).width() - (mousex + tipWidth); //Distance of element from the bottom of viewport var tipVisY = $(window).height() - (mousey + tipHeight); if ( tipVisX < 20 ) { //If tooltip exceeds the X coordinate of viewport if( tipWidth > e.pageX - 20 ){ mousex = 0; } else { mousex = e.pageX - tipWidth - 20; } } if ( tipVisY < 20 ) { //If tooltip exceeds the Y coordinate of viewport mousey = e.pageY - tipHeight - 20; } container.css({ top: mousey, left: mousex }); }); // Allow mouse over of details without hiding details $('#itemHoverContainer').mouseover(function() { if (hideTimer) clearTimeout(hideTimer); }); // Hide after mouseout $('#itemHoverContainer').mouseout(function() { if (hideTimer) clearTimeout(hideTimer); hideTimer = setTimeout(function() { container.css('display', 'none'); //container.fadeOut('fast'); }, hideDelay); }); // magelo non-ajax item hover, but move box with mouse $('.magelohb').mousemove(function(e){ var childContainer = $(this).children('span.hb'); var tipWidth = childContainer.width(); //Find width of tooltip var tipHeight = childContainer.height(); //Find height of tooltip var mousex = e.pageX + 20; //Get X coodrinates var mousey = e.pageY + 20; //Get Y coordinates //Distance of element from the right edge of viewport var tipVisX = $(window).width() - (mousex + tipWidth - 20); //Distance of element from the bottom of viewport var tipVisY = $(window).height() - (mousey + tipHeight - 20); if ( tipVisX < 20 ) { //If tooltip exceeds the X coordinate of viewport if( tipWidth > e.pageX - 20){ mousex = 0; } else { mousex = e.pageX - tipWidth - 20; } } if ( tipVisY < 20 ) { //If tooltip exceeds the Y coordinate of viewport mousey = e.pageY - tipHeight - 20; } childContainer.css({ top: mousey, left: mousex, 'z-index':'999' }); }); // change to position:fixed on all hover divs if we have JS active // otherwise leave as position:absolute so the stationary hovers are near their items $('.magelohb span.hb').each(function(i) { $(this).css({'position':'fixed'}); }); // Chrome no longer displays alt text when an image is hovered over. However the wiki only has // alt attributes for images, not titles. This fixes that by converting alt => title $('img[alt]').each(function (i, img) { $(img).attr('title', $(img).attr('alt')); }); // Fashion for item pages var extractFashionHtml = function(html) { return $(html).find('.fashion_show, .primary_secondary_show').map(function(i, el) { var $el = $(el); var data = $el.data(); data.race = $el.find('.fashion_race').html(); if ($el.is('.fashion_show')) { data.armor = $el.find('.fashion_armor').html(); } return data; }).toArray(); }; var getFashionShows = function(fashionCategory) { var url = 'http://wiki.project1999.com/Category:Fashion: ' + fashionCategory; return $.get(url).then(extractFashionHtml); }; var getItemPageShows = function() { var fashionCategories = $('#catlinks li a') .map(function(i, a) { return $(a).text(); }) .filter(function(i, text) { return text.startsWith('Fashion:'); }) .map(function(i, text) { return text.substr('Fashion: '.length); }); var fashion = fashionCategories[0]; if (!fashion) return $.when(); var tint = fashionCategories[1]; return getFashionShows(fashion).then(function(shows) { var sameTint = []; var otherTint = []; shows.forEach(function(show) { // Primary/secondary slots have no tint if (show.primaryFashion || show.secondaryFashion) sameTint.push(show); else (show.tint === tint ? sameTint : otherTint).push(show); }); return { matches: sameTint, otherTint: otherTint, fashion: fashion, tint: tint }; }); } var addFashionSection = function() { getItemPageShows().then(function(pageShows) { if(!pageShows || !pageShows.matches) return; // Build fashion section var lis = pageShows.matches.map(function(show) { return '<li class="fashion-link" data-file="' + show.file +'">' + '<a href="#">' + show.gender + ' ' + show.race + '</a></li>'; }); var $ul = $('<ul>').append(lis); var $div = $('<div><h2>Fashion/Appearance</h2></div>').append($ul); // Not sure why we have two IDs: two different item templates? $('#Drop_looted_from, #Drops_From').parent().before($div); }); }; addFashionSection(); //***************************************** // Add class-based filtering to item tables //*****************************************w // Determine whether or not a provided row should be shown for the provided // class abbreviation (eg. "BRD") var isRowShown = function($tr, classAbbrev) { // Extract classes (and races) var classText = $tr.find('td').eq(3).text().split('Class:')[1]; if (!classText) return true; // Ignore (don't filter) rows without class text // remove "Race: " part (if any) and upper-case text classText = classText.split('Race:')[0] || classText; classText = classText.toUpperCase(); // determine matching text var isMatch = classText.includes(classAbbrev); var isAllMatch = classText.includes('ALL'); var isExcept = classText.includes('ALL EXCEPT'); // determine matches if (isMatch && !isExcept) return true; // (eg. BRD in "BRD") if (!isMatch && isExcept) return true; // (eg. BRD in "ALL EXCEPT WIZ") if (!isExcept && isAllMatch) return true; // (eg. BRD in "ALL") return false; }; var scrollToTable = function($table) { window.setTimeout(function() { $('html, body').animate({ scrollTop: ($table.offset().top) }, 200); }, 100); }; // Filter the provided table to only display rows for the provided class // abbreviation var filterTable = function($table, classAbbrev) { $table.find('tr').each(function (i, tr) { var $tr = $(tr); var rowIsShown = isRowShown($tr, classAbbrev); $tr.toggle(rowIsShown); }); scrollToTable($table); addFilterLink($table, false); $('.itemsUnfilterLink').click(function() { unfilterTable($table); }); alert('Filtered to only show rows containing ' + classAbbrev + ' gear.'); }; // Restore a table to its previous, un-filtered state var unfilterTable = function($table) { $table.find('tr').show(); addFilterLink($table, true); scrollToTable($table); }; // When a user clicks on a table class filter link, handle it by asking them // which class (and then filtering the table for that class) var handleItemFilterLinkClick = function(e) { var promptMessage = 'Please enter the three-letter abbreviation for the ' + 'class you want to filter by (eg. "brd" for "Bard").'; var $table = $(e.target).closest('table'); var classAbbrev = prompt(promptMessage).toUpperCase(); if (!classAbbrev || classAbbrev.length !== 3 || classAbbrev === 'ALL') { alert('A 3-digit abbreviation wasn\'t entered (or "All" was entered); ' + 'filtering disabled'); unfilterTable($table); return false; } filterTable($table, classAbbrev); }; // Adds either a filter or unfilter link (as determined by showFilter) to the // provided table var addFilterLink = function($table, showFilter) { var $statsHeaderCells = $table.find('th:contains("Stats")'); var filterType = showFilter ? 'Filter' : 'Unfilter'; $statsHeaderCells.html('Stats <span style="float:right">' + '<a style="text-decoration: underline" class="items' + filterType + 'Link" href="#">' + filterType + (showFilter ? ' by Class' : '') + '</a></span>'); var $link = $statsHeaderCells.find('.items' + filterType + 'Link'); if (showFilter) $link.click(handleItemFilterLinkClick); else $link.click(function() { unfilterTable($table); }) }; // Add class filtering links to all item tables var addItemFilteringLinks = function() { var $tables = $('table th:contains("Item Name")').closest('table'); $tables.each(function(i, table) { var $table = $(table); // Make sure it has both "Item Name" and "Stats" columns if (!$table.has('th:contains("Stats")')) return; addFilterLink($table, true); }); }; addItemFilteringLinks(); //***************************************** // End class-based filtering to item tables //***************************************** // Add No-Drop-Based filtering to the class equipment pages if (window.location.pathname.includes('Special:ClassSlotEquip')) { // Add checkboxes UI to the page $('table') .before('<label><input id="showNoDrop" type="checkbox" checked/> Show No Drop</label> ' + '<label><input id="showDroppable" type="checkbox" checked/> Show Droppable</label>'); // Handle when either box is checked $('#showNoDrop, #showDroppable').change(function() { var showNoDrop = $('#showNoDrop').is(':checked'); var showDroppable = $('#showDroppable').is(':checked'); // NOTE: Some tables are weird and don't keep their TRs in THEAD // .... but those rows do have an old bgcolor="#cccccc" attribute // that we can use to identify (and not hide) them $('tbody tr[bgcolor!=#cccccc]').each(function(i, el) { var text = $(el).find('td:eq(0) .itemdata').text(); var isNoDrop = text.includes('NO DROP'); $(el).toggle((showNoDrop && isNoDrop) || (showDroppable && !isNoDrop)); }); }); } // Generic Table Filtering (for Template:TableFilterCheckbox) $('.table-filter-checkbox-container').each(function(i, el) { var $container = $(el); var matchSelector = $container.data('match'); var text = $container.text(); $container.html('<label><input class="table-filter-checkbox" type="checkbox" ' + 'value="' + matchSelector + '" checked />' + text + '</label>'); }); var shouldRowBeShown = function(tr) { var $tr = $(tr); // Check all the checkboxes to see if any given row should appear // TODO: Instead of checking *every* checkbox, check ones in the same .filter-group return $('.table-filter-checkbox') .toArray() .reduce(function(isShown, checkbox) { var matchSelector = $(checkbox).val(); var matches = $tr.is(matchSelector) || !!$tr.has(matchSelector).length; var isChecked = $(checkbox).attr('checked'); return isShown && !!(isChecked || (!isChecked && !matches)); }, true); } $('body').on('change', '.table-filter-checkbox', function(e) { $('table').show(); $('table:not(.toc) tbody tr:not([bgcolor="#cccccc"])').each(function(i, tr) { $(tr).toggle(shouldRowBeShown(tr)); }); // If all of a table's non-header rows are hidden, hide it $('table').filter(function(i, table) { return !$(table).has('tr:visible:not([bgcolor="#cccccc"])').length; }).hide(); }); importScript('MediaWiki:CheckboxLists.js'); importScript('MediaWiki:LocMaps.js'); var fullTitle = $('title').text(); var title = fullTitle.substr(0, fullTitle.length - ' - Project 1999 Wiki'.length); switch(title) { // Give the Per-Level Hunting Guide Page its own JS case 'Per-Level Hunting Guide': importScript('MediaWiki:HuntingGuide.js'); break; // The item category search also needs special JS case 'Item Category Search': importScript('MediaWiki:ItemCategorySearch.js'); break; // So does the Solo Artist Challenge case 'Solo Artist Challenge': importScript('MediaWiki:SoloArtistChallenge.js'); break; case 'Treasure Hunting Guide': importScript('MediaWiki:TreasureHuntingGuide.js'); break; case 'Buff Lines': importScript('MediaWiki:BuffLines.js'); break; case 'FashionQuest Finder': importScript('MediaWiki:FashionQuest.js'); break; case 'Mobs By Level': // Basic DOM manipulation (since the wiki won't let us add <input> tags in the wiki text $('#placeholder') .replaceWith( '<form id="form">' + 'Class: <input id="class" style="width: 8em" value="Warrior" /> ' + 'Level: <input id="level" style="width: 4em" /> ' + '<input type="submit"/>' + '</form>' ); $('#form').submit(function() { var clazz = $('#class').val(); var level = $('#level').val(); window.location = 'https://wiki.project1999.com/index.php?title=Special:Search&limit=500&offset=0&redirs=0&profile=default&search=%22Level%5C%3A%5C+' + level + '%22+-%22Shopkeeper%22+-%22Merchant%22+%22Class%5C%3A%5C+'+ clazz + '%22+-"startMageloProfile"'; return false; }); break; } // Warn users who accidentally try to edit a templated section if ((window.location + '').includes('title=Template:Namedmobpage&action=edit')) { alert('Warning: You are attempting you edit the template for all named mobs. You probably didn\'t mean to do that: you probably clicked on an edit link somewhere in the page and wound up here. To avoid this simply go back and use the edit *tab* at the top of the page instead.'); } // Warn uses who try to edit a mostly-transcluded section (and offer to take them to the transcluded page) var text = $('#wpTextbox1').val(); var match = text && text.match(/\{\{\#lsth\:(.*?)\|\[\[(.*?)\]\]\}\}/); if (match) { var pageName = match[1]; var section = match[2]; var isEdit = (window.location + '').includes('action=edit'); var isUnderTenLines = $('#wpTextbox1').val().split('\n').length < 10; var url = '/' + pageName + '#' + section; var message = 'This page uses "transclusion" to show part of another page, specifically the code:\n\n {{#lsth:' + pageName + '|[[' + section + ']]}}\n\nIf you want to edit the transcluded section, click "Ok": you will be taken to that page.' + ' If you want to stay on this page, click "Cancel".'; if (isEdit && isUnderTenLines && confirm(message)) location = url; } // Add links to search the forum for items to their auction tracker const forumSearchUrl = 'https://www.project1999.com/forums/search.php?do=process&forumchoice[]=27&query=%22' + $('#firstHeading').text() + '%22'; $('.auctrackerbox span span:contains("Project 1999 Auction Tracker")') .append( '<a ' + 'style="font-size: 0.5em; float: right" '+ 'target="_new" ' + 'href="' + forumSearchUrl + '"' + '>Search Forum</a>'); });