diff --git a/Gemfile b/Gemfile index 0d31318b8dc..7b8ea8d662e 100644 --- a/Gemfile +++ b/Gemfile @@ -85,6 +85,10 @@ gem "soap4r-ruby1.9" gem "dalli" gem "kgio" +# Load algoliasearch-rails and twitter typeahead for search auto-completion +gem "twitter-typeahead-rails", "0.10.5" +gem "algoliasearch-rails" + # Gems useful for development group :development do gem "vendorer" diff --git a/Gemfile.lock b/Gemfile.lock index a19d2e7fa60..52f0fadc5bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,6 +39,12 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) + algoliasearch (1.6.0) + httpclient (~> 2.4) + json (>= 1.5.1) + algoliasearch-rails (1.13.1) + algoliasearch (>= 1.2.14) + json (>= 1.5.1) arel (6.0.0) ast (2.0.0) astrolabe (1.3.0) @@ -272,6 +278,10 @@ GEM tilt (1.4.1) timecop (0.7.4) tins (1.5.2) + twitter-typeahead-rails (0.10.5) + actionpack (>= 3.1) + jquery-rails + railties (>= 3.1) tzinfo (1.2.2) thread_safe (~> 0.1) uglifier (2.7.1) @@ -295,6 +305,7 @@ PLATFORMS DEPENDENCIES SystemTimer (>= 1.1.3) actionpack-page_caching + algoliasearch-rails autoprefixer-rails bigdecimal (~> 1.1.0) coffee-rails (~> 4.1.0) @@ -338,6 +349,10 @@ DEPENDENCIES soap4r-ruby1.9 sprockets (~> 2.12.3) timecop + twitter-typeahead-rails (= 0.10.5) uglifier (>= 1.3.0) validates_email_format_of (>= 1.5.1) vendorer + +BUNDLED WITH + 1.10.6 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 354cfe66e78..8452576c97c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -17,6 +17,9 @@ //= require piwik //= require richtext //= require querystring +//= require twitter/typeahead.min +//= require algolia/v3/algoliasearch.min + var querystring = require('querystring-component'); diff --git a/app/assets/javascripts/index/search.js b/app/assets/javascripts/index/search.js index 485920c8e1f..a830b67465b 100644 --- a/app/assets/javascripts/index/search.js +++ b/app/assets/javascripts/index/search.js @@ -1,6 +1,33 @@ //= require jquery.simulate OSM.Search = function(map) { + var algolia, idx; + + algolia = algoliasearch('A4H3Q0LE3T', 'cf91c81dd26f4e3bc03c02e4f9026172'); + idx = algolia.initIndex('osm_idx'); + + // Typeahead UI + $('.autocomplete .typeahead').typeahead({ hint: false }, { + source: idx.ttAdapter({ hitsPerPage: 5 }), + displayKey: 'name', + templates: { + suggestion: function (city) { + // Render UI + return '
' + + '
' + + '' + + city.name + ', ' + city.country.toUpperCase() + + '
' + + '
'; + } + } + }); + + // Form submission handler + $(".typeahead").on("typeahead:selected", function onSelected (ev, suggestion, name) { + $(".search_form").submit(); + }); + $(".search_form input[name=query]").on("input", function(e) { if ($(e.target).val() === "") { $(".describe_location").fadeIn(100); diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 21cecaf4aa6..98759bf7f69 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -228,7 +228,7 @@ table { /* Rules for the header */ -#menu-icon { +#menu-icon { display: none !important; float: right; background: image-url("menu-icon.png") no-repeat; @@ -290,7 +290,7 @@ nav.primary { > li { border-right: $border; float: left; - &:last-child { + &:last-child { border-right: 0; } > a:hover { background: lighten($green, 30%); } @@ -371,12 +371,12 @@ nav.secondary { > li { border-right: $border; float: left; - &:last-child { + &:last-child { border-right: 0; > a { border-radius: 0 $border-radius $border-radius 0; - } + } } &:first-child > a { border-radius: $border-radius 0 0 $border-radius; } &:hover a { background: lighten($darkgrey, 30%); } @@ -444,7 +444,7 @@ nav.secondary { } } -@media only screen and (max-width:960px) { +@media only screen and (max-width:1260px) { #compact-secondary-nav { display: inline-block; } @@ -534,8 +534,6 @@ nav.secondary { #sidebar, #map { position: relative; height: 100%; - overflow-x: hidden; - overflow-y: auto; } #sidebar { @@ -575,7 +573,6 @@ nav.secondary { z-index: 1000; height: auto; border-bottom-right-radius: 5px; - overflow: hidden; .welcome { display: block; } @@ -616,7 +613,7 @@ nav.secondary { &.query-disabled { cursor: not-allowed; } - + .leaflet-marker-draggable { cursor: move; } @@ -677,7 +674,7 @@ nav.secondary { margin-bottom: 8px; position: relative; transition: border-color 0.08s ease-in; - + label { position: absolute; top: 0; @@ -811,12 +808,11 @@ nav.secondary { .sidebar_heading { position: relative; padding: $lineheight/2 $lineheight; - // background: $offwhite; - // border-bottom: 1px solid #ccc; - > .close { + + > .close { float: right; margin-top: 2px; - cursor: pointer; + cursor: pointer; } } @@ -858,8 +854,8 @@ header .search_forms, .query_wrapper { position: relative; - overflow: hidden; border-radius: 2px 0 0 2px; + width: 235px; } input[type=text] { @@ -874,7 +870,7 @@ header .search_forms, input:focus { outline: none; - box-shadow: 0px 0px 7px #9ED485; + box-shadow: 0px 0px 1px #7092C8; } input[type=submit].float { @@ -898,9 +894,9 @@ header .search_forms, .describe_location { position: absolute; - top: 6px; - right: 6px; - font-size: 10px; + top: 7px; + right: 9px; + font-size: 12px; color: $blue; } @@ -1296,7 +1292,7 @@ tr.turn:hover { .content-heading { background: $lightgrey; - + h1 { font-size: 22px; } } @@ -1892,7 +1888,7 @@ tr.turn:hover { padding-top: $lineheight; border-top: 1px solid $lightgrey; } - .horizontal-list .form-row { + .horizontal-list .form-row { float: left; padding-right: 10px; } @@ -2460,7 +2456,7 @@ input.richtext_title[type="text"] { .site-welcome, .site-fixthemap { .center { text-align: center; - .sprite { + .sprite { float: none; margin: auto; } @@ -2473,7 +2469,7 @@ input.richtext_title[type="text"] { float: left; } - .icon-list { + .icon-list { padding-bottom: 20px; div { margin-bottom: 10px; @@ -2718,3 +2714,23 @@ input.richtext_title[type="text"] { } } +.twitter-typeahead { width: 100%; } +.twitter-typeahead .tt-input, .twitter-typeahead .tt-hint { width: 100%; margin: 0px; padding: 8px 12px; border: 1px solid #ccc; outline: none; } +.twitter-typeahead .tt-hint { color: #999; } +.twitter-typeahead .tt-dropdown-menu { width: 100%; padding: 0; background-color: #fff; border: 1px solid rgba(0, 0, 0, 0.2); border-top: 0px; } +.twitter-typeahead .tt-dropdown-menu .tt-suggestion { text-align: left; padding: 3px 13px; font-size: 14px; line-height: 24px; } +.twitter-typeahead .tt-dropdown-menu .tt-suggestion.tt-cursor { color: #fff; background-color: #7092FF; } +.twitter-typeahead .tt-dropdown-menu .tt-suggestion em { font-weight: bold; font-style: normal; } + +#icon-location { + height: 22px; + width: 22px; + margin-right: 6px; + margin-left: -6px; + margin-bottom: -5px; + opacity: 0.3; +} + +.name { + cursor: pointer; +} diff --git a/app/views/layouts/_search.html.erb b/app/views/layouts/_search.html.erb index 8665ba02f1b..036f6615f89 100644 --- a/app/views/layouts/_search.html.erb +++ b/app/views/layouts/_search.html.erb @@ -1,9 +1,10 @@ +
<%= link_to image_tag('directions.png', :class => 'button'), directions_path, { :class => "button switch_link", :title => t('site.search.get_directions_title') } %> <%= submit_tag t('site.search.submit_text'), :class => 'float' %> -
- <%= text_field_tag "query", params[:query], :placeholder => t("site.search.search"), :autofocus => autofocus, :class => 'overflow' %> +
+ <%= text_field_tag "query", params[:query], :placeholder => t("site.search.search"), :autofocus => autofocus, :class => 'typeahead' %> <%= link_to t('site.search.where_am_i'), '#', { :class => "describe_location", :title => t('site.search.where_am_i_title') } %>
diff --git a/config/initializers/algoliasearch.rb b/config/initializers/algoliasearch.rb new file mode 100644 index 00000000000..ebc94e6f6ce --- /dev/null +++ b/config/initializers/algoliasearch.rb @@ -0,0 +1 @@ +AlgoliaSearch.configuration = { application_id: "A4H3Q0LE3T", api_key: "4fe490a382fef26fad15119f0add3d47", pagination_backend: :will_paginate }