// ==UserScript== // @author DanielOnDiordna // @name Drone route planner // @category Layer // @version 1.1.3.20210724.002500 // @updateURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/DanielOnDiordna/drone-route-planner.meta.js // @downloadURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/DanielOnDiordna/drone-route-planner.user.js // @description [danielondiordna-1.1.3.20210724.002500] Plan a route for your drone (manually), draw your route between portals in range. Mark hacked portals. Use the drone half range layer to see if portals are within range. Import/export data functions available. Integrated Spectrum Colorpicker 1.8.1 // @id drone-route-planner@DanielOnDiordna // @namespace https://softspot.nl/ingress/ // @match https://intel.ingress.com/* // @grant none // ==/UserScript== function wrapper(plugin_info) { // ensure plugin framework is there, even if iitc is not yet loaded if(typeof window.plugin !== 'function') window.plugin = function() {}; // use own namespace for plugin window.plugin.dronerouteplanner = function() {}; var self = window.plugin.dronerouteplanner; self.id = 'dronerouteplanner'; self.title = 'Drone route planner'; self.version = '1.1.3.20210724.002500'; self.author = 'DanielOnDiordna'; self.changelog = ` Changelog: version 0.0.1.20201106.141900 - version 0.0.1 version 0.0.2.20200613.175800 - added a remote control with interactive buttons - move all lines connected to selected portal - delete all lines connected to selected portal version 0.0.3.20200614.153600 - edit settings, colors, ranges - store/restore settings version 0.0.4.20200616.130100 - draggable remote control location (for PC only) version 0.0.5.20200617.204700 - highlighter for showing half drone range circles version 0.0.6.20200618.113800 - remote move buttons for mobile users version 0.0.7.20200618.235400 - home made spinner buttons - highlighter layer with more accurate circle drawing version 1.0.0.20200620.005600 - improved remote control move buttons for pc users - import/export data menu - improved line menu - toggle show/hide remote control version 1.0.1.20200620.192700 - added a highlighter menu with options version 1.0.2.20200620.233500 - added zoom button on the remote control - if no portal is selected, the onoff button now zooms and selects the last portal on the route version 1.0.3.20200621.234800 - added drone hacked button - added highlighter option for drone hacked portals version 1.0.4.20200623.171000 - added store/restore routes menu - added remove all button - fixed highlighter color for hacked portals - show total hacked on highlighter menu - show total lines on Remove all button version 1.0.5.20200628.231500 - bug fixed: if drone route layer was disabled when iitc starts, the remote and menu would not show version 1.1.0.20201228.123200 - half range circles removed from highlighter and placed on a layer version 1.1.1.20210119.234100 - updated plugin wrapper and userscript header formatting to match IITC-CE coding - integrated Spectrum Colorpicker 1.8.1 plugin code, no need anymore for the separate plugin - added show drone range toggle option version 1.1.1.20210421.190200 - minor fix for IITC CE where runHooks iitcLoaded is executed before addHook is defined in this plugin version 1.1.2.20210523.163900 - fixed a bug when restoring a route - changed the drone icon state to non-interactive, so portals behind the icon can be selected - fixed the half range layer display (removed from highlighter) - moved color settings to range and route setup - added alpha color picker for half range layer color - added About window with helpful usage information version 1.1.3.20210525.203200 - improved drawing of half range layer circles during loading of portals version 1.1.3.20210724.002500 - prevent double plugin setup on hook iitcLoaded `; self.namespace = 'window.plugin.' + self.id + '.'; self.pluginname = 'plugin-' + self.id; self.routelayertitle = 'Drone routes'; self.halfrangelayertitle = 'Drone half range'; self.highlighthackedname = 'Drone hacked'; self.localstoragesettings = self.pluginname + '-settings'; self.localstoragelayer = self.pluginname + '-layer'; self.localstoragehacked = self.pluginname + '-hacked'; self.localstorageroutes = self.pluginname + '-routes'; self.isSmartphone = false; self.selectedPortalGuid = undefined; self.requestportalguid = undefined; self.layer = undefined; self.halfrangelayer = undefined; self.hightlighteractive = false; self.settings = {}; self.settings.range1radius = 500.0; self.settings.range2radius = 750.0; self.settings.range1color = 'yellow'; self.settings.range2color = 'red'; self.settings.linecolor = 'purple'; self.settings.linecolorinvalid = 'red'; self.settings.remote_top_offset = 0; self.settings.remote_left_offset = 0; self.settings.halfrangecolor = 'purple'; self.settings.halfrange = 250.0; self.settings.halfrangeopacitypercent = 10; self.settings.highlighterhacked = true; self.settings.showremote = true; self.settings.showdronerange = true; self.hacked = []; self.range1 = undefined; self.range2 = undefined; self.drawicon = 'data:image/png;base64,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'; self.remoteicon = 'data:image/png;base64,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'; // drone-remote-control-3.png self.arrowicons = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAAZCAQAAADeM6mfAAAAK3RFWHRDcmVhdGlvbiBUaW1lAGRvIDE4IGp1biAyMDIwIDA5OjA5OjU1ICswMTAwvwjw7wAAAAd0SU1FB+QGEhAGF/3+GLEAAAAJcEhZcwAAHsEAAB7BAcNpVFMAAAAEZ0FNQQAAsY8L/GEFAAAEx0lEQVR42t2aT4gUVxDGPxlhDwO5jLhCQ0ASiAdBvIiiEBYW8RoQoiBI9GAISEB2RBbRwOS0USKGeBHUixhRUURdQUXI7jIJmrCiqKjRNYlG192gJAqjK2P1tDPTf6rq1etxD0k9hJmxqvu9+r3vm+7pBfgoYAv+W7EbX6E0bUcP0I+t7+A4hbyFZUyge9qWJ0cPPm29/hYbPRbQjylM4vI7xxKi+BV/4jXWOTKLOO+Yb4DrlKXGDPbTAkYxHz9gtVC1CZ+YF3QR24yZPdiBD3Acn719P4RFuI/vsIeaYWncEOY2Xv2NMRzBXsLTWQRYi5WYjTmNNo9hHmpKdhEnsIz6clbJqZDKrmApnvtOpUy7rY4HokZ6aNF10/iHlmSD8Qs1MKzY3/psqPG+hltGpQwnzvyYjrglp1qaqpiKHW9QrSjiXCPrqJpVbeSMulSSjgKuvp3EITHnJyOQUS8YHBA7lP5EA/NhKaEPP6dQREMzrCaOOq4pswzwsNUVLyTl1nQ0jTwx4Hjq1EcShgTEBiXAXWEeFixNFPwR7qHLgKOOF1gh5lUSG9WMpK2PzjWi6yMLQwNigTKszibE0sdg0VG4DCuOQzetaqo3RiTlhFw70Yimj15qzlO2SgPigsKZVnr8FcNiQRGOKawx4pBNK8j0y4QkqY/ONCLpI4TxTKxyAdGgyKaVHleouoBLxuy7gmGVMjhk0xpgO+S8WCln9lhejfD60GFYgchQdNNK780i01BunGHX3407bDZvWiNM5iu6PFeRZPWRXyNZfbhh+ADhoVhMK24VFiS8YUk4eNMKhM3rQLKdXc4fOTSS1ocNhi+QLBS3aaWd242EMywZB29aA2K2gqQLN4Wig94aieujgJM0SUtz8wAJx3N836q64IXDgiRrWBqOcBzLVIwo2SKSiij3+5737Gl9dGErXcnXpgXIJOUtjJ2rzxOHC0nWsFw46rie0lTguCJlkcj60DVSZRfO6c8GxQdIGkYYJTqLHw4dSdqw3DjqZM7J3/oGnBUMkor6dShrpDdzPyHff1igWIFwMKLgTct11S8hSRqWBUc4TiaqRgwVKSS6Pvw0ot+fu6BYgMgwwuhjF9sFV5SYZicNq0g3ARYcSdNyGVZzvMSp9qkqzstFq0bcv1/pUFxAJlQYUWPvuexAiOz+/y3zbVChm8pxZ3PjpuU2rCn8jh+xoa1htz7sGrH8vqtB0YCM07QXGI4dNy07Dg4J/xtWhGVC7VbbtKpKVgZFFG59WDVi0YcORQJihRFG27T8cKSR1GLPLzksA7T9JoVuNU0rEJ4dCSiitlj0YdOIVR8yFA6ID4wwmqbljyOJ5I7hm0fC0jStnZn/qdHWHuZRRGHTRzgeOjTipw8eShqIL4woLuTGEUcyaK7gsESmVU2huIwvtCczM+nfHCqyxhKcYD8/jxtYjDHHI0wpavga36CM9bSweDwh7W4kt/aPQXxMM11lehqfjcdYSpeq7+OAueIBNtMI8CWWYy7ea3z2IW20Wfio8folHtFq9uFwx0/6zdFLIs2nj3aESim33n2eQxnNKOF0/j+5aUQ3bhsMi4sAu0gtz/AvmdYuQuFURTxm2NJMsYdO+3+KQk59RRHQ1hon97npp4o3CavmUI36R3oAAAAASUVORK5CYII='; // arrowmatrix_black_200.png self.drawmarker = undefined; self.drawmarkerguid = undefined; self.drawmarkerpos = undefined; self.selectedline = undefined; self.remote_top_start = undefined; self.remote_left_start = undefined; self.drone_active = false; self.move_active = false; self.move_from_position = undefined; self.portalcircles = {}; self.old_halfrangecolor = undefined; self.old_halfrange = undefined; self.old_halfrangeopacitypercent = undefined; // need to initialise the 'spectrum' color picker self.colorpickeroptions = { flat: false, showInput: true, showButtons: true, showPalette: true, showSelectionPalette: true, allowEmpty: false, hideAfterPaletteSelect: true, palette: [ ['#004000','#008000','#00C000'], ['#00FF00','#80FF80','#C0FFC0'], ['#000040','#000080','#0000C0'], ['#4040FF','#8080FF','#C0C0FF'], ['#6A3400','#964A00','#C05F00'], ['#E27000','#FF8309','#FFC287'], ['#a24ac3','#514ac3','#4aa8c3','#51c34a'], ['#c1c34a','#c38a4a','#c34a4a','#c34a6f'], ['#000000','#666666','#bbbbbb','#ffffff'] ]}; self.restoresettings = function() { if (typeof localStorage[self.localstoragesettings] === 'string' && localStorage[self.localstoragesettings] !== '') { try { var settings = JSON.parse(localStorage[self.localstoragesettings]); if (typeof settings === 'object' && settings instanceof Object && !(settings instanceof Array)) { for (const i in settings) { if (typeof settings[i] === typeof self.settings[i]) self.settings[i] = settings[i]; } } } catch(e) { return false; } } }; self.storesettings = function() { localStorage[self.localstoragesettings] = JSON.stringify(self.settings); }; self.restorearray = function(localstoragename) { var data = []; if (typeof localStorage[localstoragename] === 'string' && localStorage[localstoragename] !== '') { try { data = JSON.parse(localStorage[localstoragename]); if (typeof data !== 'object' || !(data instanceof Object) || !(data instanceof Array)) { return []; } } catch(e) { return []; } } return data; }; self.storearray = function(localstoragename,data) { localStorage[localstoragename] = JSON.stringify(data); }; self.copydata = function() { if (self.linecount() === 0) { alert('No drawn lines'); return; } if (typeof android !== 'undefined' && android && android.shareString) { android.shareString(localStorage[self.localstoragelayer]); return; } var data = JSON.parse(localStorage[self.localstoragelayer]); var html = '

Select all and press CTRL+C to copy it.

' + ''; window.dialog({ html: html, id: self.pluginname + '-dialog-export-data', dialogClass: 'ui-dialog-' + self.pluginname + '-export', title: self.title + ' Copy', width: 600 }); }; self.pastedata = function(appenddata) { if (!appenddata && self.linecount() !== 0 && !confirm('Are you sure you want to replace all lines?')) return; var promptAction = prompt('Press CTRL+V to paste (' + (appenddata?'append':'replace') + ' ' + self.title + ' route data).', ''); if (promptAction === null || promptAction === '') return; try { var data = JSON.parse(promptAction); if (!appenddata) self.layer.clearLayers(); self.import(data); self.storelines(); alert('Import Successful.'); } catch(e) { alert('Import failed'); } }; self.importfile = function() { if (window.requestFile === undefined) return; window.requestFile(function(filename, content) { try { var data = JSON.parse(content); self.import(data); self.storelines(); alert('Import Successful.'); } catch(e) { alert('Import failed'); } }); }; self.savefile = function() { if(typeof android !== 'undefined' && android && android.saveFile) { android.saveFile('IITC-' + self.id + '-route.json', 'text/plain', localStorage[self.localstoragelayer]); } }; self.copydatahacked = function() { if (typeof android !== 'undefined' && android && android.shareString) { android.shareString(localStorage[self.localstoragehacked]); return; } var data = JSON.parse(localStorage[self.localstoragehacked]); var html = '

Select all and press CTRL+C to copy it.

' + ''; window.dialog({ html: html, id: self.pluginname + '-dialog-export-data', dialogClass: 'ui-dialog-' + self.pluginname + '-export', title: self.title + ' Copy', width: 600 }); }; self.pastedatahacked = function(appenddata) { if (!appenddata && !confirm('Are you sure you want to replace all hacked portals?')) return; var promptAction = prompt('Press CTRL+V to paste (' + (appenddata?'append':'replace') + ' ' + self.title + ' hacked data).', ''); if (promptAction === null || promptAction === '') return; try { var data = JSON.parse(promptAction); if (typeof data === 'object' && (data instanceof Array)) { if (!appenddata) self.hacked = []; self.importhacked(data); self.storearray(self.localstoragehacked,self.hacked); alert('Import Successful.'); } else { alert('Import failed, expected an array of guids'); } } catch(e) { alert('Import failed'); } }; self.importhacked = function(data) { self.hacked = data; self.updateHighlighter(); }; self.importfilehacked = function() { if (window.requestFile === undefined) return; window.requestFile(function(filename, content) { try { var data = JSON.parse(content); self.importhacked(data); alert('Import Successful.'); } catch(e) { alert('Import failed'); } }); }; self.savefilehacked = function() { if(typeof android !== 'undefined' && android && android.saveFile) { android.saveFile('IITC-' + self.id + '-hacked.json', 'text/plain', localStorage[self.localstoragehacked]); } }; self.linecount = function(position) { var linecount = 0; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var latLngs = line.getLatLngs(); if (!position || position.lat === latLngs[0].lat && position.lng === latLngs[0].lng || position.lat === latLngs[1].lat && position.lng === latLngs[1].lng) { linecount++; } } }); return linecount; }; self.hightlight_portal = function(portal) { let guid = portal.options.guid; let params = {opacity: 1.0, fillOpacity: 0.5}; if (self.settings.highlighterhacked && self.portal_hacked(guid)) { params.fillColor = 'red'; params.fillOpacity = 1; } else { params.fillColor = window.COLORS[portal.options.team]; params.fillOpacity = 0.5; } if (guid == window.selectedPortal) { params.color = COLOR_SELECTED_PORTAL; params.opacity = 1; console.log('hightlight_portal selectedPortal ',params.fillColor); } portal.setStyle(params); }; self.highlightportals = { highlight: function(data) { if (!data || !(data instanceof Object)) return; if (data.guid && window.portals[data.guid]) data.portal = window.portals[data.guid]; if (!data || !data.portal || !data.portal.options || !data.portal.options.guid) return; if (window._current_highlighter === self.highlighthackedname) { self.hightlight_portal(data.portal); } }, setSelected: function(active) { self.hightlighteractive = active; if (!active) { //hide layer //map.removeLayer(self.halfrangelayer); } else { //show layer //map.addLayer(self.halfrangelayer); if (self.layer._map) self.layer.bringToBack(); //self.halfrangelayer.bringToBack(); } } }; self.updateHighlighter = function() { if (!self.hightlighteractive) return; for (let guid in window.portals) { self.hightlight_portal(window.portals[guid]); } }; self.drawhalfrangecircles = function(guid,latlng) { if (self.portalcircles[guid]) return; var circleOptions = { stroke: true, color: self.settings.halfrangecolor, weight: 1, opacity: Math.max(self.settings.halfrangeopacitypercent / 100 * 2), fill: true, fillColor: null, // to use the same as 'color' for fill fillOpacity: self.settings.halfrangeopacitypercent / 100, clickable: false, interactive: false }; self.portalcircles[guid] = new L.geodesicCircle(latlng, self.settings.halfrange, circleOptions); self.halfrangelayer.addLayer(self.portalcircles[guid]); }; self.onportalAdded = function(data) { // data = {portal: marker, previousData: previousData} let guid = data.portal.options.guid; let latlng = data.portal.getLatLng(); let visiblebounds = map.getBounds(); if (!self.portalcircles[guid] && visiblebounds.contains(latlng)) { self.drawhalfrangecircles(guid,latlng); } }; self.onportalRemoved = function(data) { // data = {portal: p, data: p.options.data } let guid = data.portal.options.guid; if (self.portalcircles[guid]) { self.halfrangelayer.removeLayer(self.portalcircles[guid]); delete(self.portalcircles[guid]); } }; self.updatehalfrangelayer = function() { if (!self.halfrangelayer._map) return; // only if layer is active let visiblebounds = map.getBounds(); // update color, range and opacity for existing circles, but only if changed // and remove circles if not within bounds: let outofbounds = []; for (const guid in self.portalcircles) { if (visiblebounds.contains(self.portalcircles[guid].getLatLng())) { if (self.settings.halfrangecolor !== self.old_halfrangecolor || self.settings.halfrangeopacitypercent !== self.old_halfrangeopacitypercent) self.portalcircles[guid].setStyle({color: self.settings.halfrangecolor,opacity: self.settings.halfrangeopacitypercent / 100 * 2,fillOpacity: self.settings.halfrangeopacitypercent / 100}); if (self.settings.halfrange !== self.old_halfrange) self.portalcircles[guid].setRadius(self.settings.halfrange); } else { outofbounds.push(guid); } } self.old_halfrangecolor = self.settings.halfrangecolor; self.old_halfrange = self.settings.halfrange; self.old_halfrangeopacitypercent = self.settings.halfrangeopacitypercent; // remove circles not within bounds: for (let cnt = 0; cnt < outofbounds.length; cnt++) { let guid = outofbounds[cnt]; self.halfrangelayer.removeLayer(self.portalcircles[guid]); delete(self.portalcircles[guid]); } // draw new circles within bounds: for (const guid in window.portals) { let latlng = window.portals[guid].getLatLng(); if (visiblebounds.contains(latlng)) { self.drawhalfrangecircles(guid,latlng); } } if (self.halfrangelayer._map) self.halfrangelayer.bringToBack(); }; self.move_off = function() { self.move_active = false; document.getElementById("move").style.backgroundColor = "rgba(255,255,255,.5)"; }; self.move_on = function() { if (!window.selectedPortal || self.move_active) return false; var lines = self.getconnectedlines(); if (lines.length === 0) { alert('No connected lines to move'); return; } self.drone_on(); self.move_active = true; self.move_from_position = window.portals[window.selectedPortal].getLatLng(); document.getElementById("move").style.backgroundColor = "rgba(128,0,255,.5)"; }; self.drone_off = function() { self.drone_active = false; document.getElementById("onoff").style.backgroundColor = "rgba(255,0,0,.5)"; self.dronemarker_remove(); self.move_off(); }; self.portal_hacked = function(guid) { return self.hacked.indexOf(guid) >= 0; }; self.toggle_hacked = function() { if (!window.selectedPortal) return; let index = self.hacked.indexOf(window.selectedPortal); if (index >= 0) { self.hacked.splice(index, 1); } else { self.hacked.push(window.selectedPortal); } self.update_hacked(); self.hightlight_portal(window.portals[window.selectedPortal]); self.storearray(self.localstoragehacked,self.hacked); }; self.update_hacked = function() { if (!window.selectedPortal) { document.getElementById("hacked").style.backgroundColor = "rgba(255,255,255,.5)"; } else if (self.portal_hacked(window.selectedPortal)) { document.getElementById("hacked").style.backgroundColor = "rgba(0,255,0,.5)"; } else { document.getElementById("hacked").style.backgroundColor = "rgba(255,0,0,.5)"; } }; self.drone_on = function() { if (self.drone_active) return false; if (!window.selectedPortal) { // select and zoom to last portal let lastlinelatLngs = undefined; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { lastlinelatLngs = line.getLatLngs(); } }); if (lastlinelatLngs == undefined) return false; var visibleBounds = map.getBounds(); var position = lastlinelatLngs[1]; if (!visibleBounds.contains(position)) window.map.setView(position, map.getZoom()); let guid = self.findPortalGuidbyposition(position); if (window.portals[guid]) { window.renderPortalDetails(guid); } else { window.portalDetail.request(guid); } return false; } self.drone_active = true; document.getElementById("onoff").style.backgroundColor = "rgba(0,255,0,.5)"; self.dronemarker_draw(); }; self.toggle_onoff = function() { if (self.drone_active) { self.drone_off(); } else { self.drone_on(); } }; self.toggle_move = function() { if (self.move_active) { self.move_off(); } else { self.move_on(); } }; self.getdroneicon = function() { var zoom = map.getZoom(); var size = Math.max(30,zoom * 4); let icon = L.icon({ iconUrl: self.drawicon, iconSize: [size, size], // size of the icon iconAnchor: [size/2, size/2] // point of the icon which will correspond to marker's location }); return icon; }; self.showremote = function() { if (!self.layeractive(self.routelayertitle)) return; if ($('.DroneRemote').length) self.hideremote(); if (!self.settings.showremote) return; $('#updatestatus').prepend( '
' + '' + '' + '' + '' + '' + '
'); $('.DroneRemote').css('margin-top',(-132 + self.settings.remote_top_offset) + 'px').css('margin-left',(-50 + self.settings.remote_left_offset) + 'px'); // setup buttons self.drone_off(); self.move_off(); self.update_hacked(); }; self.hideremote = function() { $('.DroneRemote').remove(); }; self.move_remote_end = function() { if (!$('.draggable').length) return; if (!self.isSmartphone) $('.DroneRemote').css('cursor','default').css('pointer-events','none').draggable('destroy'); $('.draggable').remove(); var position = $('.DroneRemote').position(); self.settings.remote_top_offset += position.top - self.remote_top_start; self.settings.remote_left_offset += position.left - self.remote_left_start; self.storesettings(); self.remote_top_start = undefined; self.remote_left_start = undefined; }; self.move_remote_cancel = function() { if (!$('.draggable').length) return; if (!self.isSmartphone) $('.DroneRemote').css('cursor','default').css('pointer-events','none').draggable('destroy'); $('.draggable').remove(); self.hideremote(); self.showremote(); self.remote_top_start = undefined; self.remote_left_start = undefined; }; self.remote_move = function(x,y) { var pos = $('.DroneRemote').position(); pos.left += x * 5; pos.top += y * 5; $('.DroneRemote').css({left: pos.left + 'px', top: pos.top + 'px'}); }; self.move_remote_start = function() { if (!$('.DroneRemote').length) return; self.move_remote_end(); var position = $('.DroneRemote').position(); self.remote_top_start = position.top; self.remote_left_start = position.left; if (self.isSmartphone) { $('.DroneRemote').append( '
' + '
' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '
' + ' ' + ' OK
' + '
' + ' Cancel' + '
' + '
'); } else { $('.DroneRemote').append( '
' + ' ' + ' OK
' + '
' + ' Cancel' + '
' + '
'); $('.DroneRemote').css('cursor','move').css('pointer-events','auto').draggable(); } }; self.move_remote_reset = function() { self.move_remote_end(); self.settings.remote_top_offset = 0; self.settings.remote_left_offset = 0; self.storesettings(); self.hideremote(); self.showremote(); }; self.drawmarker_redraw = function() { if (self.drawmarker === undefined) return; self.drawmarker.setIcon(self.getdroneicon()); }; self.dronemarker_remove = function() { if (self.drawmarker === undefined) return; // remove marker map.removeLayer(self.drawmarker); self.drawmarker = undefined; }; self.dronemarker_draw = function() { self.dronemarker_remove(); // redraw if (!window.selectedPortal) { self.drone_off(); return; } var guid = window.selectedPortal; if (!window.portals[guid]) return; var portal = window.portals[guid]; self.drawmarkerpos = portal.getLatLng(); self.drawmarkerguid = guid; self.drawmarker = L.marker([self.drawmarkerpos.lat, self.drawmarkerpos.lng], {icon: self.getdroneicon(), interactive: false}).addTo(map); }; self.lineexists = function(latLngs) { var lineexists = false; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var existinglatLngs = line.getLatLngs(); if ((existinglatLngs[0].lat === latLngs[0].lat && existinglatLngs[0].lng === latLngs[0].lng && existinglatLngs[1].lat === latLngs[1].lat && existinglatLngs[1].lng === latLngs[1].lng) || (existinglatLngs[0].lat === latLngs[1].lat && existinglatLngs[0].lng === latLngs[1].lng && existinglatLngs[1].lat === latLngs[0].lat && existinglatLngs[1].lng === latLngs[0].lng)){ lineexists = true; } } }); return lineexists; }; self.removeline = function(line) { self.layer.removeLayer(line); self.storelines(); }; self.removeAll = function(noconfirm) { if (self.linecount() === 0) { if (!noconfirm) alert('No drawn lines to remove'); return; } if (!noconfirm && !confirm('Remove route? ' + self.linecount() + ' lines')) return; delete localStorage[self.localstoragelayer]; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { self.layer.removeLayer(line); } }); self.storelines(); }; self.drawline = function(latLngs) { if (latLngs[0].lat === latLngs[1].lat && latLngs[0].lng === latLngs[1].lng) return; // no 0 length lines if (self.lineexists(latLngs)) return; // no double lines var length = L.latLng(latLngs[0].lat,latLngs[0].lng).distanceTo([latLngs[1].lat,latLngs[1].lng]); var color = (length <= self.settings.range2radius ? self.settings.linecolor : self.settings.linecolorinvalid); var lineOptions = { stroke: true, color: color, weight: 4, opacity: 0.8, fill: false, clickable: true }; var line = L.geodesicPolyline(latLngs, L.extend({}, lineOptions, {color: color, dashArray: null})); line.on('click',function(e) { self.linemenu(line); }); self.layer.addLayer(line); return length; }; self.addline = function() { if (!self.drawmarker || !window.selectedPortal || !window.portals[window.selectedPortal]) return; var startpos = self.drawmarkerpos; var endpos = window.portals[window.selectedPortal].getLatLng(); var latLngs = [new L.LatLng(startpos.lat,startpos.lng),new L.LatLng(endpos.lat,endpos.lng)]; var length = self.drawline(latLngs); self.storelines(); }; self.moveconnectedlines = function() { if (!self.drawmarker || !window.selectedPortal || !window.portals[window.selectedPortal]) return; var guid = window.selectedPortal; var portal = window.portals[guid]; var newll = portal.getLatLng(); var movefromposition = self.move_from_position; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var moved = false; var latLngs = self.clonelatlngs(line.getLatLngs()); if (latLngs[0].lat === movefromposition.lat && latLngs[0].lng === movefromposition.lng) { latLngs[0] = new L.LatLng(newll.lat,newll.lng); moved = true; } else if (latLngs[1].lat === movefromposition.lat && latLngs[1].lng === movefromposition.lng) { latLngs[1] = new L.LatLng(newll.lat,newll.lng); moved = true; } if (moved) { if ((latLngs[0].lat === latLngs[1].lat && latLngs[0].lng === latLngs[1].lng) || self.lineexists(latLngs)) { // remove line if start and end match or if line already exists self.layer.removeLayer(line); } else { line.setLatLngs(latLngs); var length = L.latLng(latLngs[0].lat,latLngs[0].lng).distanceTo([latLngs[1].lat,latLngs[1].lng]); var color = (length <= self.settings.range2radius ? self.settings.linecolor : self.settings.linecolorinvalid); line.setStyle({color:color}); } } } }); self.storelines(); }; self.updateLineColors = function() { self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var latLngs = line.getLatLngs() var length = L.latLng(latLngs[0].lat,latLngs[0].lng).distanceTo([latLngs[1].lat,latLngs[1].lng]); var color = (length <= self.settings.range2radius ? self.settings.linecolor : self.settings.linecolorinvalid); line.setStyle({color:color}); } }); self.storelines(); }; self.totalrange = function() { var maxrange = 0; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var range = 0; if (range > maxrange) maxrange = range; } }); return maxrange < 100000 ? Math.round(maxrange) + 'm' : Math.round(maxrange/1000) + 'km'; }; self.storelines = function() { var data = []; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var item = {}; item.type = 'polyline'; item.latLngs = line.getLatLngs(); data.push(item); } }); localStorage[self.localstoragelayer] = JSON.stringify(data); }; self.import = function(data) { $.each(data, function(index,item) { switch(item.type) { case 'polyline': self.drawline(item.latLngs); break; default: console.warn(self.id + ': unknown import layer type "'+item.type); break; } }); }; self.restorelines = function() { try { var dataStr = localStorage[self.localstoragelayer]; if (dataStr === undefined) return; var data = JSON.parse(dataStr); self.import(data); } catch(e) { console.warn(self.id + ': failed to load data from localStorage: '+e); } }; self.updatedronerange = function() { // remove range if (self.range1) self.layer.removeLayer(self.range1); if (self.range2) self.layer.removeLayer(self.range2); self.range1 = undefined; self.range2 = undefined; if (!window.selectedPortal || !self.settings.showdronerange) return; // draw range var latLng = window.portals[self.selectedPortalGuid].getLatLng(); var circleOptions = { stroke: true, color: self.settings.range1color, weight: 2, opacity: 1.0, fill: true, fillColor: null, // to use the same as 'color' for fill fillOpacity: 0.2, clickable: false, interactive: false }; var extraOpt = {}; extraOpt.portalguid = self.selectedPortalGuid; extraOpt.title = window.portals[self.selectedPortalGuid].options.data.title; self.range1 = L.geodesicCircle(latLng, self.settings.range1radius, L.extend({},circleOptions,extraOpt)); circleOptions.color = self.settings.range2color; circleOptions.weight = 1; circleOptions.fillOpacity = 0.1; self.range2 = L.geodesicCircle(latLng, self.settings.range2radius, L.extend({},circleOptions,extraOpt)); self.layer.addLayer(self.range2).bringToBack(); self.layer.addLayer(self.range1).bringToBack(); self.layer.bringToBack(); //self.hightlighterlayer.bringToBack(); self.updatehalfrangelayer(); if (self.drawmarker !== undefined) { // there is a start marker if (self.drawmarkerguid !== self.selectedPortalGuid) { // another portal then the start portal is selected if (self.move_active) { self.moveconnectedlines(); self.move_from_position = latLng; } else { self.addline(); } self.dronemarker_draw(); } } }; self.onPortalSelected = function() { if (!self.layer._map) return; if (self.selectedPortalGuid === window.selectedPortal) return; if (self.selectedPortalGuid) { // remove range if (self.range1) self.layer.removeLayer(self.range1); if (self.range2) self.layer.removeLayer(self.range2); self.range1 = undefined; self.range2 = undefined; } self.selectedPortalGuid = window.selectedPortal; self.update_hacked(); if (!self.selectedPortalGuid) { self.drone_off(); return; } // draw range if (!window.portals[self.selectedPortalGuid]) return; self.updatedronerange(); }; self.clonelatlngs = function(latlngs) { var newlatlngs = []; for (var cnt = 0; cnt < latlngs.length; cnt++) { newlatlngs.push(new L.LatLng(latlngs[cnt].lat,latlngs[cnt].lng)); } return newlatlngs; }; self.removeselectedline = function() { if (!self.selectedline) return; self.removeline(self.selectedline); self.selectedline = undefined; self.closemenu(); }; self.linelength = function(line) { if (!line) return ''; var latlngs = line.getLatLngs(); var length = L.latLng(latlngs[0].lat,latlngs[0].lng).distanceTo([latlngs[1].lat,latlngs[1].lng]); return length < 100000 ? Math.round(length) + 'm' : Math.round(length/1000) + 'km'; }; self.layeractive = function(layername) { var layers = window.layerChooser.getLayers().overlayLayers; for (var id in layers) { if (layers[id].name === layername) { if (layers[id].active) { return true; } } } return false; }; self.closemenu = function() { $(".ui-dialog-content").dialog("close"); }; self.getconnectedlines = function() { var lines = []; if (!window.selectedPortal) lines; var position = window.portals[window.selectedPortal].getLatLng(); self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var latLngs = line.getLatLngs(); if (position.lat === latLngs[0].lat && position.lng === latLngs[0].lng || position.lat === latLngs[1].lat && position.lng === latLngs[1].lng) { lines.push(line); } } }); return lines; }; self.deleteconnectedlines = function() { if (!window.selectedPortal) return; var lines = self.getconnectedlines(); if (lines.length === 0) { alert('No connected lines to remove'); return; } if (!confirm('Lines connected to selected portal: '+ lines.length + '\n\nDelete?')) return; for (var i in lines) { self.layer.removeLayer(lines[i]); } self.storelines(); }; self.portaltitle = function(guid) { if (Object.keys(window.portals).length === 0) return '(no portals loaded)'; // cancel while no portals loaded yet; prevents an error inside the IITC core if (!guid) return '(no guid loaded)'; if (!window.portals[guid]) return '(portal not found)'; if (!window.portals[guid].options.data.title) return '(title not found)'; return window.portals[guid].options.data.title; }; self.selectportalbyguid = function(guid) { if (Object.keys(window.portals).length === 0) return; // cancel while no portals loaded yet; prevents an error inside the IITC core if (!guid) return false; if (guid === window.selectedPortal) { var visibleBounds = map.getBounds(); var position = window.portals[guid].getLatLngs(); if (!visibleBounds.contains(position)) window.map.setView(position, map.getZoom()); return true; } if (window.portals[guid]) { window.renderPortalDetails(guid); } else { window.portalDetail.request(guid); return false; } return true; }; self.findPortalGuidbyposition = function(position) { for (var guid in window.portals) { var portalposition = window.portals[guid].getLatLng(); if (portalposition.lat === position.lat && portalposition.lng == position.lng) { return guid; } } return undefined; }; self.linemenu = function(line) { if (!line) return; if (self.drawmarker) return; // disable menu when drawing a new line self.selectedline = line; let latLngs = line.getLatLngs(); let guid_start = self.findPortalGuidbyposition(latLngs[0]); let guid_end = self.findPortalGuidbyposition(latLngs[1]); var html = '
' + '' + self.portaltitle(guid_start) + '
' + '' + self.portaltitle(guid_end) + '
' + 'Delete this line' + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, title: self.title + ' (' + self.linelength(line) + ')' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Close': function() { $(this).dialog('close'); }, }); }; self.showAll = function() { if (Object.keys(self.layer._layers).length === 0) { alert('No drawn lines to display'); return; } map.fitBounds(self.layer.getBounds()); }; self.spin_down = function(settings) { let oldvalue = $(settings.object).val(); let spinnervalue = parseFloat($(settings.object).val()); spinnervalue -= settings.step; if (isNaN(spinnervalue) || spinnervalue < settings.min) spinnervalue = settings.min; spinnervalue = parseFloat(parseFloat(spinnervalue).toFixed(settings.decimals)); $(settings.object).val(spinnervalue.toFixed(settings.decimals) + settings.appendstring); if (oldvalue != spinnervalue) settings.changed(spinnervalue); }; self.spin_up = function(settings) { let oldvalue = $(settings.object).val(); let spinnervalue = parseFloat($(settings.object).val()); spinnervalue += settings.step; if (isNaN(spinnervalue) || spinnervalue > settings.max) spinnervalue = settings.max; spinnervalue = parseFloat(parseFloat(spinnervalue).toFixed(settings.decimals)); $(settings.object).val(spinnervalue.toFixed(settings.decimals) + settings.appendstring); if (oldvalue != spinnervalue) settings.changed(spinnervalue); }; self.spinner = function(settings) { if (!$(settings.object).length) return; if (typeof settings.decimals == 'undefined') settings.decimals = 0; if (typeof settings.appendstring == 'undefined') settings.appendstring = '' let spinnervalue = parseFloat($(settings.object).val()); if (isNaN(spinnervalue) || spinnervalue < settings.min) spinnervalue = settings.min; if (spinnervalue > settings.max) spinnervalue = settings.max; spinnervalue = parseFloat(parseFloat(spinnervalue).toFixed(settings.decimals)); $(settings.object).val(spinnervalue.toFixed(settings.decimals) + settings.appendstring); $(settings.object).after('â–¼'); $(settings.object).next().bind("click",function() { self.spin_down(settings); }).css('cursor','hand').css('user-select','none'); $(settings.object).after('â–²'); $(settings.object).next().bind("click",function() { self.spin_up(settings); }).css('cursor','hand').css('user-select','none'); $(settings.object).bind('keydown',function( event ) { if ( event.which == 13 ) { event.preventDefault(); } else if ( event.which == 38 ) { // up self.spin_up(settings); } else if ( event.which == 40 ) { // down self.spin_down(settings); } else { event.preventDefault(); } }); }; self.restoreselectedroute = function(replacelinks) { var selectedroute = $('#' + self.pluginname + '_selectroute option:selected').val(); if (!selectedroute) { alert('Nothing to restore'); return; } var linecount = self.linecount(); if (linecount !== 0) { if (replacelinks) { if (!confirm('Are you sure you want to replace all drawn lines\nwith stored route \'' + selectedroute + '\'?')) return; } else { if (!confirm('Are you sure you want to add stored lines\nfrom route \'' + selectedroute + '\' to current drawn lines?')) return; } } var storeddata = self.getstoreroutes(); if (!storeddata[selectedroute]) return; if (replacelinks && linecount !== 0) self.removeAll(true); self.import(storeddata[selectedroute]); self.storelines(); }; self.getstoreroutes = function() { var data = {}; if (typeof localStorage[self.localstorageroutes] === 'string' && localStorage[self.localstorageroutes] !== '') { try { data = JSON.parse(localStorage[self.localstorageroutes]); if (typeof data !== 'object' || !(data instanceof Object) || (data instanceof Array)) { return {}; } } catch(e) { return {}; } } return data; }; self.storeroute = function(selectedroute) { if (self.linecount() === 0) { alert('There are no drawn lines to store as a route'); return; // nothing to store } var storeddata = self.getstoreroutes(); var newname; if (selectedroute && storeddata[selectedroute]) { if (!confirm('Are you sure you want to replace stored route \'' + selectedroute + '\'?')) return; delete(storeddata[selectedroute]); newname = selectedroute; } else { var newnamecnt = Object.keys(storeddata).length + 1; newname = 'route ' + newnamecnt; while (storeddata[newname]) { newnamecnt++; newname = 'route ' + newnamecnt; } } var routedata = []; self.layer.eachLayer( function(line) { if (line instanceof L.GeodesicPolyline && line.getLatLngs().length === 2) { var item = {}; item.type = 'polyline'; item.latLngs = line.getLatLngs(); routedata.push(item); } }); storeddata[newname] = routedata; localStorage[self.localstorageroutes] = JSON.stringify(storeddata); self.updaterouteselectlist(newname); }; self.deletestoredroute = function() { var selectedroute = $('#' + self.pluginname + '_selectroute option:selected').val(); if (!selectedroute) { alert('Nothing stored to delete'); return; } if (!confirm('Are you sure you want to delete stored route \'' + selectedroute + '\'?')) return; var storeddata = self.getstoreroutes(); delete(storeddata[selectedroute]); localStorage[self.localstorageroutes] = JSON.stringify(storeddata); self.updaterouteselectlist(); }; self.renamestoredroute = function() { var selectedroute = $('#' + self.pluginname + '_selectroute option:selected').val(); if (!selectedroute) { alert('Nothing to rename'); return; } var newname = prompt('Enter a new unique name for this route:',selectedroute); if (newname === null || newname === selectedroute) return; if (newname === '') { alert('Route name cannot be empty!'); return; } if (newname.match(/['"]/) !== null) { alert('Quote characters are not allowed in the route name'); return; } var storeddata = self.getstoreroutes(); if (storeddata[newname]) { alert('Route name must be unique! \'' + newname + '\' already in use'); return; } storeddata[newname] = storeddata[selectedroute]; delete(storeddata[selectedroute]); localStorage[self.localstorageroutes] = JSON.stringify(storeddata); self.updaterouteselectlist(newname); }; self.updaterouteselectlist = function(selectedroute) { var newlist = self.createrouteselectlist(selectedroute); if (newlist !== $('#' + self.pluginname + '_selectroute').html()) $('#' + self.pluginname + '_selectroute').replaceWith(newlist); }; self.createrouteselectlist = function(selectedroute) { var storedroutes = self.getstoreroutes(); var routenames = Object.keys(storedroutes).sort(function(a,b) { return (a.toLowerCase() < b.toLowerCase()?-1:(a.toLowerCase() > b.toLowerCase()?1:0)); }); if (routenames.length === 0) return 'nothing stored'; var list = []; if (!selectedroute) selectedroute = $('#' + self.pluginname + '_selectroute option:selected').val(); if (!selectedroute) selectedroute = routenames[0]; for (var index in routenames) { var routename = routenames[index]; list.push(''); } return ''; }; self.storemenu = function() { var html = '
' + 'Store as new route' + 'Overwrite selected route' + self.createrouteselectlist() + 'Rename selected route' + 'Restore route (add)' + 'Restore route (replace)' + 'Delete selected route' + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, title: self.title + ' Store/Restore' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Close': function() { $(this).dialog('close'); }, }); }; self.backupmenu = function() { var html = '
' + 'Export data (copy)' + 'Import data (paste)' + 'Append data (paste)' + (window.requestFile !== undefined ? 'Import file' : '') + ((typeof android !== 'undefined' && android && android.saveFile) ? 'Export file' : '') + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, title: self.title + ' Route Import/Export' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Close': function() { $(this).dialog('close'); }, }); }; self.backuphackedmenu = function() { var html = '
' + 'Export hack data (copy)' + 'Import hack data (paste)' + 'Append hack data (paste)' + (window.requestFile !== undefined ? 'Import from file' : '') + ((typeof android !== 'undefined' && android && android.saveFile) ? 'Export to file' : '') + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, title: self.title + ' Hacked Import/Export' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Close': function() { $(this).dialog('close'); }, }); }; self.rangemenu = function() { var html = '
' + '
' + ' ' + 'Regular range:
' + ' ' + 'Maximum range:
' + 'Color for route lines:
' + ' within maximum range
' + ' out of maximum range
' + 'Half range layer:
' + ' Drone half range:
' + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, title: self.title + ' - Range and route setup' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Close': function() { $(this).dialog('close'); }, }); self.spinner( { object: '#range1spinner', step: 10, min: 150, max: 1000, appendstring: 'm', changed: function(value) { self.settings.range1radius = value; self.storesettings(); if (self.range1) { self.range1.setRadius(self.settings.range1radius); } self.updateLineColors(); } } ); self.spinner( { object: '#range2spinner', step: 10, min: 160, max: 1200, appendstring: 'm', changed: function(value) { self.settings.range2radius = value; self.storesettings(); if (self.range2) { self.range2.setRadius(self.settings.range2radius); } self.updateLineColors(); } } ); self.spinner( { object: '#halfrangespinner', step: 10, min: 150, max: 1200, appendstring: 'm', changed: function(value) { self.settings.halfrange = value; self.storesettings(); self.updatehalfrangelayer(); } } ); $('#drone_linecolor').spectrum($.extend(true, self.colorpickeroptions, { change: function(color) { self.settings.linecolor = color.toHexString(); self.storesettings(); self.updateLineColors(); }, color: self.settings.linecolor, })); $('#drone_linecolorinvalid').spectrum($.extend(true, self.colorpickeroptions, { change: function(color) { self.settings.linecolorinvalid = color.toHexString(); self.storesettings(); self.updateLineColors(); }, color: self.settings.linecolorinvalid, })); $('#drone_range1color').spectrum($.extend(true, self.colorpickeroptions, { change: function(color) { self.settings.range1color = color.toHexString(); self.storesettings(); if (self.range1) { self.range1.setStyle({color:self.settings.range1color}); }}, color: self.settings.range1color, })); $('#drone_range2color').spectrum($.extend(true, self.colorpickeroptions, { change: function(color) { self.settings.range2color = color.toHexString(); self.storesettings(); if (self.range1) { self.range2.setStyle({color:self.settings.range2color}); }}, color: self.settings.range2color, })); $('#drone_halfrangecolor').spectrum($.extend(true, self.colorpickeroptions, { showAlpha: true, change: function(color) { self.settings.halfrangecolor = color.toHexString(); self.settings.halfrangeopacitypercent = color.getAlpha() * 100; self.storesettings(); self.updatehalfrangelayer(); }, color: tinycolor(self.settings.halfrangecolor).setAlpha(self.settings.halfrangeopacitypercent / 100), })); }; self.about = function() { let container = document.createElement('div'); let aboutarea = container.appendChild(document.createElement('div')); aboutarea.innerHTML = `How to properly use the Drone route planner This plugin has many features, with 1 basic purpose: - Mark portals as hacked with your Drone, to keep track of your "Unique Portals Drone" state. Enable the Drone routes layer, to display a remote control for your Drone (by default at the bottom of the screen). If a portal is selected, the plugin will draw two range circles around that portal: - Regular range for your Drone, which is always possible. - Maximum range for your Drone, which is possible in certain conditions. You can edit the range distance and colors from the Drone menu. You can also disable it to show no ranges on the map. With the remote control, you can mark a selected portal as Hacked with button "H". The button H is red if portal is not yet hacked, and green if it is hacked. Remember to enable the highlighter "Drone hacked" to show the portals you have marked as hacked. With the remote control, you can draw a drone route: 1. select a portal 2. switch on the remote control (button turns green) and a Drone icon shows on the selected portal 3. select another portal, within the regular or maximum range for your drone 4. the Drone icon shows on the other portal, and a route link is drawn between the portals 5. you can continue selecting portals to plan a route for your drone 6. when you are finished, switch off the remote control If you made a mistake, and want to draw your route to another portal, you can enable the move button on the remote control (button turns purple). If move is enabled, all the route lins connected to the Drone icon portal is moved to another portal you selected. The trashcan button can be used to delete all routes connected to the selected portal. Use the looking glass button to zoom the map to see the complete route in view. The remote control has a menu button ☰ This will show the menu, same as from the normal menu in the portal details dialog. From the menu there are a lot of extra functions: - range and route setup to change colors and distances - edit the half range layer color and distance (if two half range circles touch, your drone can reach that portal) - enable the move function for the remote control (or reset it's position) - Zoom to view total route, same as the looking glass button on the remote - import/export your list of hacked portals - import/export your routes - store/restore the routes, so you can draw a new route, or combine stored routes - remove the current route completely `.replace(/\n/g,'
\n'); let author = container.appendChild(document.createElement('div')); author.style.fontStyle = 'italic'; author.style.fontSize = 'smaller'; author.textContent = self.title + ' version ' + self.version + ' by ' + self.author; window.dialog({ html: container, id: self.id, width: 'auto', title: self.title + ' - About' }).dialog('option', 'buttons', { '< Main menu': function() { self.menu(); }, 'Changelog': function() { alert(self.changelog); }, 'Close': function() { $(this).dialog('close'); }, }); }; self.menu = function() { var html = '
' + 'Range and route setup...' + 'Move remote control' + 'Reset remote control location' + 'Zoom to view total route' + 'Import/Export (' + self.hacked.length + ') hacked portals...' + 'Import/Export route...' + 'Store/restore routes...' + 'Remove route (' + self.linecount() + ' lines)...' + '
' + 'version ' + self.version + ' by ' + self.author + '' + '
'; window.dialog({ html: html, id: self.id, dialogClass: 'ui-dialog-' + self.pluginname, width: 'auto', title: self.title }).dialog('option', 'buttons', { 'About': function() { self.about(); }, 'Close': function() { $(this).dialog('close'); } }); }; self.setupColorpickerSpectrum = function() { // source: https://github.com/bgrins/spectrum // minified with https://www.minifier.org/ // Spectrum Colorpicker v1.8.1 // https://github.com/bgrins/spectrum // Author: Brian Grinstead // License: MIT (function(factory){"use strict";if(typeof define==='function'&&define.amd){define(['jquery'],factory)}else if(typeof exports=="object"&&typeof module=="object"){module.exports=factory(require('jquery'))}else{factory(jQuery)}})(function($,undefined){"use strict";var defaultOpts={beforeShow:noop,move:noop,change:noop,show:noop,hide:noop,color:!1,flat:!1,showInput:!1,allowEmpty:!1,showButtons:!0,clickoutFiresChange:!0,showInitial:!1,showPalette:!1,showPaletteOnly:!1,hideAfterPaletteSelect:!1,togglePaletteOnly:!1,showSelectionPalette:!0,localStorageKey:!1,appendTo:"body",maxSelectionSize:7,cancelText:"cancel",chooseText:"choose",togglePaletteMoreText:"more",togglePaletteLessText:"less",clearText:"Clear Color Selection",noColorSelectedText:"No Color Selected",preferredFormat:!1,className:"",containerClassName:"",replacerClassName:"",showAlpha:!1,theme:"sp-light",palette:[["#ffffff","#000000","#ff0000","#ff8000","#ffff00","#008000","#0000ff","#4b0082","#9400d3"]],selectionPalette:[],disabled:!1,offset:null},spectrums=[],IE=!!/msie/i.exec(window.navigator.userAgent),rgbaSupport=(function(){function contains(str,substr){return!!~(''+str).indexOf(substr)} var elem=document.createElement('div');var style=elem.style;style.cssText='background-color:rgba(0,0,0,.5)';return contains(style.backgroundColor,'rgba')||contains(style.backgroundColor,'hsla')})(),replaceInput=["
","
","
","
"].join(''),markup=(function(){var gradientFix="";if(IE){for(var i=1;i<=6;i++){gradientFix+="
"}} return["
","
","
","
","","
","
","
","
","
","
","
","
","
","
","
","
","
","
","
","
","
",gradientFix,"
","
","
","
","
","","
","
","
","","","
","
","
"].join("")})();function paletteTemplate(p,color,className,opts){var html=[];for(var i=0;i')}else{var cls='sp-clear-display';html.push($('
').append($('').attr('title',opts.noColorSelectedText)).html())}} return"
"+html.join('')+"
"} function hideAll(){for(var i=0;iMath.abs(dragY-oldDragY);shiftMovementDirection=furtherFromX?"x":"y"} var setSaturation=!shiftMovementDirection||shiftMovementDirection==="x";var setValue=!shiftMovementDirection||shiftMovementDirection==="y";if(setSaturation){currentSaturation=parseFloat(dragX/dragWidth)} if(setValue){currentValue=parseFloat((dragHeight-dragY)/dragHeight)} isEmpty=!1;if(!opts.showAlpha){currentAlpha=1} move()},dragStart,dragStop);if(!!initialColor){set(initialColor);updateUI();currentPreferredFormat=opts.preferredFormat||tinycolor(initialColor).format;addColorToSelectionPalette(initialColor)}else{updateUI()} if(flat){show()} function paletteElementClick(e){if(e.data&&e.data.ignore){set($(e.target).closest(".sp-thumb-el").data("color"));move()}else{set($(e.target).closest(".sp-thumb-el").data("color"));move();if(opts.hideAfterPaletteSelect){updateOriginalInput(!0);hide()}else{updateOriginalInput()}} return!1} var paletteEvent=IE?"mousedown.spectrum":"click.spectrum touchstart.spectrum";paletteContainer.on(paletteEvent,".sp-thumb-el",paletteElementClick);initialColorContainer.on(paletteEvent,".sp-thumb-el:nth-child(1)",{ignore:!0},paletteElementClick)} function updateSelectionPaletteFromStorage(){if(localStorageKey&&window.localStorage){try{var oldPalette=window.localStorage[localStorageKey].split(",#");if(oldPalette.length>1){delete window.localStorage[localStorageKey];$.each(oldPalette,function(i,c){addColorToSelectionPalette(c)})}}catch(e){} try{selectionPalette=window.localStorage[localStorageKey].split(";")}catch(e){}}} function addColorToSelectionPalette(color){if(showSelectionPalette){var rgb=tinycolor(color).toRgbString();if(!paletteLookup[rgb]&&$.inArray(rgb,selectionPalette)===-1){selectionPalette.push(rgb);while(selectionPalette.length>maxSelectionSize){selectionPalette.shift()}} if(localStorageKey&&window.localStorage){try{window.localStorage[localStorageKey]=selectionPalette.join(";")}catch(e){}}}} function getUniqueSelectionPalette(){var unique=[];if(opts.showPalette){for(var i=0;iviewWidth&&viewWidth>dpWidth)?Math.abs(offsetLeft+dpWidth-viewWidth):0);offsetTop-=Math.min(offsetTop,((offsetTop+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(dpHeight+inputHeight-extraY):extraY));return{top:offsetTop,bottom:offset.bottom,left:offsetLeft,right:offset.right,width:offset.width,height:offset.height}} function noop(){} function stopPropagation(e){e.stopPropagation()} function bind(func,obj){var slice=Array.prototype.slice;var args=slice.call(arguments,2);return function(){return func.apply(obj,args.concat(slice.call(arguments)))}} function draggable(element,onmove,onstart,onstop){onmove=onmove||function(){};onstart=onstart||function(){};onstop=onstop||function(){};var doc=document;var dragging=!1;var offset={};var maxHeight=0;var maxWidth=0;var hasTouch=('ontouchstart' in window);var duringDragEvents={};duringDragEvents.selectstart=prevent;duringDragEvents.dragstart=prevent;duringDragEvents["touchmove mousemove"]=move;duringDragEvents["touchend mouseup"]=stop;function prevent(e){if(e.stopPropagation){e.stopPropagation()} if(e.preventDefault){e.preventDefault()} e.returnValue=!1} function move(e){if(dragging){if(IE&&doc.documentMode<9&&!e.button){return stop()} var t0=e.originalEvent&&e.originalEvent.touches&&e.originalEvent.touches[0];var pageX=t0&&t0.pageX||e.pageX;var pageY=t0&&t0.pageY||e.pageY;var dragX=Math.max(0,Math.min(pageX-offset.left,maxWidth));var dragY=Math.max(0,Math.min(pageY-offset.top,maxHeight));if(hasTouch){prevent(e)} onmove.apply(element,[dragX,dragY,e])}} function start(e){var rightclick=(e.which)?(e.which==3):(e.button==2);if(!rightclick&&!dragging){if(onstart.apply(element,arguments)!==!1){dragging=!0;maxHeight=$(element).height();maxWidth=$(element).width();offset=$(element).offset();$(doc).on(duringDragEvents);$(doc.body).addClass("sp-dragging");move(e);prevent(e)}}} function stop(){if(dragging){$(doc).off(duringDragEvents);$(doc.body).removeClass("sp-dragging");setTimeout(function(){onstop.apply(element,arguments)},0)} dragging=!1} $(element).on("touchstart mousedown",start)} function throttle(func,wait,debounce){var timeout;return function(){var context=this,args=arguments;var throttler=function(){timeout=null;func.apply(context,args)};if(debounce)clearTimeout(timeout);if(debounce||!timeout)timeout=setTimeout(throttler,wait)}} function inputTypeColorSupport(){return $.fn.spectrum.inputTypeColorSupport()} var dataID="spectrum.id";$.fn.spectrum=function(opts,extra){if(typeof opts=="string"){var returnValue=this;var args=Array.prototype.slice.call(arguments,1);this.each(function(){var spect=spectrums[$(this).data(dataID)];if(spect){var method=spect[opts];if(!method){throw new Error("Spectrum: no such method: '"+opts+"'")} if(opts=="get"){returnValue=spect.get()}else if(opts=="container"){returnValue=spect.container}else if(opts=="option"){returnValue=spect.option.apply(spect,args)}else if(opts=="destroy"){spect.destroy();$(this).removeData(dataID)}else{method.apply(spect,args)}}});return returnValue} return this.spectrum("destroy").each(function(){var options=$.extend({},$(this).data(),opts);var spect=spectrum(this,options);$(this).data(dataID,spect.id)})};$.fn.spectrum.load=!0;$.fn.spectrum.loadOpts={};$.fn.spectrum.draggable=draggable;$.fn.spectrum.defaults=defaultOpts;$.fn.spectrum.inputTypeColorSupport=function inputTypeColorSupport(){if(typeof inputTypeColorSupport._cachedResult==="undefined"){var colorInput=$("")[0];inputTypeColorSupport._cachedResult=colorInput.type==="color"&&colorInput.value!==""} return inputTypeColorSupport._cachedResult};$.spectrum={};$.spectrum.localization={};$.spectrum.palettes={};$.fn.spectrum.processNativeColorInputs=function(){var colorInputs=$("input[type=color]");if(colorInputs.length&&!inputTypeColorSupport()){colorInputs.spectrum({preferredFormat:"hex6"})}};(function(){var trimLeft=/^[\s,#]+/,trimRight=/\s+$/,tinyCounter=0,math=Math,mathRound=math.round,mathMin=math.min,mathMax=math.max,mathRandom=math.random;var tinycolor=function(color,opts){color=(color)?color:'';opts=opts||{};if(color instanceof tinycolor){return color} if(!(this instanceof tinycolor)){return new tinycolor(color,opts)} var rgb=inputToRGB(color);this._originalInput=color;this._r=rgb.r;this._g=rgb.g;this._b=rgb.b;this._a=rgb.a;this._roundA=mathRound(1000*this._a)/1000;this._format=opts.format||rgb.format;this._gradientType=opts.gradientType;if(this._r<1){this._r=mathRound(this._r)} if(this._g<1){this._g=mathRound(this._g)} if(this._b<1){this._b=mathRound(this._b)} this._ok=rgb.ok;this._tc_id=tinyCounter++};tinycolor.prototype={isDark:function(){return this.getBrightness()<128},isLight:function(){return!this.isDark()},isValid:function(){return this._ok},getOriginalInput:function(){return this._originalInput},getFormat:function(){return this._format},getAlpha:function(){return this._a},getBrightness:function(){var rgb=this.toRgb();return(rgb.r*299+rgb.g*587+rgb.b*114)/1000},setAlpha:function(value){this._a=boundAlpha(value);this._roundA=mathRound(1000*this._a)/1000;return this},toHsv:function(){var hsv=rgbToHsv(this._r,this._g,this._b);return{h:hsv.h*360,s:hsv.s,v:hsv.v,a:this._a}},toHsvString:function(){var hsv=rgbToHsv(this._r,this._g,this._b);var h=mathRound(hsv.h*360),s=mathRound(hsv.s*100),v=mathRound(hsv.v*100);return(this._a==1)?"hsv("+h+", "+s+"%, "+v+"%)":"hsva("+h+", "+s+"%, "+v+"%, "+this._roundA+")"},toHsl:function(){var hsl=rgbToHsl(this._r,this._g,this._b);return{h:hsl.h*360,s:hsl.s,l:hsl.l,a:this._a}},toHslString:function(){var hsl=rgbToHsl(this._r,this._g,this._b);var h=mathRound(hsl.h*360),s=mathRound(hsl.s*100),l=mathRound(hsl.l*100);return(this._a==1)?"hsl("+h+", "+s+"%, "+l+"%)":"hsla("+h+", "+s+"%, "+l+"%, "+this._roundA+")"},toHex:function(allow3Char){return rgbToHex(this._r,this._g,this._b,allow3Char)},toHexString:function(allow3Char){return'#'+this.toHex(allow3Char)},toHex8:function(){return rgbaToHex(this._r,this._g,this._b,this._a)},toHex8String:function(){return'#'+this.toHex8()},toRgb:function(){return{r:mathRound(this._r),g:mathRound(this._g),b:mathRound(this._b),a:this._a}},toRgbString:function(){return(this._a==1)?"rgb("+mathRound(this._r)+", "+mathRound(this._g)+", "+mathRound(this._b)+")":"rgba("+mathRound(this._r)+", "+mathRound(this._g)+", "+mathRound(this._b)+", "+this._roundA+")"},toPercentageRgb:function(){return{r:mathRound(bound01(this._r,255)*100)+"%",g:mathRound(bound01(this._g,255)*100)+"%",b:mathRound(bound01(this._b,255)*100)+"%",a:this._a}},toPercentageRgbString:function(){return(this._a==1)?"rgb("+mathRound(bound01(this._r,255)*100)+"%, "+mathRound(bound01(this._g,255)*100)+"%, "+mathRound(bound01(this._b,255)*100)+"%)":"rgba("+mathRound(bound01(this._r,255)*100)+"%, "+mathRound(bound01(this._g,255)*100)+"%, "+mathRound(bound01(this._b,255)*100)+"%, "+this._roundA+")"},toName:function(){if(this._a===0){return"transparent"} if(this._a<1){return!1} return hexNames[rgbToHex(this._r,this._g,this._b,!0)]||!1},toFilter:function(secondColor){var hex8String='#'+rgbaToHex(this._r,this._g,this._b,this._a);var secondHex8String=hex8String;var gradientType=this._gradientType?"GradientType = 1, ":"";if(secondColor){var s=tinycolor(secondColor);secondHex8String=s.toHex8String()} return"progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"},toString:function(format){var formatSet=!!format;format=format||this._format;var formattedString=!1;var hasAlpha=this._a<1&&this._a>=0;var needsAlphaFormat=!formatSet&&hasAlpha&&(format==="hex"||format==="hex6"||format==="hex3"||format==="name");if(needsAlphaFormat){if(format==="name"&&this._a===0){return this.toName()} return this.toRgbString()} if(format==="rgb"){formattedString=this.toRgbString()} if(format==="prgb"){formattedString=this.toPercentageRgbString()} if(format==="hex"||format==="hex6"){formattedString=this.toHexString()} if(format==="hex3"){formattedString=this.toHexString(!0)} if(format==="hex8"){formattedString=this.toHex8String()} if(format==="name"){formattedString=this.toName()} if(format==="hsl"){formattedString=this.toHslString()} if(format==="hsv"){formattedString=this.toHsvString()} return formattedString||this.toHexString()},_applyModification:function(fn,args){var color=fn.apply(null,[this].concat([].slice.call(args)));this._r=color._r;this._g=color._g;this._b=color._b;this.setAlpha(color._a);return this},lighten:function(){return this._applyModification(lighten,arguments)},brighten:function(){return this._applyModification(brighten,arguments)},darken:function(){return this._applyModification(darken,arguments)},desaturate:function(){return this._applyModification(desaturate,arguments)},saturate:function(){return this._applyModification(saturate,arguments)},greyscale:function(){return this._applyModification(greyscale,arguments)},spin:function(){return this._applyModification(spin,arguments)},_applyCombination:function(fn,args){return fn.apply(null,[this].concat([].slice.call(args)))},analogous:function(){return this._applyCombination(analogous,arguments)},complement:function(){return this._applyCombination(complement,arguments)},monochromatic:function(){return this._applyCombination(monochromatic,arguments)},splitcomplement:function(){return this._applyCombination(splitcomplement,arguments)},triad:function(){return this._applyCombination(triad,arguments)},tetrad:function(){return this._applyCombination(tetrad,arguments)}};tinycolor.fromRatio=function(color,opts){if(typeof color=="object"){var newColor={};for(var i in color){if(color.hasOwnProperty(i)){if(i==="a"){newColor[i]=color[i]}else{newColor[i]=convertToPercentage(color[i])}}} color=newColor} return tinycolor(color,opts)};function inputToRGB(color){var rgb={r:0,g:0,b:0};var a=1;var ok=!1;var format=!1;if(typeof color=="string"){color=stringInputToObject(color)} if(typeof color=="object"){if(color.hasOwnProperty("r")&&color.hasOwnProperty("g")&&color.hasOwnProperty("b")){rgb=rgbToRgb(color.r,color.g,color.b);ok=!0;format=String(color.r).substr(-1)==="%"?"prgb":"rgb"}else if(color.hasOwnProperty("h")&&color.hasOwnProperty("s")&&color.hasOwnProperty("v")){color.s=convertToPercentage(color.s);color.v=convertToPercentage(color.v);rgb=hsvToRgb(color.h,color.s,color.v);ok=!0;format="hsv"}else if(color.hasOwnProperty("h")&&color.hasOwnProperty("s")&&color.hasOwnProperty("l")){color.s=convertToPercentage(color.s);color.l=convertToPercentage(color.l);rgb=hslToRgb(color.h,color.s,color.l);ok=!0;format="hsl"} if(color.hasOwnProperty("a")){a=color.a}} a=boundAlpha(a);return{ok:ok,format:color.format||format,r:mathMin(255,mathMax(rgb.r,0)),g:mathMin(255,mathMax(rgb.g,0)),b:mathMin(255,mathMax(rgb.b,0)),a:a}} function rgbToRgb(r,g,b){return{r:bound01(r,255)*255,g:bound01(g,255)*255,b:bound01(b,255)*255}} function rgbToHsl(r,g,b){r=bound01(r,255);g=bound01(g,255);b=bound01(b,255);var max=mathMax(r,g,b),min=mathMin(r,g,b);var h,s,l=(max+min)/2;if(max==min){h=s=0}else{var d=max-min;s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p} if(s===0){r=g=b=l}else{var q=l<0.5?l*(1+s):l+s-l*s;var p=2*l-q;r=hue2rgb(p,q,h+1/3);g=hue2rgb(p,q,h);b=hue2rgb(p,q,h-1/3)} return{r:r*255,g:g*255,b:b*255}} function rgbToHsv(r,g,b){r=bound01(r,255);g=bound01(g,255);b=bound01(b,255);var max=mathMax(r,g,b),min=mathMin(r,g,b);var h,s,v=max;var d=max-min;s=max===0?0:d/max;if(max==min){h=0}else{switch(max){case r:h=(g-b)/d+(g>1))+720)%360;--results;){hsl.h=(hsl.h+part)%360;ret.push(tinycolor(hsl))} return ret} function monochromatic(color,results){results=results||6;var hsv=tinycolor(color).toHsv();var h=hsv.h,s=hsv.s,v=hsv.v;var ret=[];var modification=1/results;while(results--){ret.push(tinycolor({h:h,s:s,v:v}));v=(v+modification)%1} return ret} tinycolor.mix=function(color1,color2,amount){amount=(amount===0)?0:(amount||50);var rgb1=tinycolor(color1).toRgb();var rgb2=tinycolor(color2).toRgb();var p=amount/100;var w=p*2-1;var a=rgb2.a-rgb1.a;var w1;if(w*a==-1){w1=w}else{w1=(w+a)/(1+w*a)} w1=(w1+1)/2;var w2=1-w1;var rgba={r:rgb2.r*w1+rgb1.r*w2,g:rgb2.g*w1+rgb1.g*w2,b:rgb2.b*w1+rgb1.b*w2,a:rgb2.a*p+rgb1.a*(1-p)};return tinycolor(rgba)};tinycolor.readability=function(color1,color2){var c1=tinycolor(color1);var c2=tinycolor(color2);var rgb1=c1.toRgb();var rgb2=c2.toRgb();var brightnessA=c1.getBrightness();var brightnessB=c2.getBrightness();var colorDiff=(Math.max(rgb1.r,rgb2.r)-Math.min(rgb1.r,rgb2.r)+Math.max(rgb1.g,rgb2.g)-Math.min(rgb1.g,rgb2.g)+Math.max(rgb1.b,rgb2.b)-Math.min(rgb1.b,rgb2.b));return{brightness:Math.abs(brightnessA-brightnessB),color:colorDiff}};tinycolor.isReadable=function(color1,color2){var readability=tinycolor.readability(color1,color2);return readability.brightness>125&&readability.color>500};tinycolor.mostReadable=function(baseColor,colorList){var bestColor=null;var bestScore=0;var bestIsReadable=!1;for(var i=0;i125&&readability.color>500;var score=3*(readability.brightness/125)+(readability.color/500);if((readable&&!bestIsReadable)||(readable&&bestIsReadable&&score>bestScore)||((!readable)&&(!bestIsReadable)&&score>bestScore)){bestIsReadable=readable;bestScore=score;bestColor=tinycolor(colorList[i])}} return bestColor};var names=tinycolor.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"663399",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"};var hexNames=tinycolor.hexNames=flip(names);function flip(o){var flipped={};for(var i in o){if(o.hasOwnProperty(i)){flipped[o[i]]=i}} return flipped} function boundAlpha(a){a=parseFloat(a);if(isNaN(a)||a<0||a>1){a=1} return a} function bound01(n,max){if(isOnePointZero(n)){n="100%"} var processPercent=isPercentage(n);n=mathMin(max,mathMax(0,parseFloat(n)));if(processPercent){n=parseInt(n*max,10)/100} if((math.abs(n-max)<0.000001)){return 1} return(n%max)/parseFloat(max)} function clamp01(val){return mathMin(1,mathMax(0,val))} function parseIntFromHex(val){return parseInt(val,16)} function isOnePointZero(n){return typeof n=="string"&&n.indexOf('.')!=-1&&parseFloat(n)===1} function isPercentage(n){return typeof n==="string"&&n.indexOf('%')!=-1} function pad2(c){return c.length==1?'0'+c:''+c} function convertToPercentage(n){if(n<=1){n=(n*100)+"%"} return n} function convertDecimalToHex(d){return Math.round(parseFloat(d)*255).toString(16)} function convertHexToDecimal(h){return(parseIntFromHex(h)/255)} var matchers=(function(){var CSS_INTEGER="[-\\+]?\\d+%?";var CSS_NUMBER="[-\\+]?\\d*\\.\\d+%?";var CSS_UNIT="(?:"+CSS_NUMBER+")|(?:"+CSS_INTEGER+")";var PERMISSIVE_MATCH3="[\\s|\\(]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")\\s*\\)?";var PERMISSIVE_MATCH4="[\\s|\\(]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")[,|\\s]+("+CSS_UNIT+")\\s*\\)?";return{rgb:new RegExp("rgb"+PERMISSIVE_MATCH3),rgba:new RegExp("rgba"+PERMISSIVE_MATCH4),hsl:new RegExp("hsl"+PERMISSIVE_MATCH3),hsla:new RegExp("hsla"+PERMISSIVE_MATCH4),hsv:new RegExp("hsv"+PERMISSIVE_MATCH3),hsva:new RegExp("hsva"+PERMISSIVE_MATCH4),hex3:/^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex8:/^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/}})();function stringInputToObject(color){color=color.replace(trimLeft,'').replace(trimRight,'').toLowerCase();var named=!1;if(names[color]){color=names[color];named=!0}else if(color=='transparent'){return{r:0,g:0,b:0,a:0,format:"name"}} var match;if((match=matchers.rgb.exec(color))){return{r:match[1],g:match[2],b:match[3]}} if((match=matchers.rgba.exec(color))){return{r:match[1],g:match[2],b:match[3],a:match[4]}} if((match=matchers.hsl.exec(color))){return{h:match[1],s:match[2],l:match[3]}} if((match=matchers.hsla.exec(color))){return{h:match[1],s:match[2],l:match[3],a:match[4]}} if((match=matchers.hsv.exec(color))){return{h:match[1],s:match[2],v:match[3]}} if((match=matchers.hsva.exec(color))){return{h:match[1],s:match[2],v:match[3],a:match[4]}} if((match=matchers.hex8.exec(color))){return{a:convertHexToDecimal(match[1]),r:parseIntFromHex(match[2]),g:parseIntFromHex(match[3]),b:parseIntFromHex(match[4]),format:named?"name":"hex8"}} if((match=matchers.hex6.exec(color))){return{r:parseIntFromHex(match[1]),g:parseIntFromHex(match[2]),b:parseIntFromHex(match[3]),format:named?"name":"hex"}} if((match=matchers.hex3.exec(color))){return{r:parseIntFromHex(match[1]+''+match[1]),g:parseIntFromHex(match[2]+''+match[2]),b:parseIntFromHex(match[3]+''+match[3]),format:named?"name":"hex"}} return!1} window.tinycolor=tinycolor})();$(function(){if($.fn.spectrum.load){$.fn.spectrum.processNativeColorInputs()}})}); $('head').append(''); }; // end setupColorpickerSpectrum self.setup = function() { if ('pluginloaded' in self) { console.log('IITC plugin already loaded: ' + self.title + ' version ' + self.version); return; } else { self.pluginloaded = true; } self.restoresettings(); self.setupColorpickerSpectrum(); self.hacked = self.restorearray(self.localstoragehacked); self.layer = new L.FeatureGroup(); window.addLayerGroup(self.routelayertitle, self.layer, true); map.on('layeradd', function(obj) { if (obj.layer === self.layer) { self.showremote(); self.onPortalSelected(); } }); map.on('layerremove', function(obj) { if (obj.layer === self.layer) { self.dronemarker_remove(); self.onPortalSelected(); self.hideremote(); } }); self.restorelines(); self.halfrangelayer = new L.FeatureGroup(); window.addLayerGroup(self.halfrangelayertitle, self.halfrangelayer, true); map.on('layeradd', function(obj) { if (obj.layer === self.halfrangelayer) { self.updatehalfrangelayer(); } }); map.on('layerremove', function(obj) { if (obj.layer === self.halfrangelayer) { } }); //map.addLayer(self.halfrangelayer); window.map.on('moveend', function() { window.setTimeout(self.updatehalfrangelayer); }); window.addHook('mapDataRefreshEnd',function() { window.setTimeout(self.updatehalfrangelayer); }); window.addHook('portalAdded', self.onportalAdded); window.addHook('portalRemoved', self.onportalRemoved); window.addPortalHighlighter(self.highlighthackedname,self.highlightportals); // if hightligheractive: if (window._current_highlighter == self.highlighthackedname) { self.hightlighteractive = true; self.updateHighlighter(); } window.map.on('zoomend', function() { self.drawmarker_redraw(); }); window.addHook('portalSelected', self.onPortalSelected); $('#toolbox').append('' + self.title + ''); $('head').append( ''); self.isSmartphone = window.isSmartphone(); $('head').append(''); $('head').append(''); if (self.layeractive(self.routelayertitle)) { self.showremote(); } console.log('IITC plugin loaded: ' + self.title + ' version ' + self.version); }; var setup = function() { (window.iitcLoaded?self.setup():window.addHook('iitcLoaded',self.setup)); }; setup.info = plugin_info; //add the script info data to the function as a property if(!window.bootPlugins) window.bootPlugins = []; window.bootPlugins.push(setup); // if IITC has already booted, immediately run the 'setup' function if(window.iitcLoaded && typeof setup === 'function') setup(); } // wrapper end // inject code into site context var script = document.createElement('script'); var info = {}; if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description }; script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');')); (document.body || document.head || document.documentElement).appendChild(script);