From 782053e0615aef8b6b9100778e19090820501d3d Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 21 Sep 2013 11:51:15 -0700 Subject: [PATCH] Fix issues with object preselection in main view, object lookup in "SEO" view. Don't minify files in development. --- .gitignore | 2 +- api.py | 8 +- app.py | 9 +- local_config_example.py | 1 + static/js/main/controllers/Asterank3D.js | 59 ------ static/js/main/controllers/AsteroidDetails.js | 191 ------------------ static/js/main/controllers/AsteroidLookup.js | 29 --- static/js/main/controllers/AsteroidTable.js | 113 ----------- static/js/main/controllers/CustomInput.js | 93 --------- static/js/main/controllers/IntroStatement.js | 12 -- .../js/main/controllers/asteroid_details.js | 4 +- templates/asteroid.html | 4 +- 12 files changed, 18 insertions(+), 507 deletions(-) create mode 100644 local_config_example.py delete mode 100644 static/js/main/controllers/Asterank3D.js delete mode 100644 static/js/main/controllers/AsteroidDetails.js delete mode 100644 static/js/main/controllers/AsteroidLookup.js delete mode 100644 static/js/main/controllers/AsteroidTable.js delete mode 100644 static/js/main/controllers/CustomInput.js delete mode 100644 static/js/main/controllers/IntroStatement.js diff --git a/.gitignore b/.gitignore index c19102a..3bb01a3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,10 @@ *.rdb venv - build pip-log.txt nohup.out .DS_Store +local_config.py data/deltav/db2.csv diff --git a/api.py b/api.py index 7419f19..2b07b2d 100644 --- a/api.py +++ b/api.py @@ -66,14 +66,14 @@ def rankings(sort_by, limit, orbits_only=False): return ret def autocomplete(query, limit): - query = query.replace('+', ' ') + query = query.replace('+', ' ').lower() regx = re.compile(query, re.IGNORECASE) ret = list(asteroids.find({'full_name': {'$regex': regx}}, \ - {'_id': False}) - .limit(limit)) + {'_id': False})) + #.limit(limit)) # this sorting is not quite exact, as it penalizes asteroids with # long prefix numbers. But it's close enough. - return sorted(ret, key=lambda x: x['full_name'].find(query)) + return sorted(ret, key=lambda x: x['full_name'].lower().find(query))[:limit] def compositions(): return horizon.compositions() diff --git a/app.py b/app.py index c75ddf8..68dc574 100755 --- a/app.py +++ b/app.py @@ -18,6 +18,12 @@ mail = Mail(app) app.secret_key = 'not a secret key' +try: + import local_config + app.config['ASSETS_DEBUG'] = local_config.DEBUG +except ImportError: + pass + # bundling assets = Environment(app) # This filter can be helping for debugging javascript. @@ -59,7 +65,8 @@ def asteroid_details(asteroid_slug=None): if not asteroid_slug: return 'Sorry, could not find this asteroid in our database.', 404 unslug = asteroid_slug.replace('-', ' ') - candidates = api.autocomplete(unslug, 1) # TODO better way + # Need to get top 10, otherwise sometimes the best match is not returned by mongo. + candidates = api.autocomplete(unslug, 10) # TODO better way? if len(candidates) < 1: return 'Sorry, could not find this asteroid in our database.', 404 diff --git a/local_config_example.py b/local_config_example.py new file mode 100644 index 0000000..51c64dd --- /dev/null +++ b/local_config_example.py @@ -0,0 +1 @@ +DEBUG = True diff --git a/static/js/main/controllers/Asterank3D.js b/static/js/main/controllers/Asterank3D.js deleted file mode 100644 index d3bf9a5..0000000 --- a/static/js/main/controllers/Asterank3D.js +++ /dev/null @@ -1,59 +0,0 @@ -function Asterank3DCtrl($scope, pubsub) { - $scope.running = true; - - $scope.Init = function() { - asterank3d = new Asterank3D({ - container: document.getElementById('webgl-container'), - not_supported_callback: function() { - // TODO should be angularified - if (typeof mixpanel !== 'undefined') mixpanel.track('not supported'); - $('#webgl-not-supported').show(); - var $tc = $('#top-container'); - var $bc = $('#bottom-container'); - $tc.height($tc.height() + ($bc.height() - 250)) - $bc.height(250); - var $rs = $('#right-side'); - var $ls = $('#left-side'); - $('#results-table-container').height($rs.height() + 250); - $rs.height($rs.height() + 250); - $ls.height($ls.height() + 250); - }, - top_object_color: 0xffffff - }); - } - - $scope.SunView = function() { - asterank3d.clearLock(); - } - - $scope.EarthView = function() { - asterank3d.setLock('earth'); - } - - $scope.Pause = function() { - asterank3d.pause(); - $scope.running = false; - } - - $scope.Play = function() { - asterank3d.play(); - $scope.running = true; - } - - $scope.FullView = function() { - window.location.href="http://asterank.com/3d"; - } - - pubsub.subscribe('Lock3DView', function(asteroid) { - asterank3d.setLock(asteroid.full_name); - }); - - pubsub.subscribe('NewAsteroidRanking', function(rankings) { - asterank3d.clearRankings(); - asterank3d.processAsteroidRankings(rankings); - }); - - pubsub.subscribe('Default3DView', function() { - asterank3d.clearLock(); - }); -} diff --git a/static/js/main/controllers/AsteroidDetails.js b/static/js/main/controllers/AsteroidDetails.js deleted file mode 100644 index 81111e6..0000000 --- a/static/js/main/controllers/AsteroidDetails.js +++ /dev/null @@ -1,191 +0,0 @@ -function AsteroidDetailsCtrl($scope, $http, pubsub) { - 'use strict'; - - var MPC_FIELDS_TO_INCLUDE = { - // Already in JPL fields: - /* - 'a': { - 'name': 'Semimajor Axis', - 'units': 'AU' - }, - 'i': { - 'name': 'Inclination', - 'units': 'deg' - }, - */ - 'e': { - 'name': 'Eccentricity' - }, - 'epoch': { - 'name': 'Epoch' - }, - 'dv': { - 'name': 'Delta-v', - 'units': 'km/s' - }, - 'diameter': { - 'name': 'Diameter', - 'units': 'km' - }, - 'ma': { - 'name': 'Mean Anomaly', - 'units': 'deg @ epoch' - }, - 'om': { - 'name': 'Longitude of Ascending Node', - 'units': 'deg @ J2000' - }, - 'w': { - 'name': 'Argument of Perihelion', - 'units': 'deg @ J2000' - } - }; - - var blink_interval; // js interval used to blink sky survey images - - $scope.asteroid = null; - $scope.asteroid_details = null; - - $scope.Init = function() { - $scope.ResetView(); - } - - $scope.ResetView = function() { - $scope.showing_stats = []; // stats to show - $scope.approaches = []; // upcoming approaches - $scope.composition = []; - $scope.images = []; - $scope.images_loading = true; - if (blink_interval) { - clearInterval(blink_interval); - } - } - - var jpl_cache = new SimpleCache(); - var compositions_map = null; - - $scope.blink = function() { - if ($('#imagery .image-container input:checked').length < 2) { - alert('Please check off at least 2 images you want to blink.'); - return; - } - var $checked_containers = $('#imagery .image-container input:checked'); - var containers = $.makeArray($checked_containers); - function do_next_blink() { - $('#imagery .image-container').hide(); - var showme = containers.shift(); - $(showme).parent().parent().show(); // parent container div - containers.push(showme); - } - do_next_blink(); - blink_interval = setInterval(do_next_blink, 1000); - } - - pubsub.subscribe('AsteroidDetailsClick', function(asteroid) { - if ($scope.asteroid - && asteroid.full_name === $scope.asteroid.full_name) { - // already selected - $scope.asteroid = null; - pubsub.publish('ShowIntroStatement'); - pubsub.publish('Default3DView'); - return; - } - - // Update detailed click view - $scope.asteroid = asteroid; - $scope.ResetView(); - - // Flat fields that we just want to display - $scope.stats = []; - - pubsub.publish('HideIntroStatement'); - - // grab jpl asteroid details - var query = $scope.asteroid.prov_des || $scope.asteroid.full_name; - var cache_result = jpl_cache.Get(query); - if (cache_result) { - ShowData(cache_result); - } - else { - $http.get('/jpl/lookup?query=' + query) - .success(function(data) { - ShowData(data); - jpl_cache.Set($scope.asteroid.full_name, data); - }); - } - ShowOrbitalDiagram(); - - // Lock 3d view - pubsub.publish('Lock3DView', [asteroid]); - }); - - function ShowData(data) { - // JPL data from main view - for (var attr in data) { - if (!data.hasOwnProperty(attr)) continue; - if (typeof data[attr] !== 'object') { - if (data[attr] != -1) { - $scope.stats.push({ - // TODO these need to have units as a separate structure attr - name: attr.replace(/(.*?)\(.*?\)/, "$1"), - units: attr.replace(/.*?\((.*?)\)/, "$1"), - value: data[attr] - }); - } - } - } - - // JPL data includes MPC data - for (var attr in MPC_FIELDS_TO_INCLUDE) { - if (!MPC_FIELDS_TO_INCLUDE.hasOwnProperty(attr)) continue; - var val = MPC_FIELDS_TO_INCLUDE[attr]; - $scope.stats.push({ - name: attr, - units: val.units, - value: $scope.asteroid[attr] - }); - } - - // special fields: next pass and close approaches - $scope.approaches = data['Close Approaches']; - - if ($scope.asteroid.custom_object) { - $scope.images = []; - $scope.images_loading = false; - } - else { - // Composition data - if (compositions_map) { - // Object.keys not supported < ie9, so shim is required (see misc.js) - $scope.composition = Object.keys(compositions_map[$scope.asteroid.spec]); - } - else { - $http.get('/api/compositions').success(function(data) { - compositions_map = data; - $scope.composition = - Object.keys(compositions_map[$scope.asteroid.spec]); - }); - } - - // Imagery data! - var imagery_req_url = '/api/skymorph/images_for?target=' + $scope.asteroid.prov_des; - var requesting_images_for = $scope.asteroid.prov_des; - $http.get(imagery_req_url).success(function(data) { - if ($scope.asteroid.prov_des == requesting_images_for) { - $scope.images = data.images; - $scope.images_loading = false; - } - }); - } - } - - function ShowOrbitalDiagram() { - // Orbital diagram - var orbit_diagram = new OrbitDiagram('#orbit-2d-diagram', {}); - orbit_diagram.render( - $scope.asteroid.a, - $scope.asteroid.e, - $scope.asteroid.w - ); - } -} diff --git a/static/js/main/controllers/AsteroidLookup.js b/static/js/main/controllers/AsteroidLookup.js deleted file mode 100644 index 47abc5e..0000000 --- a/static/js/main/controllers/AsteroidLookup.js +++ /dev/null @@ -1,29 +0,0 @@ -function AsteroidLookupCtrl($scope, $http, pubsub) { - 'use strict'; - var PRESELECT_URL_PARAM = 'object'; - - $scope.lookup_query = ''; - - $scope.Init = function() { - var preselected = getURLParameter(PRESELECT_URL_PARAM); - if (preselected) { - // FIXME if preselected is already in the list by default, - // both are highlighted. - $scope.autocomplete_default_text = preselected; - // We manually hit the autocomplete endpoint. Was - // not straightforward to trigger dropdown + selection. - $http.get('/api/autocomplete?query=' + preselected) - .success(function(data) { - if (!data.length || data.length < 1) { - alert('Sorry, could not load object "' + preselected + '"'); - return; - } - pubsub.publish('UpdateRankingsWithFeaturedAsteroid', [data[0]]); - }); - } - } - - $scope.Lookup = function(suggestion) { - pubsub.publish('UpdateRankingsWithFeaturedAsteroid', [suggestion.data]); - } -} diff --git a/static/js/main/controllers/AsteroidTable.js b/static/js/main/controllers/AsteroidTable.js deleted file mode 100644 index 91475fe..0000000 --- a/static/js/main/controllers/AsteroidTable.js +++ /dev/null @@ -1,113 +0,0 @@ -function AsteroidTableCtrl($scope, $http, pubsub) { - 'use strict'; - // Config - $scope.rankings = []; - $scope.loading_initial_rankings = true; - $scope.sort_orders = [ - { - text: 'most cost effective', - search_value: 'score' - }, - { - text: 'most valuable', - search_value: 'value' - }, - { - text: 'most accessible', - search_value: 'accessibility' - }, - { - text: 'upcoming passes', - search_value: 'upcoming' - }, - { - text: 'smallest', - search_value: 'smallest' - } - ]; - $scope.limit_options = [100, 300, 500, 1000, 4000]; - - // Functions - - $scope.Init = function() { - // Initialization - $scope.limit = $scope.limit_options[1]; - $scope.sort_by = $scope.sort_orders[0]; - - $scope.UpdateRankings(); - } - - var rankings_cache = new SimpleCache(function(item) { - return item.sort_by + '|' + item.limit; - }); - - $scope.UpdateRankings = function() { - var params = { - sort_by: $scope.sort_by.search_value, - limit: $scope.limit - }; - var cache_result = rankings_cache.Get(params); - if (cache_result) { - $scope.rankings = cache_result; - // publish to subscribers (incl. 3d view) - pubsub.publish('NewAsteroidRanking', [$scope.rankings]); - BroadcastInitialRankingsLoaded(); - } - else { - $('#results-table-loader').show(); - $scope.rankings = []; - $http.get('/api/rankings?sort_by=' - + params.sort_by - + '&limit=' - + params.limit) - .success(function(data) { - $scope.rankings = data; - rankings_cache.Set(params, data); - $('#results-table-loader').hide(); - - // publish to subscribers (incl. 3d view) - pubsub.publish('NewAsteroidRanking', [$scope.rankings]); - BroadcastInitialRankingsLoaded(); - }); - } - - } // end UpdateRankings - - $scope.AsteroidClick = function(obj) { - if (obj === $scope.selected) { - // deselect - $scope.selected = null; - } - else { - $scope.selected = obj; - } - pubsub.publish('AsteroidDetailsClick', [obj]); - } - - var inserted_asteroids = {}; - pubsub.subscribe('UpdateRankingsWithFeaturedAsteroid', function(asteroid) { - // normal rankings, except we insert a featured asteroid on top - $scope.selected = asteroid; - - if (!inserted_asteroids[asteroid.full_name]) { - // update rankings - $scope.rankings.unshift(asteroid); - - // send new rankings to 3d view - pubsub.publish('NewAsteroidRanking', [$scope.rankings]); - - inserted_asteroids[asteroid.full_name] = true; - } - - // load details - pubsub.publish('AsteroidDetailsClick', [asteroid]); - }); - - function BroadcastInitialRankingsLoaded() { - if ($scope.loading_initial_rankings) { - pubsub.publish('InitialRankingsLoaded'); - $scope.loading_initial_rankings = false; - } - } -} - diff --git a/static/js/main/controllers/CustomInput.js b/static/js/main/controllers/CustomInput.js deleted file mode 100644 index d55dc82..0000000 --- a/static/js/main/controllers/CustomInput.js +++ /dev/null @@ -1,93 +0,0 @@ -function CustomInputCtrl($scope, $http, pubsub) { - var SERIALIZED_URL_PARAM = 's'; - $scope.object = { - a: Ephemeris.earth.a, - e: Ephemeris.earth.e, - i: Ephemeris.earth.i, - om: Ephemeris.earth.om, - w: Ephemeris.earth.w_bar, - ma: Ephemeris.earth.ma, - epoch: Ephemeris.earth.epoch, - per: Ephemeris.earth.P, - spec: '?', // necessary for composition lookup - custom_object: true - }; - $scope.num_custom_objects = 1; - - $scope.Init = function() { - pubsub.subscribe('ShowCustomInputCtrl', function() { - $scope.StartCustomOrbit(); - }); - - $scope.$watch('object', function (oldVal, newVal) { - // Update deeplink - $scope.direct_url = 'http://asterank.com/?s=' - + encodeURIComponent(JSON.stringify($scope.object)); - }, true); - - // Check if there's a custom object in the url - var serialized = getURLParameter(SERIALIZED_URL_PARAM); - if (serialized) { - // Insert above any new rankings - pubsub.subscribe('InitialRankingsLoaded', function() { - var parsed_obj = JSON.parse(decodeURIComponent(serialized)); - $scope.obj = parsed_obj; - $scope.UseCustomInput(); - }); - } - } - - $scope.StartCustomOrbit = function() { - $scope.show_custom_input = true; - - // Filepicker - neccessary to initialize widget - setTimeout(function() { - // Unfortunately setTimeout hack is necessary because of how bootstrap - // constructs and shows dialogs - var element = document.getElementById('filepicker-widget') - filepicker.constructWidget(element); - }, 0); - } - - $scope.UseCustomInput = function() { - var custom_obj = $.extend({}, $scope.object); - custom_obj.name = custom_obj.full_name = custom_obj.prov_des - = 'Custom Object ' + $scope.num_custom_objects; - custom_obj.P = $scope.object.per; // workaround for inconsistency in 3d api - $scope.num_custom_objects++; - pubsub.publish('UpdateRankingsWithFeaturedAsteroid', [custom_obj]); - $scope.CloseCustomInput(); - } - - $scope.SaveAndUseCustomInput = function() { - // Save on server side - $http.post('/api/user_objects', { - object: $scope.object, - keys: $scope.image_keys - }).success(function(data) { - console.log('Object saved', data); - }); - - $scope.UseCustomInput(); - } - - $scope.CloseCustomInput = function() { - $scope.show_custom_input = false; - } - - $scope.OrbitLinkFocused= function() { - // remember, jquery in angular is bad - $('#link-orbit-container input').select(); - } - - // File picker functions - $scope.FilepickerCallback = function(e) { - if (!e.fpfiles) return; - var keys = []; - for (var i=0; i < e.fpfiles.length; i++) { - var file = e.fpfiles[i]; - keys.push(file.key); - } - $scope.image_keys = keys; - } -} diff --git a/static/js/main/controllers/IntroStatement.js b/static/js/main/controllers/IntroStatement.js deleted file mode 100644 index 7a74db1..0000000 --- a/static/js/main/controllers/IntroStatement.js +++ /dev/null @@ -1,12 +0,0 @@ -function IntroStatementCtrl($scope, pubsub) { - 'use strict'; - $scope.show = true; - - pubsub.subscribe('HideIntroStatement', function() { - $scope.show = false; - }); - - pubsub.subscribe('ShowIntroStatement', function() { - $scope.show = true; - }); -} diff --git a/static/js/main/controllers/asteroid_details.js b/static/js/main/controllers/asteroid_details.js index 81111e6..320e678 100644 --- a/static/js/main/controllers/asteroid_details.js +++ b/static/js/main/controllers/asteroid_details.js @@ -159,9 +159,9 @@ function AsteroidDetailsCtrl($scope, $http, pubsub) { // Object.keys not supported < ie9, so shim is required (see misc.js) $scope.composition = Object.keys(compositions_map[$scope.asteroid.spec]); } - else { + else if ($scope.asteroid.spec) { // This is not set when object is passed via &object param $http.get('/api/compositions').success(function(data) { - compositions_map = data; + var compositions_map = data; $scope.composition = Object.keys(compositions_map[$scope.asteroid.spec]); }); diff --git a/templates/asteroid.html b/templates/asteroid.html index a027bba..2284277 100644 --- a/templates/asteroid.html +++ b/templates/asteroid.html @@ -13,7 +13,7 @@ {% set orbit_explanation = 'orbit is entirely contained within Earth\'s, with a semimajor axis less than 1' %} {% elif asteroid.class == 'AMO' %} {% set canonical_orbit_type = 'Amor' %} - {% set orbit_explanation = 'orbit may approach Earth\'s, but its orbit is larger ' %} + {% set orbit_explanation = 'orbit may approach Earth\'s, but its orbit is larger' %} {% endif %} {% block title %}{{ canonical_name }} information - orbit, physical parameters{% endblock %} @@ -21,7 +21,7 @@ {% block content %}

{{ canonical_name }}

-{{ canonical_name }} is a {{ canonical_orbit_type }}-class asteroid with spectral type {{ asteroid.spec }}. Its full name is "{{ asteroid.full_name }}" and its provisional designation is "{{ asteroid.prov_des }}". +{{ canonical_name }} is a {{ canonical_orbit_type }}-class asteroid with spectral type {{ asteroid.spec }}. Its full name is "{{ asteroid.full_name }}" and its provisional designation is "{{ asteroid.prov_des }}". {{ canonical_name }}'s {{ orbit_explanation }}.