AtlasTools.js
Note: After saving, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
// <nowiki>
/* jshint esversion: 6, bitwise: false */
/* globals stratics, mw, jQuery */
(function ($) {
"use strict";
/* Init */
$('#editlocation').append('<input type="button" value="Click to select a pin to edit" id="pinSelect"/><div id="pinEditDiv">')
.find('.pinEditCancel, .pinEditStore, .pinEditSubmit')
.invis()
.add('#pinSelect')
.button();
var makehtml = stratics.f.util.makehtml,
nbsp = ' ',
br = '<br>';
/* Remove unwanted default title attributes that cause browser tooltips. */
$('a').each(function() {
$(this).removeAttr("title");
});
/* Keep the map visible while scrolling. */
if (!/&curid/.test(location.search)) { // Don't take effect on edit diff pages
var $body = $('#bodyContent'),
$map = $('.map-holder:not(.noscroll)'),
$doc = $(document);
if ($map.length > 0) {
var mapleft = $map[0].getBoundingClientRect().left;
$map.css({
position: 'fixed',
left: mapleft,
top: $body.offset().top - $doc.scrollTop()
});
$(window).scroll(function() {
var ymax = $body.offset().top + $body.height() - $map.height() - $doc.scrollTop();
if (ymax < 0) {
$map.css('top', ymax);
} else if ($('#mw-head').isOnScreen()) {
$map.css('top', $body.offset().top - $doc.scrollTop());
} else {
$map.css('top', $('#navigation').height());
}
});
}
}
/* Flash icons on hover. */
$("span.pin").each(function () {
$(this).find('img').before('<span>');
});
$("#UOLinksList").on("mouseover", "span", function() {
var pair = $(this).attr("data-pair") || '';
pair = '#' + pair.replace(/\:/g,'\\:');
$(pair).addClass('highlight').find('span').addClass('pin-circle');
}).on("mouseout", "span", function() {
var pair = $(this).attr("data-pair") || '';
pair = '#' + pair.replace(/\:/g,'\\:');
$(pair).removeClass('highlight').find('span').removeClass('pin-circle');
});
/* Add jCanvas (http://projects.calebevans.me/jcanvas/docs/) */
$('head').append(makehtml('script', {
src: 'https://cdnjs.cloudflare.com/ajax/libs/jcanvas/16.7.3/jcanvas.min.js'
}));
/* Adds a new canvas layer for each map */
var addCanvas = function(thisClass, z) {
$('.map:not(.mapcanvas)').each(function() {
var $img = $(this).find('img');
$(this).after(makehtml('div', {
class: 'map mapcanvas',
style: $(this).attr('style') + ((z === undefined) ? '' : 'z-index:' + z)
},
makehtml('canvas', {
class: thisClass,
width: $img.attr('width'),
height: $img.attr('height'),
})
));
});
};
/* Create the trigger icon */
$('.map-holder').append(makehtml('aside', {
class: 'pin menutrigger',
style: 'font-size: 25px;color:rgb(224, 171, 67);'
}, '⚙'));
/* Create and add the base tab html */
var loc = location.href.toString().split('#')[0],
tab1 = makehtml('li', {}, makehtml('a', {
href: loc + '#mapoptions'
}, 'Options')),
tab2 = makehtml('li', {}, makehtml('a', {
href: loc + '#mylocation'
}, 'Find your location')),
tab3 = makehtml('li', {}, makehtml('a', {
href: loc + '#showhide'
}, 'Show/hide icons')),
tab4 = makehtml('li', {}, makehtml('a', {
href: loc + '#addlocation'
}, 'Add location')),
tab5 = makehtml('li', {}, makehtml('a', {
href: loc + '#editlocation'
}, 'Edit location'));
$("#toolmenu").prepend(makehtml('ul', {}, tab1 + tab2 + tab3 + tab4 + tab5));
/* Create UI for 'find me' tab */
var xinput = makehtml('input', {
id: 'xcoord',
maxlength: '4',
size: '4',
style: 'margin-top: 13px;padding: 2px 5px;min-height: 0;',
type: 'text'
}),
yinput = makehtml('input', {
id: 'ycoord',
maxlength: '4',
size: '4',
style: 'margin-top: 13px;padding: 2px 5px;min-height: 0;margin-right: 7px;',
type: 'text'
}),
findbutton = makehtml('input', {
id: 'findme',
type: 'button',
value: 'Find me'
}),
removebutton = makehtml('input', {
id: 'findme',
type: 'button',
value: 'Remove me from the map'
});
$('#mylocation').append('x: ' + xinput + 'y: ' + yinput + ' ' + findbutton + ' ' + removebutton);
/* Populate the list of pintypes being used */
var $checkboxes = $(makehtml('div', {
id: 'pinlist'
}));
$('.pin-types').each(function() {
var inputText = $(this).attr('data-name'),
inputType = $(this).attr('data-pin');
$checkboxes.append(makehtml('label', {}, makehtml('input', {
'data-type': inputType,
type: 'checkbox',
checked: 'true'
}, inputText)) + '<br>');
});
$('#showhide').append($checkboxes);
/* Populate the options tab for the gridlines option */
$('#mapoptions').append(makehtml('label', {}, makehtml('input', {
'data-option': 'gridlines',
type: 'checkbox',
}, 'Show gridlines')));
/* Populate the options tab for the radar map option */
$('#mapoptions').append('<br><br>' + makehtml( + 'label', {}, makehtml('input', {
'data-option': 'radarMap',
type: 'checkbox',
}, 'Tilt map like radar view')));
/* Enable the HTML for the add location tab */
var $addloc = $('#addlocation');
$addloc.html($addloc.html().replace(/</g,'<').replace(/>/g,'>'));
/* Add the control buttons for the pin edit tabs */
$('.editPinButtons').append([
'<input type="button" class="pinEditCancel" value="Cancel editing this pin" />',
'<input type="button" class="pinEditStore" value="Store edits to this pin" />',
'<input type="button" class="pinEditSubmit" value="Submit all stored edits" />'
]);
/* Initialize tabs and popup dialog */
$("#toolmenu").tabs({
activate: function (event, ui) {
var active = $('#toolmenu').tabs('option', 'active');
$("#toolmenu").dialog({
height: {
mylocation: 225,
mapoptions: 285,
showhide: 600,
addlocation: 500,
editlocation: 400
}[$("#toolmenu ul>li a").eq(active).attr('href').split('#')[1]]
});
}
}).dialog({
autoOpen: false,
draggable: true,
width: 700,
height: 285
});
$('.pinEditCancel, .pinEditStore, .pinEditSubmit').invis();
/* Add event handler for opening the dialog */
$(".menutrigger").on("click", function() {
$('.mapmarker').remove();
$("#toolmenu").dialog("open").parent().css({
opacity: '.8'
});
$(this).parent().find('div:eq(0)').append(makehtml('span', {
class: 'mapmarker'
}));
});
/* Add event handler for 'find me' button */
$('#findme').click(function() {
var mainAtlas = /^UO\:Atlas\/[A-Za-z]+\//.test(mw.config.values.wgPageName);
$('.mapmarker').after(makehtml('span', {
class: 'yourposition ' + $('.mapmarker').prev().attr('class'),
'data-name': 'Your location',
style: 'left: ' + $("#xcoord").val() + 'px; top: ' + $("#ycoord").val() + 'px;'
},
makehtml('img', {
src: 'http://stratics.com/w/images/b/b4/UO-icon-player.png',
width: (mainAtlas ? 6 : 12),
height: (mainAtlas ? 13 : 26)
})
));
$("#toolmenu").dialog("close");
});
/* Add event handler for 'remove me' button */
$('#removeme').click(function() {
$('.yourposition').remove();
});
/* Add event handler for changes to the pin list checkboxes */
$('#pinlist').on('change', 'input', function() {
var pintype = $(this).attr('data-type');
$('.' + pintype)[this.checked ? 'show' : 'hide']();
});
/* Handle a successful markup submission. */
$('body').on('submitMarkupSuccess', () => {
$('#instructionBox').html('Edits saved. Reloading the page.');
stratics.f.util.reloadPage();
});
/* Handle a failed markup submission. */
$('body').on('submitMarkupFailure', () => {
$('#instructionBox').html('An error occurred.<br>Please try again.');
});
/* Add container for the radar map option */
$('.map').parent().wrap('<div class="mapCollection"><div>');
/* Add event handler for selections on the options tab */
$('#mapoptions').on('change', 'input', function() {
var option = $(this).attr('data-option');
switch (option) {
case 'gridlines':
case 'serverlines':
$('.' + option).toggle();
break;
case 'radarMap':
$('.mapCollection').toggleClass('radarMap');
break;
}
});
/* Create gridline overlays */
addCanvas('gridlines', 1);
$('.gridlines').hide().each(function() {
var x,
y,
width = $(this).width(),
height = $(this).height(),
scale = $(this).parent().parent().getScale(),
insets = $(this).parent().getInsets();
var visibleX = parseInt(insets[3], 10) + 4 + (96 / scale),
visibleY = parseInt(insets[0], 10) + (72 / scale),
linewidth = Math.ceil(5 / scale),
fontsize = Math.ceil(60 / scale) * 1.4;
fontsize = (fontsize > 60) ? 60 : fontsize;
for (y = 0; y < height; y = y + 100) {
$(this).drawLine({
strokeStyle: 'rgb(224, 171, 67)',
strokeWidth: linewidth,
x1: 0,
y1: y,
x2: width,
y2: y
}).drawText({
fillStyle: '#fff',
x: visibleX,
y: y + 5,
fontSize: fontsize,
fontFamily: 'Verdana, sans-serif',
text: y
});
}
for (x = 100; x < width; x = x + 100) {
$(this).drawLine({
strokeStyle: 'rgb(224, 171, 67)',
strokeWidth: linewidth,
x1: x,
y1: 0,
x2: x,
y2: height
});
}
for (x = 100; x < width; x = x + ((scale == 1) ? 200 : 100)) {
$(this).drawText({
fillStyle: '#fff',
x: x,
y: visibleY,
fontSize: fontsize,
fontFamily: 'Verdana, sans-serif',
text: x
});
}
});
/* Add functionality for the Add Location tab */
addCanvas('addlocation', 3);
$('#getlocbtn').click(function() {
$("#toolmenu").dialog("close");
$('.addlocation,.gridlines,.serverlines').css('cursor', 'crosshair').click(function(event) {
var $this = $(this),
rect = this.getBoundingClientRect();
var x = Math.round($this.width() / rect.width * (event.clientX - rect.left)),
y = Math.round($this.height() / rect.height * (event.clientY - rect.top));
var makeWiki = function() {
var str = '-->{{UOAddPin|';
str += $('#getlocselect').val() + '|';
str += x + '|' + y + '|' + $('#getlocdescription').val();
var wiki = $('#getlocwikipage').val();
if (wiki.length > 0) {
str += '|link=' + wiki;
}
str += '}}<!--';
return str;
};
$('.addlocation,.gridlines,.serverlines').css('cursor', 'auto');
$('#getloccoords').text(x + ' x ' + y);
$('#getlocresult').text(makeWiki);
$('#getloctext').show();
$("#toolmenu").dialog("open");
$('#getlocwikipage, #getlocselect, #getlocdescription').on("change keyup", function() {
$('#getlocresult').text(makeWiki);
});
});
});
/* Create a large box for directions in the bottom left corner */
stratics.f.util.$makeDirections = () => {
return $('<div>', {
'class': 'largeFloatingInstructions',
id: 'instructionBox'
}).appendTo('body');
};
/* Destroys the large box for directions in the bottom left corner */
stratics.f.util.removeDirections = () => {
return $('#instructionBox').remove();
};
/* Empties the edit pin tab, resetting it back to initial state */
stratics.f.atlas.ui.resetEditPin = () => {
$('#pinSelect, #pinEditDiv').show();
$('.pinEditCancel, .pinEditStore').invis();
$('#toolmenu').tabs('enable');
return $('#pinEditDiv').empty();
};
/* Event handler for markup AJAX request */
$('body').on('markupArrived', function () {
let wiki = stratics.wiki,
marker = 'ADD LOCATIONS HERE. DO NOT MODIFY ABOVE THIS LINE.';
var markup = stratics.wiki.markup;
$('#toolmenu').dialog('close');
stratics.f.util.$makeDirections().html('Submitting edits, please wait...');
if (markup.length > 0 && wiki.openEdits.length > 0) {
let edits = wiki.openEdits;
for (let edit of edits) {
if (Array.isArray(edit)) { // Pin edit
markup = markup.replace(edit[0], edit[1]);
} else if ('string' === typeof edit) { // Pin addition
markup = markup.replace(marker, marker + '\n' + edit);
}
}
}
stratics.wiki.markup = markup;
stratics.f.wiki.submitMarkup('[Pin Editor]: Edits to ' + wiki.openEdits.length + ' pins.', stratics.wiki.markup); // Asynch
wiki.openEdits = [];
stratics.wiki.markup = '';
});
/* Creates a string of markup with data for a single pin */
stratics.f.wiki.buildPinMarkup = (data) => {
let retval = '-->{{UOAddPin|' + [data.type.replace('_',' '), data.x, data.y, data.name].join('|');
if (data.hasOwnProperty('page') && undefined !== data.page && data.page.length > 0) {
retval += '|link=' + data.page;
}
return retval + '}}<!--';
};
/* Reset a pin to its original location */
stratics.f.wiki.setPinCoordsOrig = ($pin) => {
let [x, y] = $pin.attr('id').split(':'),
offset = {
x: ~~$pin.attr('data-offsetX'),
y: ~~$pin.attr('data-offsetY')
};
$pin.css({
left: (~~x - offset.x) + 'px',
top: (~~y - offset.y) + 'px'
});
};
/* Gets the original markup for a pin */
stratics.f.wiki.getPinMarkupOrig = (data) => {
let info = $('#editlocation').data('selection').attr('id').split(':');
return stratics.f.wiki.buildPinMarkup({
x: info[0],
y: info[1],
type: info[2],
name: $('#editName').data('initial'),
page: $('#editPage').data('initial')
});
};
/* Gets the new markup for a pin on the edit tab */
stratics.f.wiki.getPinMarkupEdit = (data) => {
return stratics.f.wiki.buildPinMarkup({
x: $('#editX').val(),
y: $('#editY').val(),
type: $('#editType').val(),
name: $('#editName').val(),
page: $('#editPage').val()
});
};
/* Gets the new markup for a pin on the add tab */
stratics.f.wiki.getPinMarkupAdd = (data) => {
let info = $('#getloccoords').split(' x ');
return stratics.f.wiki.buildPinMarkup({
x: info[0],
y: info[1],
type: $('#getlocselect').val(),
name: $('#getlocdescription').val(),
page: $('#getlocwikipage').val()
});
};
/* Allows the keyboard to be used to control the arrow buttons on the edit pin tab. */
stratics.f.atlas.movePinByKey = e => {
var key = stratics.keycodes[e.which] || false;
if (!!key && e.which > 32 && e.which < 41) {
e.preventDefault();
e.stopPropagation();
}
$('#arrow' + key).trigger('click');
};
/* Handles a change to a pin's location on the X axis */
stratics.f.atlas.changePinX = function (amount) {
var $pin = stratics.f.atlas.changePinInput($('#editX'), amount);
var left = parseInt($pin.css('left'), 10);
$pin.css('left', ~~left + ~~amount);
return;
};
/* Handles a change to a pin's location on the Y axis */
stratics.f.atlas.changePinY = function (amount) {
var $pin = stratics.f.atlas.changePinInput($('#editY'), amount);
var top = parseInt($pin.css('top'), 10);
$pin.css('top', ~~top + ~~amount);
return;
};
/* Utility function to change the value in an pin location input. */
/* Returns a jQuery-wrapped element which is the pin on the map. */
stratics.f.atlas.changePinInput = function ($pin, amount) {
var val = $pin.val();
$pin.val(~~val + ~~amount);
return $('#editlocation').data('selection');
};
/* Populate the Edit location tab when a location is selected. */
$('#editlocation').on('pinSelected', function (e) {
let $pin = $(e.target).data('selection'),
makehtml = stratics.f.util.makehtml;
let info = $pin.attr('id').split(':'),
arrowBtn = (value, id) => {
return makehtml('input', {
id: 'arrow' + id,
type: 'button',
style: "width:2em;height:2em;opacity:.8;",
value
});
};
$('#pinSelect').attr('value', 'Click to select another pin to edit')
.hide();
$('#pinEditDiv').empty()
.append([
br,
$pin.html(),
nbsp,
$('<input>', {
id: 'editName',
style: 'width:30em;',
type: 'text',
value: $pin.attr('data-name')
}).data('initial', $pin.attr('data-name')),
$('<div>', {id:'arrowControls', style:'float:right;'}).append([
arrowBtn('🡼','NW'),
arrowBtn('🡹','N'),
arrowBtn('🡽','NE'),
br,
arrowBtn('🡸','W'),
$('<span>', {style:'vertical-align: bottom;display:inline-block;width:2em;height:2em;'}),
arrowBtn('🡺','E'),
br,
arrowBtn('🡿','SW'),
arrowBtn('🡻','S'),
arrowBtn('🡾','SE')
]),
br, br,
'Location: ',
'<label>x:' + makehtml('input', {
id: 'editX',
style: 'width:6em;margin-left:5px;margin-right:10px;',
type: 'number',
value: info[0]
}) + '</label>',
$('<label>y:' + makehtml('input', {
id: 'editY',
style: 'width:6em;margin-left:5px;margin-right:10px;',
type: 'number',
value: info[1]
}) + '</label>').data('initial', info[2]),
$('#getlocselect').clone()
.attr('id', 'editType')
.val(info[2].replace(/_/g, ' '))
.data('initial', info[2]),
br, br,
'<label>Wikipage: ' + makehtml('input', {
id: 'editPage',
style: 'width:28em;',
type: 'text',
value: $pin.attr('data-page') || ''
}) + '</label>',
])
.find('img')
.attr('id', 'editImage');
$('#editX').data('initial', info[0]);
$('#editY').data('initial', info[1]);
$('#editPage').data('initial', $pin.attr('data-page'));
/* Start: Move pin click handlers */
let setArrowClick = (dir, x, y) => {
$('#arrow' + dir).click(() => {
if (!!x) stratics.f.atlas.changePinX(x);
if (!!y) stratics.f.atlas.changePinY(y);
});
};
setArrowClick('N', 0, -1);
setArrowClick('W', -1, 0);
setArrowClick('S', 0, 1);
setArrowClick('E', 1, 0);
setArrowClick('NW', -1, -1);
setArrowClick('SW', -1, 1);
setArrowClick('NE', 1, -1);
setArrowClick('SE', 1, 1);
/* End: Move pin click handlers */
/* Handlers for changes directly to the x and y inputs */
$('#editX, #editY').on('change, keyup input mousewheel', () => {
let $pin = $('#editlocation').data('selection');
let offset = {
x: ~~$pin.attr('data-offsetX'),
y: ~~$pin.attr('data-offsetY')
};
$pin.css({
left: (~~$('#editX').val() - offset.x) + 'px',
top: (~~$('#editY').val() - offset.y) + 'px'
});
});
/* Pin-type change handler */
$('#editType').change(() => {
$('#editlocation').data('selection')
.add('#editImage')
.each(() => {
let classes = $(this).attr('class'),
newClass = 'icon-' + $('#editType').val().replace(/\s/g, '_');
$(this).attr('class', classes.replace(/icon\-\S+/, newClass));
});
});
/* Enable keyboard movement of pins */
$('body').on('keydown.pinselect', function (e) {
if (!$(e.target).is('#editName, #editX, #editY, #editType')) {
stratics.f.atlas.movePinByKey(e);
}
});
$('#toolmenu').tabs('disable')
.dialog('open');
});
/* Turns off pin-selection mode */
stratics.f.atlas.ui.disablePinSelectionMode = (e) => {
e.preventDefault();
$('.map-holder').css('cursor','default');
$('body').off('keyup.checkEscape');
$('span.pin').off('click.pinSelect');
stratics.f.util.removeDirections();
$('.menutrigger').show();
};
/* Handler for the "select a pin to edit" button */
$('#pinSelect').click(function () {
/* Turns on pin-selection mode */
$('#toolmenu').dialog('close');
$('.map-holder').css('cursor','pointer');
$('.menutrigger').hide();
stratics.f.util.$makeDirections().html('Click on a pin on the map to select it.<br/>Hit the escape key to cancel.');
$('body').trigger('focus');
/* Handler for ESC being pressed */
$('body').on('keyup.checkEscape', function (e) {
if (e.which === 27) {
stratics.f.atlas.ui.disablePinSelectionMode(e);
stratics.f.atlas.ui.resetEditPin();
$('#toolmenu').dialog('open');
}
});
/* Handler for a click on a pin */
$('span.pin').on('click.pinSelect', function (e) {
stratics.f.atlas.ui.disablePinSelectionMode(e);
$('.pinEditCancel, .pinEditStore', '#editlocation').vis();
$('#editlocation').data('selection', $(this))
.trigger('pinSelected');
});
});
/* Handler for the "cancel editing pin" button */
$('#editlocation').on('click', '.pinEditCancel', () => {
stratics.f.wiki.setPinCoordsOrig($('#editlocation').data('selection'));
stratics.f.atlas.ui.resetEditPin();
});
/* Handler for the "store pin edit" button */
$('#editlocation').on('click', '.pinEditStore', () => {
let wikiF = stratics.f.wiki;
$('body').off('keydown.pinselect');
stratics.wiki.openEdits.push([wikiF.getPinMarkupOrig(), wikiF.getPinMarkupEdit()]);
$('.pinEditSubmit').vis();
stratics.f.atlas.ui.resetEditPin();
});
/* Handler for the "submit edits" button */
$('.pinEditSubmit').click(() => {
stratics.f.wiki.getMarkup(); // Asynch request
$(this).invis();
});
if (/^UO\:Atlas\/(?:Fel|Tram)/.test(mw.config.values.wgPageName)) { /* Only run on Felucca and Trammel maps. */
/* Populate the options tab for the gridlines option */
$('#mapoptions').append('<br><br>' + makehtml('label', {}, makehtml('input', {
'data-option': 'serverlines',
type: 'checkbox',
}, 'Show server lines')));
/* Create server line overlays */
addCanvas('serverlines', 2);
$('.serverlines').hide().each(function() {
var $this = $(this);
var height = $this.height(),
scale = $this.parent().parent().getScale();
var linewidth = Math.ceil(5 / scale);
var makeLine = function(x1, y1, x2, y2) {
$this.drawLine({
strokeStyle: 'red',
strokeWidth: linewidth,
x1: x1,
y1: y1,
x2: x2,
y2: y2
});
};
makeLine(0, 2030, 2678, 2030);
makeLine(2678, 0, 2678, height);
makeLine(0, 1281, 2679, 1281);
makeLine(1536, 1281, 1536, 0);
makeLine(3838, 0, 3838, height);
});
}
})(jQuery);
// </nowiki>