Skip to content

Instantly share code, notes, and snippets.

@johnd0e
Last active August 27, 2019 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnd0e/cedbbc998888c5f497aec4afcd641e58 to your computer and use it in GitHub Desktop.
Save johnd0e/cedbbc998888c5f497aec4afcd641e58 to your computer and use it in GitHub Desktop.
IITC plugin: Exports portals currently in view for use with Google Map /Earth (KML Format incl. extra data)

Install | Comment | Source

Ideas

kml

диалог/файл (заголовок/описание):

  • n точек
  • permalink в имя

область

диалог

  • проверить почему не копируется выделенное в диалоге, сравнить реализацию в других скриптах может кнопку добавить (см. copy link to portal https://github.com/TheSned/IITCPlugins)
  • поправить размер для mobile

// title и html_title

iitc-plugin-ingressKML-exporter.user.js
// ==UserScript==
// @id kml-exporter
// @name IITC plugin: KML Exporter
// @category Tools
// @version 1
// @namespace https://gist.github.com/johnd0e
// @homepageURL https://gist.github.com/johnd0e/cedbbc998888c5f497aec4afcd641e58
// @supportURL https://gist.github.com/johnd0e/cedbbc998888c5f497aec4afcd641e58#new_comment_field
// @updateURL https://gist.github.com/johnd0e/cedbbc998888c5f497aec4afcd641e58/raw/KML-exporter.user.js
// @downloadURL https://gist.github.com/johnd0e/cedbbc998888c5f497aec4afcd641e58/raw/KML-exporter.user.js
// @description Exports portals currently in view for use with Google Map /Earth
// (KML Format incl. extra data).
// !! Currently styles are optimized for mobile GE
// @match https://intel.ingress.com/*
// @grant none
// ==/UserScript==
function wrapper(plugin_info) {
'use strict';
// ensure plugin framework is there, even if iitc is not yet loaded
if(typeof window.plugin !== 'function') window.plugin = function() {};
// base context for plugin
window.plugin.ingressKMLexporter = {};
const self = window.plugin.ingressKMLexporter;
// custom dialog wrapper with more flexibility
const TEAM_TO_CSS = ['none', 'res', 'enl'];
self.default = {
icon: 'http://www.gstatic.com/mapspro/images/stock/959-wht-circle-blank.png',
balloon: '<a href="$[portal/url]"><img src="$[portal/img]" height="80%" title="$[name]"/></a>', // mobile GE
iconColorMode: 'normal', // 'random': not working on mobile GE
labelColorMode: 'normal',
teams: {
none: {
iconColor: 'B00066FF'
},
res: {
iconColor: 'B0D09205'
},
enl: {
iconColor: 'B002BF02'
}
}
};
self.normal = {
iconScale: 0.3,
labelScale: 0.4,
teams: {} // default
};
self.highlight = {
iconScale: 0.7,
labelScale: 0.7,
teams: {} // default
};
//desktop GE
//self.BALLOON = '<a href="$[portal/url]"><img src="$[portal/img]" height="180" title="$[name]"/></a>'
//self.listBALLOON = '<a href="#$[id];balloonFlyto"><img src="$[portal/img]" height="180" title="fly to $[name]"/></a>'//
function genStyle (type,team) {
const s = L.extend({}, self.default, self[type], self.default.teams[team], self[type].teams[team]);
return `
<Style id="${team}-${type}">
<IconStyle>
<Icon><href>${s.icon}</href></Icon>
<color>${s.iconColor}</color>
<colorMode>${s.iconColorMode}</colorMode>
<scale>${s.iconScale}</scale>
</IconStyle>
<LabelStyle><scale>${s.labelScale}</scale><colorMode>${s.labelColorMode}</colorMode></LabelStyle>
<BalloonStyle>
<text><![CDATA[${s.balloon}]]></text>'
</BalloonStyle>
</Style>`;
/*
'<BalloonStyle>' +
' <text><![CDATA[' + self.BALLOON + ']]></text>' + // desktop: self.listBALLOON
' <displayMode>hide</displayMode>' + // desktop only
'</BalloonStyle>');
*/
}
function genStyles () {
const o = [];
['none','enl','res'].forEach(function (team) {
o.push(genStyle('normal',team));
o.push(genStyle('highlight',team));
});
return o.join('\n');
}
function genPortal (p) {
const d = p.options.data; // title, level, resCount, health, image
const teamStyle = TEAM_TO_CSS[p.options.team];
const ll = p.getLatLng(); // lat, lng
const url = `https://intel.ingress.com/intel?pll=${ll.lat},${ll.lng}`;
// const url = 'https://intel.ingress.com' + window.makePermalink(ll); // iitc-ce
const snippet = `<a href=${url}>${ll.lat},${ll.lng}</a>`;
const description = `<img src="${d.image}"/>${url}`;
/*
function safe_html(str) { //window.escapeHtmlSpecialChars
const span = document.createElement('span');
span.textContent = str;
return span.innerHTML;
}
const title_html = safe_html(title)
*/
return `
<Placemark id="${p.options.guid}">
<styleUrl>#${teamStyle}</styleUrl>
<name><![CDATA[${d.title}]]></name>
<description><![CDATA[${description}]]></description>
<Snippet maxLines="1"><![CDATA[${snippet}]]></Snippet>
<Point>
<coordinates>${ll.lng},${ll.lat},0.0</coordinates>
</Point>
<ExtendedData>
<SchemaData schemaUrl="#portal">
<SimpleData name="team">${teamStyle}</SimpleData>
<SimpleData name="level">${d.level}</SimpleData>
<SimpleData name="resCount">${d.resCount}</SimpleData>
<SimpleData name="health">${d.health}</SimpleData>
<SimpleData name="url">${url}</SimpleData>
<SimpleData name="img">${d.image}</SimpleData>
<!--SimpleData name="gx_media_links">${d.image}</SimpleData-->
</SchemaData>
</ExtendedData>
</Placemark>`;
}
function getPortals () {
const mapBounds = map.getBounds();
function inBounds (portal) {
return mapBounds.contains(portal.getLatLng());
}
const portals = [];
for (let x in window.portals) { portals.push(window.portals[x]); }
return portals.filter(inBounds);
}
function gen (portals,title) {
return `<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>[${title || 'Import from IITC'}]</name>
${portals.map(genPortal).join('\n')}
${genStyles()}
<Schema name="portal" id="portal">
<SimpleField type="string" name="team"></SimpleField>
<SimpleField type="uint" name="level"></SimpleField>
<SimpleField type="uint" name="resCount"></SimpleField>
<SimpleField type="uint" name="health"></SimpleField>
<SimpleField type="string" name="img"></SimpleField>
<SimpleField type="string" name="url"></SimpleField>
</Schema>
</Document>
</kml>
`;
}
function saveAs (data,filename,dataType) {
const link = document.createElement('a');
/*
dataType = dataType || 'text/plain;charset=utf-8'; // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
const uri = L.Util.template('data:{dataType};charset=utf-8,{content}',{
dataType: dataType,
content: encodeURIComponent(data)
});
link.href = data; // !!fails with large amounts of data
*/
if (!(data instanceof Array)) { data = [data]; }
const file = new Blob(data, {type: dataType}); // https://developer.mozilla.org/en-US/docs/Web/API/Blob
const objectURL = URL.createObjectURL(file); // https://www.w3.org/TR/FileAPI/#blob-url
link.href = objectURL;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
link.remove();
//setTimeout(function () {
URL.revokeObjectURL(objectURL);
//});
// alternative: https://github.com/eligrey/FileSaver.js/blob/master/src/FileSaver.js
return true;
}
function genDlg (data, filename, dataType) {
const description = $('<p>').html('Save the data below to a KML file and import it on <a href=https://google.com/maps/d> <code>google.com/maps/d</code></a>.');
const textarea = $('<textarea>',{rows: 30, style: 'width: 100%', autofocus: true}).val(data);
const buttons = $('<p>');
$('<button>').html('Copy').click(function () {
textarea.focus();
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard
document.execCommand("copy"); // https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
}).appendTo(buttons);
/*
if (typeof android !== 'undefined' && android.copy) {
$('<button>').html('Copy').click(function () {
const el = textarea[0];
android.copy(el.value.substring(el.selectionStart, el.selectionEnd));
}).appendTo(buttons);
}
*/
if (typeof android !== 'undefined' && android.shareString) {
$('<button>').html('Share').click(function () {
const el = textarea[0];
android.shareString(el.value.substring(el.selectionStart, el.selectionEnd));
}).appendTo(buttons);
// alt: https://developers.google.com/web/updates/2016/09/navigator-share
}
const androidSaveButton = $('<button>').html('Save').appendTo(buttons);
if (typeof android !== 'undefined' && android.saveFile) { // opposite: getFileRequestUrlPrefix/requestFile
androidSaveButton.click(function () {
android.saveFile(filename, dataType, data);
});
} else {
androidSaveButton.click(function () {
saveAs(data, filename, dataType);
});
}
const dialog = window.dialog({
title: 'Ingress KML Exporter',
html: $('<div>')
.append(description)
.append(buttons)
.append(textarea),
width: 600
});
dialog.parent().find('.ui-dialog-buttonpane').remove();
textarea.focus(function () {
const el = textarea[0];
if (el.selectionStart === el.selectionEnd) {
textarea.select();
}
});
}
function setup () {
/*
function pad (str, len) {
str = str.toString();
const n = (len || 2) - str.length;
return '0'.repeat(n>0 ? n : 0) + str;
}
const dt = new Date();
const dtf = pad(dt.getMonth()+1) + pad(dt.getDate()) + '_' + pad(dt.getHours()) + pad(dt.getMinutes()) + pad(dt.getSeconds());
*/
const file = $('<a title="Download KML-list of portals."><code>[.kml]</code></a>')
.click(function () {
const date = new Date().toLocaleString('ja',{dateStyle:'short',timeStyle:'medium',hour12:false});
const filename = date.replace(/[/:]/g,'').replace(' ','_') + '.kml';
const data = gen(getPortals(),`Import from IITC [${date}]`);
const dataType = 'application/vnd.google-earth.kml+xml';
if (typeof android !== 'undefined' && android.saveFile) { // opposite: getFileRequestUrlPrefix/requestFile
android.saveFile(filename, dataType, data);
} else {
saveAs(data,filename,dataType);
}
});
}
const dlg = $('<a title="Generate KML list of portals">KML Export</a>')
.click(function () {
const date = new Date().toLocaleString('ja',{dateStyle:'short',timeStyle:'medium',hour12:false});
const data = gen(getPortals(),`Import from IITC [${date}]`);
const filename = date.replace(/[/:]/g,'').replace(' ','_') + '.kml';
const dataType = 'application/vnd.google-earth.kml+xml';
genDlg(data,filename,dataType);
})
.appendTo('#toolbox')
.on('taphold',function (e) {
$(this).after(download).off('taphold');
});
}
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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment