diff --git a/.gitignore b/.gitignore index 1df2b76f..55ccd51b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ localbuildsettings.py *~ *.bak *.project +.pydevproject diff --git a/plugins/unique.css b/plugins/unique.css new file mode 100644 index 00000000..f5454699 --- /dev/null +++ b/plugins/unique.css @@ -0,0 +1,17 @@ +#uniques-content-outer { + display: table; + width: 100%; + height: 26px; + text-align: center; +} + +#uniques-content-outer > div{ + display: inline-block; + vertical-align: middle; + margin: 6px 3px 1px 3px; +} + +#uniques-label { + padding: 0 4px; + cursor: help; +} diff --git a/plugins/uniques.user.js b/plugins/uniques.user.js new file mode 100644 index 00000000..7b838020 --- /dev/null +++ b/plugins/uniques.user.js @@ -0,0 +1,216 @@ +//==UserScript== +//@id iitc-plugin-uniques@3ch01c +//@name IITC plugin: Uniques +//@category Misc +//@version 0.2.0.@@DATETIMEVERSION@@ +//@namespace https://github.com/3ch01c/ingress-intel-total-conversion +//@updateURL @@UPDATEURL@@ +//@downloadURL @@DOWNLOADURL@@ +//@description [@@BUILDNAME@@-@@BUILDDATE@@] Allow manual entry of portals hacked/captured. Use the 'highlighter-uniques' plugin to show the uniques on the map, and 'sync' to share between multiple browsers or desktop/mobile. +//@include https://www.ingress.com/intel* +//@include http://www.ingress.com/intel* +//@match https://www.ingress.com/intel* +//@match http://www.ingress.com/intel* +//@grant none +//==/UserScript== + +@@PLUGINSTART@@ +//PLUGIN START //////////////////////////////////////////////////////// + +//use own namespace for plugin +window.plugin.uniques = function() {}; + +//delay in ms +window.plugin.uniques.SYNC_DELAY = 10000; + +window.plugin.uniques.LOCAL_STORAGE_KEY = 'plugin-uniques-data'; + +window.plugin.uniques.KEY = {key: window.plugin.uniques.LOCAL_STORAGE_KEY, field: 'uniques'}; +window.plugin.uniques.UPDATE_QUEUE = {key: 'plugin-uniques-data-queue', field: 'updateQueue'}; +window.plugin.uniques.UPDATING_QUEUE = {key: 'plugin-uniques-data-updating-queue', field: 'updatingQueue'}; + +window.plugin.uniques.uniques = {}; +window.plugin.uniques.updateQueue = {}; +window.plugin.uniques.updatingQueue = {}; + +window.plugin.uniques.enableSync = false; + +window.plugin.uniques.disabledMessage = null; +window.plugin.uniques.contentHTML = null; + +window.plugin.uniques.addToSidebar = function() { + if(typeof(Storage) === "undefined") { + $('#portaldetails > .imgpreview').after(plugin.uniques.disabledMessage); + return; + } + + $('#portaldetails > .imgpreview').after(plugin.uniques.contentHTML); + plugin.uniques.updateChecked(); +} + +window.plugin.uniques.updateChecked = function() { + var guid = window.selectedPortal, + hacked = (plugin.uniques.uniques[guid] && plugin.uniques.uniques[guid].hacked) || false, + captured = (plugin.uniques.uniques[guid] && plugin.uniques.uniques[guid].captured) || false; + $('#hacked').prop('checked', hacked); + $('#captured').prop('checked', captured); +} + +window.plugin.uniques.updateHacked = function(hacked) { + var guid = window.selectedPortal; + if (hacked) { + // add entry + if (guid in plugin.uniques.uniques) { plugin.uniques.uniques[guid].hacked = true; } + else { plugin.uniques.uniques[guid] = {hacked: true}; } + if (guid in plugin.uniques.updateQueue) { plugin.uniques.updateQueue[guid].hacked = true; } + else { plugin.uniques.updateQueue[guid] = {hacked: true}; } + } else if (guid in plugin.uniques.uniques) { + // remove entry + if (plugin.uniques.uniques[guid].captured === undefined) { delete plugin.uniques.uniques[guid]; } + else { delete plugin.uniques.uniques[guid].hacked; } + } + plugin.uniques.storeLocal(plugin.uniques.KEY); + plugin.uniques.storeLocal(plugin.uniques.UPDATE_QUEUE); + plugin.uniques.delaySync(); +} + +window.plugin.uniques.updateCaptured = function(captured) { + var guid = window.selectedPortal; + if (captured) { + // add entry + if (guid in plugin.uniques.uniques) { plugin.uniques.uniques[guid].captured = true; } + else { plugin.uniques.uniques[guid] = {captured: true}; } + if (guid in plugin.uniques.updateQueue) { plugin.uniques.updateQueue[guid].captured = true; } + else { plugin.uniques.updateQueue[guid] = {captured: true}; } + } else if (guid in plugin.uniques.uniques) { + // remove entry + if (plugin.uniques.uniques[guid].captured === undefined) { delete plugin.uniques.uniques[guid]; } + else { delete plugin.uniques.uniques[guid].captured; } + } + plugin.uniques.storeLocal(plugin.uniques.KEY); + plugin.uniques.storeLocal(plugin.uniques.UPDATE_QUEUE); + plugin.uniques.delaySync(); +} + +//Delay the syncing to group a few updates in a single request +window.plugin.uniques.delaySync = function() { + if(!plugin.uniques.enableSync) return; + clearTimeout(plugin.uniques.delaySync.timer); + plugin.uniques.delaySync.timer = setTimeout(function() { + plugin.uniques.delaySync.timer = null; + window.plugin.uniques.syncNow(); + }, plugin.uniques.SYNC_DELAY); +} + +//Store the updateQueue in updatingQueue and upload +window.plugin.uniques.syncNow = function() { + if(!plugin.uniques.enableSync) return; + $.extend(plugin.uniques.updatingQueue, plugin.uniques.updateQueue); + plugin.uniques.updateQueue = {}; + plugin.uniques.storeLocal(plugin.uniques.UPDATING_QUEUE); + plugin.uniques.storeLocal(plugin.uniques.UPDATE_QUEUE); + + plugin.sync.updateMap('uniques', 'uniques', plugin.uniques.updatingQueue); +} + +//Call after IITC and all plugin loaded +window.plugin.uniques.registerFieldForSyncing = function() { + if(!window.plugin.sync) return; + window.plugin.sync.registerMapForSync('uniques', 'uniques', window.plugin.uniques.syncCallback, window.plugin.uniques.syncInitialed); +} + +//Call after local or remote change uploaded +window.plugin.uniques.syncCallback = function(pluginName, fieldName, e, fullUpdated) { + if(fieldName === 'uniques') { + plugin.uniques.storeLocal(plugin.uniques.KEY); + // All data is replaced if other client update the data during this client + // offline, + // fire 'pluginUniquesRefreshAll' to notify a full update + if(fullUpdated) { + plugin.uniques.updateChecked(); + window.runHooks('pluginUniquesRefreshAll'); + return; + } + + if(!e) return; + if(e.isLocal) { + // Update pushed successfully, remove it from updatingQueue + delete plugin.uniques.updatingQueue[e.property]; + } else { + // Remote update + delete plugin.uniques.updateQueue[e.property]; + plugin.uniques.storeLocal(plugin.uniques.UPDATE_QUEUE); + plugin.uniques.updateChecked(); + window.runHooks('pluginUniquesUpdateUniques', {guid: e.property}); + } + } +} + +//syncing of the field is initialed, upload all queued update +window.plugin.uniques.syncInitialed = function(pluginName, fieldName) { + if(fieldName === 'uniques') { + plugin.uniques.enableSync = true; + if(Object.keys(plugin.uniques.updateQueue).length > 0) { + plugin.uniques.delaySync(); + } + } +} + +window.plugin.uniques.storeLocal = function(mapping) { + if(typeof(plugin.uniques[mapping.field]) !== 'undefined' && plugin.uniques[mapping.field] !== null) { + localStorage[mapping.key] = JSON.stringify(plugin.uniques[mapping.field]); + } else { + localStorage.removeItem(mapping.key); + } +} + +window.plugin.uniques.loadLocal = function(mapping) { + if (localStorage[mapping.key] !== undefined) { plugin.uniques[mapping.field] = JSON.parse(localStorage[mapping.key]); } +} + +/***************************************************************************************************************************************************************/ +/** HIGHLIGHTER ************************************************************************************************************************************************/ +/***************************************************************************************************************************************************************/ +window.plugin.uniques.highlight = function(data) { + var guid = data.portal.options.ent[0]; + if((uniqueInfo = window.plugin.uniques.uniques[guid]) !== undefined) { + if (!uniqueInfo.hacked && !uniqueInfo.captured) { data.portal.setStyle({fillColor:'magenta', fillOpacity:1}); } + else if (uniqueInfo.captured && !uniqueInfo.hacked) { data.portal.setStyle({fillColor:'red', fillOpacity:.75}); } + else if (uniqueInfo.hacked && !uniqueInfo.captured) { data.portal.setStyle({fillColor:'yellow', fillOpacity:.5}); } + } else { + data.portal.setStyle({fillColor:'magenta', fillOpacity:1}); + } +} + +window.plugin.uniques.setupCSS = function() { + $("