diff --git a/plugins/missions.css b/plugins/missions.css index 6ca45056..5b62638e 100644 --- a/plugins/missions.css +++ b/plugins/missions.css @@ -160,3 +160,11 @@ width: 18px; } +.plugin-mission-search-result-desc { + display: block; + max-height: 2em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + diff --git a/plugins/missions.user.js b/plugins/missions.user.js index 72522d53..8d955ba8 100644 --- a/plugins/missions.user.js +++ b/plugins/missions.user.js @@ -883,6 +883,72 @@ window.plugin.missions = { } }, + onSearch: function(query) { + var self = this; + + if(query.confirmed) { + this.loadMissionsInBounds(window.map.getBounds(), function(missions) { + self.addMissionsToQuery(query, missions); + }); + } + + var cachedMissions = Object.keys(this.cacheByMissionGuid).map(function(guid) { + return self.cacheByMissionGuid[guid].data; + }); + + self.addMissionsToQuery(query, cachedMissions); + }, + + addMissionsToQuery: function(query, missions) { + var term = query.term.toLowerCase(); + + missions.forEach(function(mission) { + if(mission.title.toLowerCase().indexOf(term) === -1 + && ((!mission.description) || mission.description.toLowerCase().indexOf(term) === -1)) { + return; + } + + if(query.results.some(function(result) { return result.mission && (result.mission.guid == mission.guid); })) + // mission already in list (a cached mission may be found again via missions in bounds) + return; + + var result = { + title: escapeHtmlSpecialChars(mission.title), + description: mission.description + ? 'Recently viewed mission: ' + escapeHtmlSpecialChars(mission.description) + '' + : 'Mission in view', + icon: 'https://commondatastorage.googleapis.com/ingress.com/img/tm_icons/tm_cyan.png', + onSelected: this.onSearchResultSelected.bind(this), + mission: mission, + layer: null, // prevent a preview, we'll handle this + }; + + // mission may be a cached mission or contain the full details + if(mission.waypoints) { + var latlngs = mission.waypoints.filter(function(waypoint) { + return !!waypoint.portal; + }).map(function(waypoint) { + return [waypoint.portal.latE6/1E6, waypoint.portal.lngE6/1E6]; + }); + result.bounds = L.latLngBounds(latlngs) + } + if(mission.typeNum) { + result.icon = this.missionTypeImages[mission.typeNum] || this.missionTypeImages[0]; + } + + query.addResult(result); + }.bind(this)); + }, + + onSearchResultSelected: function(result, event) { + if(result.bounds) { + map.fitBounds(result.bounds, {maxZoom: 17}); + } + + this.openMission(result.mission.guid); + return false; + }, + setup: function() { this.cacheByPortalGuid = {}; this.cacheByMissionGuid = {}; @@ -923,6 +989,8 @@ window.plugin.missions = { // window.addPortalHighlighter('Mission start point', this.highlight.bind(this)); window.addHook('portalSelected', this.onPortalSelected.bind(this)); + window.addHook('search', this.onSearch.bind(this)); + /* I know iitc has portalAdded event but it is missing portalDeleted. So we have to resort to Object.observe */